Merge final immutable-image qualification guard

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* codex/runner-native-platform-prerequisites:
  fix(environments): bind platform facts to the effective immutable image
This commit is contained in:
DottaandPaperclip committed 2026-10-12 16:17:20 -05:00
commit f340d92b39
4 files changed
+26 -8

No files matched your search

+17 -2
View File
@@ -69,7 +69,7 @@ describe("probeEnvironment", () => {
expect(await readSandboxPlatformQualification({} as any, environment, "foreign-company")).toBeNull();
expect(await readSandboxPlatformQualification({} as any, { ...environment, config: { ...environment.config, image: `registry.example.test/runtime@sha256:${"b".repeat(64)}` } }, "company")).toBeNull();
vi.mocked(configRuntime.resolveEnvironmentDriverConfigForRuntime).mockImplementation(async (_db, _company, _env, options) => {
options?.onResolvedCustomImageTemplate?.({ id: "changed-template", capturedAt: null });
options?.onResolvedCustomImageTemplate?.({ id: "changed-template", capturedAt: null, templateKind: "image", bindingField: "image" });
return { driver: "sandbox", config: environment.config };
});
expect(await readSandboxPlatformQualification({} as any, environment, "company")).toBeNull();
@@ -117,9 +117,24 @@ describe("probeEnvironment", () => {
const identity = vi.fn();
const result = await resolveActiveEnvironmentCustomImageTemplateForRuntime(db as never, { environmentId: "env", baseConfig: { provider: "daytona", reuseLease: false }, runtimeConfig: { provider: "daytona", reuseLease: false }, readOnly: true, onResolvedTemplate: identity });
expect(result).toMatchObject({ image: row.templateRef });
expect(identity).toHaveBeenCalledWith({ id: "template", capturedAt: capturedAt.toISOString() });
expect(identity).toHaveBeenCalledWith({ id: "template", capturedAt: capturedAt.toISOString(), templateKind: "image", bindingField: "image" });
expect(update).not.toHaveBeenCalled();
});
it.each(["provider_template", "unknown"])("does not qualify a named active %s boot binding over a pinned base image", async templateKind => {
const image = `registry.example.test/runtime@sha256:${"a".repeat(64)}`;
const environment = { id: "env", driver: "sandbox", status: "active", config: { provider: "daytona", image }, metadata: null } as any;
vi.spyOn(configRuntime, "resolveEnvironmentDriverConfigForRuntime").mockImplementation(async (_db, _company, _env, options) => {
const bindingField = templateKind === "provider_template" ? "template" : "templateRef";
options?.onResolvedCustomImageTemplate?.({ id: "active-template", capturedAt: null, templateKind, bindingField });
return { driver: "sandbox", config: { ...environment.config, [bindingField]: "mutable-template-name" } };
});
mockRuntimeAcquireRunLease.mockResolvedValue({ lease: { id: "lease", provider: "daytona", metadata: { image } } });
const result = await probeEnvironment({} as any, environment, { companyId: "company", acquireSandboxRuntimeLease: true });
expect(result.ok).toBe(true);
expect(result.details?.platformQualificationRecorded).toBe(false);
expect(mockRuntimeExecute).not.toHaveBeenCalled();
expect(mockRecordPlatformProbe).toHaveBeenCalledTimes(1);
});
it("returns false when an atomic probe record loses its config comparison", async () => {
const { environmentService } = await vi.importActual<typeof import("../services/environments.js")>("../services/environments.js");
const returning = vi.fn().mockResolvedValue([]);
+1 -1
View File
@@ -661,7 +661,7 @@ export async function resolveEnvironmentDriverConfigForRuntime(
// configuration and tooling so the test reflects what real agent runs use.
applyCustomImageTemplate?: boolean;
readOnlyCustomImageTemplate?: boolean;
onResolvedCustomImageTemplate?: (identity: { id: string; capturedAt: string | null }) => void;
onResolvedCustomImageTemplate?: (identity: { id: string; capturedAt: string | null; templateKind: string; bindingField: string }) => void;
},
): Promise<ParsedEnvironmentConfig> {
const parsed = parseEnvironmentDriverConfig(environment);
@@ -560,7 +560,7 @@ export async function resolveActiveEnvironmentCustomImageTemplateForRuntime(
secretRefExcludePaths?: Iterable<string>;
now?: Date;
readOnly?: boolean;
onResolvedTemplate?: (identity: { id: string; capturedAt: string | null }) => void;
onResolvedTemplate?: (identity: { id: string; capturedAt: string | null; templateKind: string; bindingField: string }) => void;
},
): Promise<SandboxEnvironmentConfig> {
const row = await db
@@ -591,7 +591,8 @@ export async function resolveActiveEnvironmentCustomImageTemplateForRuntime(
// match. Runtime-only knobs such as lease reuse, timeouts, and resource hints
// are excluded from the fingerprint so those edits do not discard the capture.
const now = input.now ?? new Date();
input.onResolvedTemplate?.({ id: row.id, capturedAt: row.capturedAt?.toISOString() ?? null });
input.onResolvedTemplate?.({ id: row.id, capturedAt: row.capturedAt?.toISOString() ?? null,
templateKind: row.templateKind ?? "unknown", bindingField: resolveEnvironmentCustomImageRuntimeConfigBinding(row).field });
if (!input.readOnly) await db
.update(environmentCustomImageTemplates)
.set({ lastUsedAt: now, updatedAt: now })
+5 -3
View File
@@ -34,15 +34,17 @@ export function parseSandboxPlatformFacts(output: string): PlatformFacts {
...(libc === "glibc" ? { glibcVersion: version?.trim() ?? "unknown" } : {}) };
}
async function sandboxBinding(db: Db, environment: Environment, companyId: string) {
let template: { id: string; capturedAt: string | null } | null = null;
const selectedTemplate: { value: { id: string; capturedAt: string | null; templateKind: string; bindingField: string } | null } = { value: null };
const parsed = await resolveEnvironmentDriverConfigForRuntime(db, companyId, environment, {
applyCustomImageTemplate: true, readOnlyCustomImageTemplate: true,
onResolvedCustomImageTemplate: identity => { template = identity; },
onResolvedCustomImageTemplate: identity => { selectedTemplate.value = identity; },
});
if (parsed.driver !== "sandbox") return null;
const image = parsed.config.image;
// Names, mutable tags, provider defaults and snapshot names are not immutable identities.
if (!isImmutableImage(image) || record(parsed.config).snapshot) return null;
const template = selectedTemplate.value;
if (!isImmutableImage(image) || ["snapshot", "template", "templateRef"].some(key => record(parsed.config)[key])
|| (template && (template.templateKind !== "image" || template.bindingField !== "image"))) return null;
return { baseConfigFingerprint: fingerprint(environment.config), runtimeConfigFingerprint: fingerprint(parsed.config as unknown as Record<string, unknown>), image, template };
}