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

@@ -141,6 +141,50 @@ describe("Daytona sandbox provider plugin", () => {
__resetDaytonaSandboxHandleCacheForTest();
});
const snapshotRecord = { id: "a6b9e7d0-f886-471a-b461-640dd03e8d0f", name: "managed-snapshot", organizationId: "provider-account", createdAt: "2026-10-07T23:19:57.133Z" };
const snapshotProbe = { driverKey: "daytona", companyId: "company-1", environmentId: "env-1", runId: "probe-1",
resolveSnapshotIdentity: true, config: { apiKey: "fixture-key", snapshot: "managed-snapshot", reuseLease: false } };
it("qualifies a named snapshot by creating from its immutable provider ID", async () => {
mockSnapshotGet.mockResolvedValue(snapshotRecord);
mockCreate.mockResolvedValue(createMockSandbox());
const lease = await plugin.definition.onEnvironmentAcquireLease!(snapshotProbe);
expect(mockSnapshotGet).toHaveBeenCalledWith("managed-snapshot");
expect(mockCreate.mock.calls[0][0].snapshot).toBe(snapshotRecord.id);
expect(lease.metadata).toMatchObject({ snapshot: "managed-snapshot", snapshotIdentity: {
...snapshotRecord, provider: "daytona", requestedRef: "managed-snapshot",
} });
});
it("does not resolve snapshot names during ordinary acquisition", async () => {
mockCreate.mockResolvedValue(createMockSandbox());
await plugin.definition.onEnvironmentAcquireLease!({ ...snapshotProbe, resolveSnapshotIdentity: undefined });
expect(mockSnapshotGet).not.toHaveBeenCalled();
expect(mockCreate.mock.calls[0][0].snapshot).toBe("managed-snapshot");
});
it.each([{ id: "mutable-name" }, { organizationId: "" }, { name: "different-name" }, { createdAt: "invalid" }])(
"rejects unverified snapshot identity %j before allocation", async invalid => {
mockSnapshotGet.mockResolvedValue({ ...snapshotRecord, ...invalid });
await expect(plugin.definition.onEnvironmentAcquireLease!(snapshotProbe)).rejects.toThrow("immutable snapshot identity");
expect(mockCreate).not.toHaveBeenCalled();
},
);
it("never allocates after a snapshot identity lookup times out", async () => {
vi.useFakeTimers();
try {
let resolveLookup!: (value: typeof snapshotRecord) => void;
mockSnapshotGet.mockReturnValue(new Promise(resolve => { resolveLookup = resolve; }));
const result = plugin.definition.onEnvironmentAcquireLease!(snapshotProbe).catch(error => error);
await vi.advanceTimersByTimeAsync(10_001);
expect(await result).toBeInstanceOf(Error);
resolveLookup(snapshotRecord);
await vi.advanceTimersByTimeAsync(1);
expect(mockCreate).not.toHaveBeenCalled();
} finally { vi.useRealTimers(); }
});
it("declares environment lifecycle handlers", async () => {
expect(await plugin.definition.onHealth?.()).toEqual({
status: "ok",
@@ -210,6 +210,8 @@ type DaytonaSnapshotService = {
delete?: (snapshot: unknown) => Promise<void>;
};
type SnapshotIdentity = { provider: "daytona"; requestedRef: string; id: string; name: string; organizationId: string; createdAt: string };
const WORKSPACE_SENTINEL_RELATIVE_PATH = ".paperclip-runtime/reusable-sandbox-lease.json";
// Quota-safety defaults (minutes). Daytona counts *stopped* sandboxes against
@@ -672,6 +674,7 @@ function leaseMetadata(input: {
resumedFromState?: string | null;
sandboxState?: string | null;
workspaceSentinel?: WorkspaceSentinelResult;
snapshotIdentity?: SnapshotIdentity;
}) {
return {
provider: "daytona",
@@ -681,6 +684,7 @@ function leaseMetadata(input: {
sandboxState: input.sandboxState ?? input.sandbox.state ?? null,
image: input.config.image,
snapshot: input.config.snapshot,
...(input.snapshotIdentity ? { snapshotIdentity: input.snapshotIdentity } : {}),
target: input.sandbox.target,
timeoutMs: input.config.timeoutMs,
reuseLease: input.config.reuseLease,
@@ -956,6 +960,7 @@ async function createSandbox(
purpose?: string;
onCreateAttempt?: (cleanup: PluginEnvironmentCreationCleanup) => void;
onCreateFailure?: () => PluginEnvironmentAcquisitionDiagnostic;
onSnapshotIdentity?: (identity: SnapshotIdentity) => void;
} = {},
): Promise<Sandbox> {
const resourceRequestError = validateRuntimeResourceRequest(config);
@@ -963,6 +968,23 @@ async function createSandbox(
throw new Error(resourceRequestError);
}
const client = createDaytonaClient(config);
let createConfig = config;
if ("resolveSnapshotIdentity" in params && params.resolveSnapshotIdentity && config.snapshot && !config.image) {
// This read happens only during explicit qualification. The SDK does not
// bound snapshot.get; a timed-out read must never continue into allocation.
const snapshot = await withLivenessTimeout("snapshot.identity", Math.min(config.timeoutMs || 10_000, 10_000),
() => client.snapshot.get(config.snapshot!));
if (!/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(snapshot.id ?? "")
|| !snapshot.name || !snapshot.organizationId || !snapshot.createdAt
|| (config.snapshot !== snapshot.id && config.snapshot !== snapshot.name)
|| !Number.isFinite(Date.parse(String(snapshot.createdAt)))) {
throw new Error("Daytona did not return an immutable snapshot identity. Retry the connection probe or select Legacy runner.");
}
const identity: SnapshotIdentity = { provider: "daytona", requestedRef: config.snapshot,
id: snapshot.id, name: snapshot.name, organizationId: snapshot.organizationId, createdAt: new Date(snapshot.createdAt).toISOString() };
createConfig = { ...config, snapshot: identity.id };
options.onSnapshotIdentity?.(identity);
}
// The SDK can create a sandbox and then throw while waiting for it to start.
// Keep an attempt-specific provider name so that failure cannot lose ownership.
const attemptId = randomUUID();
@@ -977,7 +999,7 @@ async function createSandbox(
}), "paperclip-create-attempt": attemptId };
// The SDK mutates params.labels (for example, code-toolbox-language).
// Preserve our immutable ownership snapshot for validation and retry.
const createParams = { ...buildCreateParams(config, { ...labels }), name };
const createParams = { ...buildCreateParams(createConfig, { ...labels }), name };
const cleanup: PluginEnvironmentCreationCleanup = {
providerLeaseId: name, companyId: params.companyId, environmentId: params.environmentId,
...("runId" in params ? { runId: params.runId } : {}),
@@ -2491,6 +2513,7 @@ const plugin = definePlugin({
params: PluginEnvironmentAcquireLeaseParams,
): Promise<PluginEnvironmentLease> {
const config = parseDriverConfig(params.config);
let snapshotIdentity: SnapshotIdentity | undefined;
// One budget covers creation, setup, and inline cleanup. The host leaves
// 30 seconds beyond this deadline to receive/journal the cleanup record.
const budgetMs = config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_DAYTONA_OPERATION_TIMEOUT_MS;
@@ -2534,8 +2557,9 @@ const plugin = definePlugin({
};
const acquire = async (): Promise<PluginEnvironmentLease> => {
const sandbox = await createSandbox(params, config, {
onCreateAttempt: (attempt) => { cleanup = attempt; },
onCreateAttempt: (attempt) => { assertActive(); cleanup = attempt; },
onCreateFailure: observeFailure,
onSnapshotIdentity: identity => { snapshotIdentity = identity; },
});
try {
assertActive();
@@ -2595,6 +2619,7 @@ const plugin = definePlugin({
remoteCwd,
resumedLease: false,
workspaceSentinel,
snapshotIdentity,
}),
};
} catch (error) {
+5
View File
@@ -635,6 +635,11 @@ export interface PluginEnvironmentRunnerIngressEndpointParams
export interface PluginEnvironmentAcquireLeaseParams extends PluginEnvironmentDriverBaseParams {
runId: string;
/** Explicit platform probes may request a provider-owned immutable snapshot
* identity. Supporting providers create by that ID and return snapshotIdentity
* in lease metadata. Older providers may omit it; the host then cannot qualify
* a mutable snapshot name. Ordinary discovery must not allocate a sandbox. */
resolveSnapshotIdentity?: boolean;
workspaceMode?: string;
requestedCwd?: string;
agentId?: string;