diff --git a/apps/web/src/features/sandbox/deployment-specification.test.ts b/apps/web/src/features/sandbox/deployment-specification.test.ts index 7dbff0823..fe306d494 100644 --- a/apps/web/src/features/sandbox/deployment-specification.test.ts +++ b/apps/web/src/features/sandbox/deployment-specification.test.ts @@ -1,5 +1,6 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { defaultSandboxResources, distributionRuntime, savedSpecification, validSandboxResources } from "./deployment-specification"; +import { isRuntimeReleaseField } from "./runtime-release"; import standardSizes from "./standard-sizes.json"; import type { SandboxSpecification } from "@agents-core-web/agents-client"; @@ -48,6 +49,19 @@ describe("deployment resources and Runtime", () => { expect(validSandboxResources("e2b", { cpus: 2, memory_mib: 2048, root_disk_mib: 1024 })).toBe(false); expect(validSandboxResources("microsandbox", { cpus: 2, memory_mib: 2048, root_disk_mib: 1023, environment_disk_mib: 8192 })).toBe(false); }); + it("accepts any well-formed Runtime image name in the Runtime reference", async () => { + const digest = "b".repeat(64); + for (const runtime_ref of [`parsar-core-runtime@sha256:${digest}`, `oac-runtime@sha256:${digest}`]) { + vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response(JSON.stringify({ ...manifest, runtime_ref })))); + expect((await distributionRuntime(new AbortController().signal)).microsandbox_ref).toBe(runtime_ref); + expect(isRuntimeReleaseField("microsandbox_ref", runtime_ref)).toBe(true); + } + for (const runtime_ref of [`oac-runtime:${digest}`, `oac-runtime@sha256:${"b".repeat(63)}`, `oac-runtime@sha256:${"B".repeat(64)}`, `@sha256:${digest}`]) { + vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response(JSON.stringify({ ...manifest, runtime_ref })))); + await expect(distributionRuntime(new AbortController().signal)).rejects.toThrow(); + expect(isRuntimeReleaseField("microsandbox_ref", runtime_ref)).toBe(false); + } + }); it("rejects unavailable, mutable or incomplete release identities", async () => { vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response("{}", { status: 404 }))); await expect(distributionRuntime(new AbortController().signal)).rejects.toThrow(); diff --git a/apps/web/src/features/sandbox/deployment-specification.ts b/apps/web/src/features/sandbox/deployment-specification.ts index 9bf59c471..52ab24559 100644 --- a/apps/web/src/features/sandbox/deployment-specification.ts +++ b/apps/web/src/features/sandbox/deployment-specification.ts @@ -1,4 +1,5 @@ import type { SandboxDeployment, SandboxE2BTemplateBuild, SandboxProvider, SandboxResources, SandboxRuntimeRelease, SandboxSpecification } from "@agents-core-web/agents-client"; +import { RUNTIME_REF_PATTERN } from "./runtime-release"; import standardSizes from "./standard-sizes.json"; interface Manifest { @@ -53,7 +54,7 @@ export async function distributionRuntime(signal: AbortSignal): Promise@sha256:` shape. */ +export const RUNTIME_REF_PATTERN = /^[a-z0-9][a-z0-9._-]*@sha256:[0-9a-f]{64}$/; + const patterns: Record = { source_commit: /^[0-9a-f]{40}$/, image_id: /^sha256:[0-9a-f]{64}$/, image_manifest_digest: /^sha256:[0-9a-f]{64}$/, - microsandbox_ref: /^parsar-core-runtime@sha256:[0-9a-f]{64}$/, + microsandbox_ref: RUNTIME_REF_PATTERN, runtime_sha256: /^[0-9a-f]{64}$/, firmware_sha256: /^[0-9a-f]{64}$/, };