Qualify Claude defaults against pinned Daytona snapshot identities

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-15 14:11:29 -05:00
1 parent 2e107b341f
commit 7bd7699c9c
18 files changed
+325 -31

No files matched your search

@@ -50,6 +50,35 @@ describe("probeEnvironment", () => {
mockEnvironmentRuntimeService.mockClear();
});
it("qualifies a named Daytona snapshot only after an ID-pinned lease and owned cleanup", async () => {
const environment = { id: "env", driver: "sandbox", status: "active", config: { provider: "daytona", snapshot: "managed-snapshot" }, metadata: null } as any;
const identity = { provider: "daytona", requestedRef: "managed-snapshot", id: "a6b9e7d0-f886-471a-b461-640dd03e8d0f", name: "managed-snapshot", organizationId: "provider-account", createdAt: "2026-10-07T23:19:57.133Z" };
vi.spyOn(configRuntime, "resolveEnvironmentDriverConfigForRuntime").mockResolvedValue({ driver: "sandbox", config: environment.config });
mockRuntimeAcquireRunLease.mockResolvedValue({ lease: { id: "lease", provider: "daytona", metadata: { snapshot: "managed-snapshot", snapshotIdentity: identity } } });
mockRuntimeExecute.mockResolvedValue({ exitCode: 0, stdout: "Linux\nx86_64\nglibc\nglibc 2.39\n" });
const result = await probeEnvironment({} as any, environment, { companyId: "company", acquireSandboxRuntimeLease: true });
expect(result.details?.platformQualificationRecorded).toBe(true);
expect(mockRuntimeAcquireRunLease).toHaveBeenCalledWith(expect.objectContaining({ resolveSnapshotIdentity: true }));
const proof = mockRecordPlatformProbe.mock.calls[1]![0].proof;
expect(proof).toMatchObject({ v: 2, snapshotIdentity: identity });
environment.metadata = { [SANDBOX_PLATFORM_PROBE_METADATA_KEY]: { company: proof } };
expect(await readSandboxPlatformQualification({} as any, environment, "company")).toMatchObject({ platform: "linux", architecture: "x64", glibcVersion: "glibc 2.39" });
expect(await readSandboxPlatformQualification({} as any, environment, "foreign-company")).toBeNull();
expect(mockRuntimeAcquireRunLease).toHaveBeenCalledTimes(1);
});
it.each(["missing", "wrong-reference", "missing-owner", "cleanup"])("does not qualify a named snapshot after %s", async failure => {
const environment = { id: "env", driver: "sandbox", status: "active", config: { provider: "daytona", snapshot: "managed-snapshot" } } as any;
const identity = { provider: "daytona", requestedRef: failure === "wrong-reference" ? "other" : "managed-snapshot", id: "a6b9e7d0-f886-471a-b461-640dd03e8d0f", name: "managed-snapshot", organizationId: failure === "missing-owner" ? "" : "provider-account", createdAt: "2026-10-07T23:19:57.133Z" };
vi.spyOn(configRuntime, "resolveEnvironmentDriverConfigForRuntime").mockResolvedValue({ driver: "sandbox", config: environment.config });
mockRuntimeAcquireRunLease.mockResolvedValue({ lease: { id: "lease", provider: "daytona", metadata: { snapshot: "managed-snapshot", ...(failure === "missing" ? {} : { snapshotIdentity: identity }) } } });
mockRuntimeExecute.mockResolvedValue({ exitCode: 0, stdout: "Linux\nx86_64\nglibc\nglibc 2.39\n" });
if (failure === "cleanup") mockRuntimeReleaseRunLease.mockResolvedValue({ id: "lease", companyId: "company", environmentId: "env", status: "released", cleanupStatus: "failed" });
const result = await probeEnvironment({} as any, environment, { companyId: "company", acquireSandboxRuntimeLease: true });
expect(result.details?.platformQualificationRecorded).toBe(false);
expect(mockRecordPlatformProbe).toHaveBeenCalledTimes(1);
});
it.each(["2.38", "2.39", "musl"])("records actual immutable-image facts for %s and reads them without another lease", async libc => {
const image = `registry.example.test/runtime@sha256:${"a".repeat(64)}`;
const environment = { id: "env", driver: "sandbox", status: "active", config: { provider: "daytona", image, reuseLease: false }, metadata: null } as any;
@@ -322,6 +322,37 @@ describeEmbeddedPostgres("environmentRuntimeService", () => {
} as unknown as PluginWorkerManager;
}
it.each(["paperclip_runner", "claude_local", null])("pins qualified snapshots only for native execution (%s)", async adapterType => {
const pluginId = randomUUID();
const { companyId, environment: baseEnvironment, runId } = await seedEnvironment();
const config = { provider: "daytona", snapshot: "managed-snapshot", reuseLease: false, timeoutMs: 1234 };
await insertSandboxProviderPlugin(pluginId, { environmentDrivers: [{ driverKey: "daytona", kind: "sandbox_provider", displayName: "Daytona", configSchema: { type: "object" } }] });
await environmentService(db).update(baseEnvironment.id, { driver: "sandbox", config });
const environment = { ...baseEnvironment, driver: "sandbox", config };
const parsed = await resolveEnvironmentDriverConfigForRuntime(db, companyId, environment);
const snapshotId = "a6b9e7d0-f886-471a-b461-640dd03e8d0f";
environment.metadata = { paperclipSandboxPlatformProbes: { [companyId]: {
v: 2, companyId, snapshot: config.snapshot, template: null,
baseConfigFingerprint: createHash("sha256").update(stableStringify(config)).digest("hex"),
runtimeConfigFingerprint: createHash("sha256").update(stableStringify(parsed.config)).digest("hex"),
snapshotIdentity: { provider: "daytona", requestedRef: config.snapshot, id: snapshotId, name: config.snapshot, organizationId: "provider-account", createdAt: "2026-10-07T23:19:57.133Z" },
} } };
const worker = createFreshPluginLeaseWorker(pluginId);
vi.mocked(worker.call).mockImplementation(async (_id, method, params: any) => {
if (method !== "environmentAcquireLease") throw new Error(`Unexpected ${method}`);
return { providerLeaseId: "snapshot-lease", metadata: { provider: "daytona", snapshot: params.config.snapshot, remoteCwd: "/workspace" } };
});
const service = environmentRuntimeService(db, { pluginWorkerManager: worker });
const acquired = await service.acquireRunLease({ companyId, environment, issueId: null, heartbeatRunId: runId,
persistedExecutionWorkspace: null, adapterType, ...(adapterType === null ? { resolveSnapshotIdentity: true } : {}) });
const expectedSnapshot = adapterType === "paperclip_runner" ? snapshotId : config.snapshot;
expect(worker.call).toHaveBeenCalledWith(pluginId, "environmentAcquireLease", expect.objectContaining({
config: expect.objectContaining({ snapshot: expectedSnapshot }),
...(adapterType === null ? { resolveSnapshotIdentity: true } : {}),
}), expect.any(Number));
expect(acquired.lease.metadata?.snapshot).toBe(expectedSnapshot);
});
function insertReusableExecutionWorkspace(executionWorkspaceId: string, companyId: string, projectId: string) {
return db.insert(executionWorkspaces).values({
id: executionWorkspaceId,
@@ -0,0 +1,34 @@
import { describe, expect, it } from "vitest";
import type { Environment, SandboxEnvironmentConfig } from "@paperclipai/shared";
import { fingerprintEnvironmentSandboxProviderConfig as fingerprint, SANDBOX_PLATFORM_PROBE_METADATA_KEY } from "../services/environment-custom-image-runtime.js";
import { qualifiedSandboxSnapshotId, type SandboxTemplateIdentity } from "../services/sandbox-snapshot-qualification.js";
function fixture() {
const config = { provider: "daytona", snapshot: "managed-snapshot", apiKey: "fixture-account" } as SandboxEnvironmentConfig;
const template: SandboxTemplateIdentity = { id: "template", capturedAt: "2026-10-15T00:00:00Z", templateKind: "snapshot", bindingField: "snapshot" };
const identity = { provider: "daytona", requestedRef: config.snapshot, id: "a6b9e7d0-f886-471a-b461-640dd03e8d0f", name: config.snapshot, organizationId: "provider-account", createdAt: "2026-10-07T23:19:57.133Z" };
const proof = { v: 2, companyId: "company", snapshot: config.snapshot, template,
baseConfigFingerprint: fingerprint(config), runtimeConfigFingerprint: fingerprint(config), snapshotIdentity: identity };
const environment = { config, metadata: { [SANDBOX_PLATFORM_PROBE_METADATA_KEY]: { company: proof } } } as unknown as Environment;
return { config, template, identity, proof, environment };
}
describe("qualified snapshot execution binding", () => {
it("pins the measured provider ID without a network lookup", () => {
const f = fixture();
expect(qualifiedSandboxSnapshotId(f.environment, "company", f.config, f.template)).toBe(f.identity.id);
});
it.each(["company", "base-config", "account", "template", "snapshot", "image", "provider", "identity"])("rejects changed %s", change => {
const f = fixture();
let company = "company";
if (change === "company") company = "foreign-company";
if (change === "base-config") f.environment.config = { ...f.config, target: "different" };
if (change === "account") f.config = { ...f.config, apiKey: "different-account" };
if (change === "template") f.template = { ...f.template!, capturedAt: "2026-10-16T00:00:00Z" };
if (change === "snapshot") f.config = { ...f.config, snapshot: "new-snapshot" };
if (change === "image") f.config = { ...f.config, image: "other-image" };
if (change === "provider") f.config = { ...f.config, provider: "other-provider" };
if (change === "identity") f.identity.id = "mutable-name";
expect(qualifiedSandboxSnapshotId(f.environment, company, f.config, f.template)).toBeNull();
});
});
+21 -9
View File
@@ -14,6 +14,7 @@ import { environmentRuntimeService } from "./environment-runtime.js";
import { environmentService } from "./environments.js";
import { fingerprintEnvironmentSandboxProviderConfig, SANDBOX_PLATFORM_PROBE_METADATA_KEY } from "./environment-custom-image-runtime.js";
import type { SandboxEnvironmentConfig } from "@paperclipai/shared";
import { isQualifiableDaytonaSnapshot, qualifiedSandboxSnapshotId, readSnapshotIdentity, type SandboxTemplateIdentity } from "./sandbox-snapshot-qualification.js";
export const SANDBOX_PLATFORM_PROBE_COMMAND = "uname -s; uname -m; if version=$(getconf GNU_LIBC_VERSION 2>/dev/null) && [ -n \"$version\" ]; then printf 'glibc\\n%s\\n' \"$version\"; else case \"$(ldd --version 2>&1)\" in *musl*) printf 'musl\\n' ;; *) printf 'unknown\\n' ;; esac; fi";
type PlatformFacts = { platform: string; architecture: string; libc: "glibc" | "musl" | "unknown"; glibcVersion?: string };
@@ -34,7 +35,7 @@ export function parseSandboxPlatformFacts(output: string): PlatformFacts {
...(libc === "glibc" ? { glibcVersion: version?.trim() ?? "unknown" } : {}) };
}
async function sandboxBinding(db: Db, environment: Environment, companyId: string) {
const selectedTemplate: { value: { id: string; capturedAt: string | null; templateKind: string; bindingField: string } | null } = { value: null };
const selectedTemplate: { value: SandboxTemplateIdentity } = { value: null };
const parsed = await resolveEnvironmentDriverConfigForRuntime(db, companyId, environment, {
applyCustomImageTemplate: true, readOnlyCustomImageTemplate: true,
onResolvedCustomImageTemplate: identity => { selectedTemplate.value = identity; },
@@ -42,6 +43,10 @@ async function sandboxBinding(db: Db, environment: Environment, companyId: strin
if (parsed.driver !== "sandbox") return null;
const image = parsed.config.image;
const template = selectedTemplate.value;
if (isQualifiableDaytonaSnapshot(parsed.config, template)) {
return { baseConfigFingerprint: fingerprint(environment.config), runtimeConfigFingerprint: fingerprint(parsed.config),
snapshot: parsed.config.snapshot, template, qualifiedSnapshotId: qualifiedSandboxSnapshotId(environment, companyId, parsed.config, template) };
}
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 };
@@ -49,9 +54,11 @@ async function sandboxBinding(db: Db, environment: Environment, companyId: strin
export async function readSandboxPlatformQualification(db: Db, environment: Environment, companyId: string): Promise<PlatformFacts | null> {
const proof = record(record(environment.metadata?.[SANDBOX_PLATFORM_PROBE_METADATA_KEY])[companyId]);
if (proof.v !== 1 || proof.companyId !== companyId || proof.baseConfigFingerprint !== fingerprint(environment.config)) return null;
if (![1, 2].includes(Number(proof.v)) || proof.companyId !== companyId || proof.baseConfigFingerprint !== fingerprint(environment.config)) return null;
const binding = await sandboxBinding(db, environment, companyId);
if (!binding || proof.runtimeConfigFingerprint !== binding.runtimeConfigFingerprint || proof.image !== binding.image
if (!binding || (proof.v === 2 ? !("qualifiedSnapshotId" in binding && binding.qualifiedSnapshotId)
: !("image" in binding) || proof.image !== binding.image)
|| proof.runtimeConfigFingerprint !== binding.runtimeConfigFingerprint
|| JSON.stringify(proof.template) !== JSON.stringify(binding.template)) return null;
const facts = record(proof.facts);
if (typeof facts.platform !== "string" || typeof facts.architecture !== "string"
@@ -140,6 +147,7 @@ export async function probeEnvironment(
heartbeatRunId: null,
persistedExecutionWorkspace: null,
adapterType: null,
resolveSnapshotIdentity: true,
applyCustomImageTemplate: options.applyCustomImageTemplate === true,
});
const metadata = leaseRecord.lease.metadata ?? {};
@@ -149,11 +157,13 @@ export async function probeEnvironment(
: null;
details = { provider, providerLeaseId: leaseRecord.lease.providerLeaseId, leaseId: leaseRecord.lease.id,
leasePolicy: leaseRecord.lease.leasePolicy, metadata, platformQualificationRecorded: false,
platformQualificationDiagnostic: "An immutable OCI image digest is required; this connection probe does not qualify a mutable image or snapshot name." };
if (isImmutableImage(metadata.image) && !metadata.snapshot) {
platformQualificationDiagnostic: "Platform qualification requires an immutable OCI image or a Daytona snapshot with a verified provider ID. Update the provider plugin and probe again, or select Legacy runner." };
if ((isImmutableImage(metadata.image) && !metadata.snapshot) || metadata.snapshotIdentity) {
try {
const binding = await sandboxBinding(db, environment, resolvedCompanyId);
if (binding && metadata.image === binding.image) {
const snapshotIdentity = binding && "snapshot" in binding ? readSnapshotIdentity(metadata.snapshotIdentity, binding.snapshot) : null;
if (binding && (("image" in binding && metadata.image === binding.image && !metadata.snapshot)
|| (snapshotIdentity && metadata.snapshot === binding.snapshot && provider === "daytona"))) {
const platform = await runtime.execute({ environment: probeEnvironmentConfig, lease: leaseRecord.lease,
command: "sh", args: ["-c", SANDBOX_PLATFORM_PROBE_COMMAND],
bypassSession: true, timeoutMs: 10_000, commandTimeoutMs: 10_000 });
@@ -163,10 +173,12 @@ export async function probeEnvironment(
if (facts.platform !== "unknown" && facts.architecture !== "unknown"
&& (facts.platform !== "linux" || facts.libc !== "unknown")
&& (facts.libc !== "glibc" || /^(?:glibc\s+)?\d+\.\d+(?:\.\d+)?$/.test(facts.glibcVersion ?? ""))) {
qualification = { v: 1, companyId: resolvedCompanyId, ...binding, facts, probedAt: new Date().toISOString() };
const { qualifiedSnapshotId: _qualifiedSnapshotId, ...recordedBinding } = { qualifiedSnapshotId: null, ...binding };
qualification = { v: snapshotIdentity ? 2 : 1, companyId: resolvedCompanyId, ...recordedBinding,
...(snapshotIdentity ? { snapshotIdentity } : {}), facts, probedAt: new Date().toISOString() };
delete details.platformQualificationDiagnostic;
} else details.platformQualificationDiagnostic = "The image's OS, architecture or libc could not be identified. Legacy remains the creation default.";
} else details.platformQualificationDiagnostic = "The live lease does not match the selected immutable image configuration. Probe again.";
} else details.platformQualificationDiagnostic = "The sandbox OS, architecture or libc could not be identified. Legacy remains the creation default.";
} else details.platformQualificationDiagnostic = "The live lease does not match the selected image or snapshot identity. Probe again.";
} catch {
details.platformQualificationDiagnostic = "Platform qualification could not complete; connection readiness does not establish native compatibility. Check the image and probe again.";
}
+13 -1
View File
@@ -43,6 +43,7 @@ import {
} from "@paperclipai/adapter-utils/acpx-engine/startup-timing";
import { environmentService } from "./environments.js";
import { instanceSettingsService } from "./instance-settings.js";
import { qualifiedSandboxSnapshotId, type SandboxTemplateIdentity } from "./sandbox-snapshot-qualification.js";
import { verifyNativeHarnessBackupStamp } from "./native-runtime/native-harness-backup-stamp.js";
import {
collectEnvironmentSecretRefs,
@@ -454,6 +455,8 @@ export interface EnvironmentDriverAcquireInput {
* configured default adapter.
*/
adapterType: string | null;
/** Resolve an immutable provider snapshot identity for an explicit platform probe. */
resolveSnapshotIdentity?: boolean;
/**
* Force applying the active custom-image template even when issueId and
* heartbeatRunId are null. Operator-initiated `Test` probes set this so the
@@ -1844,14 +1847,19 @@ function createSandboxEnvironmentDriver(
async acquireRunLease(input) {
const storedParsed = parseEnvironmentDriverConfig(input.environment);
const selectedTemplate: { value: SandboxTemplateIdentity } = { value: null };
const parsed = await resolveEnvironmentDriverConfigForRuntime(db, input.companyId, input.environment, {
issueId: input.issueId,
heartbeatRunId: input.heartbeatRunId,
applyCustomImageTemplate: input.applyCustomImageTemplate ?? false,
onResolvedCustomImageTemplate: identity => { selectedTemplate.value = identity; },
});
if (parsed.driver !== "sandbox" || storedParsed.driver !== "sandbox") {
throw new Error(`Expected sandbox environment config for driver "${input.environment.driver}".`);
}
const pinnedSnapshotId = input.adapterType === "paperclip_runner"
? qualifiedSandboxSnapshotId(input.environment, input.companyId, parsed.config, selectedTemplate.value) : null;
if (pinnedSnapshotId) parsed.config = { ...parsed.config, snapshot: pinnedSnapshotId };
// Check if this provider should be handled by a plugin.
if (!isBuiltinSandboxProvider(parsed.config.provider)) {
@@ -1882,7 +1890,8 @@ function createSandboxEnvironmentDriver(
}
const workerConfig = stripSandboxProviderEnvelope(parsed.config);
const storedConfig = storedParsed.config;
const storedConfig = pinnedSnapshotId ? { ...storedParsed.config, snapshot: pinnedSnapshotId } : storedParsed.config;
if (pinnedSnapshotId) delete storedConfig.image;
const providerConfigForLease = sandboxConfigForLeaseMetadata(storedConfig);
// Require the reusable-lease capability AND a worker that verifies the
// reuse methods. The provider must first opt in through the declaration:
@@ -2122,6 +2131,7 @@ function createSandboxEnvironmentDriver(
// environment's default adapter image (a pi agent then runs in the
// opencode image and the harness binary is missing at exec time).
adapterType: input.adapterType ?? undefined,
...(input.resolveSnapshotIdentity ? { resolveSnapshotIdentity: true } : {}),
// Forward a caller deadline so the provider configures a provider-side
// expiry at or before it and returns the real provider expiry.
...(requestedExpiresAtParam(input.requestedExpiresAt) !== undefined
@@ -4000,6 +4010,7 @@ export function environmentRuntimeService(
executionWorkspaceSettings?: IssueExecutionWorkspaceSettings | null;
/** The agent's adapter type for this run (mixed-harness environments). */
adapterType?: string | null;
resolveSnapshotIdentity?: boolean;
/**
* Force applying the active custom-image template even for ad-hoc (no
* issue/run) invocations. Operator `Test` probes set this so the runtime
@@ -4037,6 +4048,7 @@ export function environmentRuntimeService(
executionWorkspaceMode: leaseContext.executionWorkspaceMode,
executionWorkspaceSettings: input.executionWorkspaceSettings ?? null,
adapterType: input.adapterType ?? null,
resolveSnapshotIdentity: input.resolveSnapshotIdentity,
applyCustomImageTemplate: input.applyCustomImageTemplate ?? false,
requestedExpiresAt: input.requestedExpiresAt ?? null,
assertCompanyBinding: input.assertCompanyBinding,
@@ -0,0 +1,53 @@
import type { Environment, SandboxEnvironmentConfig } from "@paperclipai/shared";
import { fingerprintEnvironmentSandboxProviderConfig, SANDBOX_PLATFORM_PROBE_METADATA_KEY } from "./environment-custom-image-runtime.js";
export type SandboxTemplateIdentity = { id: string; capturedAt: string | null; templateKind: string; bindingField: string } | null;
export type SandboxSnapshotIdentity = {
provider: "daytona";
requestedRef: string;
id: string;
name: string;
organizationId: string;
createdAt: string;
};
export function readSnapshotIdentity(value: unknown, reference: unknown): SandboxSnapshotIdentity | null {
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
const identity = value as Record<string, unknown>;
if (identity.provider !== "daytona" || identity.requestedRef !== reference
|| typeof identity.id !== "string" || !/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(identity.id)
|| typeof identity.name !== "string" || !identity.name.trim()
|| (reference !== identity.id && reference !== identity.name)
|| typeof identity.organizationId !== "string" || !identity.organizationId.trim()
|| typeof identity.createdAt !== "string" || !Number.isFinite(Date.parse(identity.createdAt))) return null;
return identity as SandboxSnapshotIdentity;
}
export function isQualifiableDaytonaSnapshot(
input: SandboxEnvironmentConfig, template: SandboxTemplateIdentity,
): input is SandboxEnvironmentConfig & Record<string, unknown> & { snapshot: string } {
const config = input as unknown as Record<string, unknown>;
return config.provider === "daytona" && typeof config.snapshot === "string" && !!config.snapshot.trim()
&& !config.image && !config.template && !config.templateRef
&& (!template || (template.templateKind === "snapshot" && template.bindingField === "snapshot"));
}
/** Discovery reads only saved, company-scoped proof. Execution pins the same
* provider ID rather than resolving the mutable name again. A new config or
* captured template needs a new probe; deleting the pinned snapshot fails at
* the provider instead of silently selecting its replacement. */
export function qualifiedSandboxSnapshotId(
environment: Environment, companyId: string, config: SandboxEnvironmentConfig, template: SandboxTemplateIdentity,
): string | null {
if (!isQualifiableDaytonaSnapshot(config, template)) return null;
const proofs = environment.metadata?.[SANDBOX_PLATFORM_PROBE_METADATA_KEY];
if (!proofs || typeof proofs !== "object" || Array.isArray(proofs)) return null;
const proof = (proofs as Record<string, unknown>)[companyId];
if (!proof || typeof proof !== "object" || Array.isArray(proof)) return null;
const value = proof as Record<string, unknown>;
if (value.v !== 2 || value.companyId !== companyId
|| value.baseConfigFingerprint !== fingerprintEnvironmentSandboxProviderConfig(environment.config as SandboxEnvironmentConfig)
|| value.runtimeConfigFingerprint !== fingerprintEnvironmentSandboxProviderConfig(config)
|| value.snapshot !== config.snapshot || JSON.stringify(value.template) !== JSON.stringify(template)) return null;
return readSnapshotIdentity(value.snapshotIdentity, config.snapshot)?.id ?? null;
}