import { executionPlanDigestAsync, type ExecutionPlan, type PlanPackage, ExecutionPlanError, hexDigest, executionVersions, } from "./plan.js"; import { createHash } from "node:crypto"; import { canonicalJson } from "../capability-model/evolution.js"; export interface ArtifactFile { path: string; digest: string; bytes: number; mediaType: string; } export interface ArtifactImplementation { id: string; target: string; compatibility: "quixos-service-v1" | "quixos-js-module-v1" | "quixos-restricted-module-v1"; path: string; ports: "quixos-transaction-ports-v1"; registryExport?: string; exports: string[]; /** Every executable/imported local asset, including the entrypoint, must be declared. */ files: ArtifactFile[]; contentDigest: string; } export interface ArtifactGroup { schemaVersion: 1; packageRevisionId: string; bindingDigest: string; versions: ExecutionPlan["definition"]["versions"]; implementations: ArtifactImplementation[]; components?: ComponentArtifact[]; } /** Installation evidence binds a reusable group to the selected exact source. * Compilation receipts never claim that a cache hit was built at a new pin. */ export interface PackageArtifacts extends ArtifactGroup { sourceDigest: string; } export const componentSharedModules = [ "react", "react-dom", "react-dom/client", "react/jsx-runtime", "@quixos/camino-react", "@quixos/camino-react/ui", ] as const; export interface ComponentArtifact { id: string; subject: string; compatibility: "org.quixos.react.esm/1"; path: string; exportName: string; sharedModules: Record<(typeof componentSharedModules)[number], string>; files: ArtifactFile[]; contentDigest: string; } export interface ImplementationSelection { target: string; compatibility: ArtifactImplementation["compatibility"]; /** Optional only when exactly one compatible implementation covers these exports. */ id?: string; exports: readonly string[]; } /** Select from a checked manifest; selection does not establish package trust or isolation. * Never resolve ambiguity by manifest order or silently substitute a requested implementation. */ export function selectArtifactImplementation( manifest: PackageArtifacts, selection: ImplementationSelection, ): ArtifactImplementation { const candidates = manifest.implementations.filter( (entry) => (selection.id === undefined || entry.id === selection.id) && entry.target === selection.target && entry.compatibility === selection.compatibility && selection.exports.every((id) => entry.exports.includes(id)), ); if (candidates.length !== 1) throw new ExecutionPlanError( candidates.length ? "AMBIGUOUS_IMPLEMENTATION" : "IMPLEMENTATION_UNAVAILABLE", manifest.packageRevisionId, `${selection.id ?? "Select an explicit implementation ID"}: expected one ${selection.target}/${selection.compatibility} implementation covering the requested exports; found ${candidates.length}`, ); return candidates[0]!; } export interface CheckedWorld { codec: "camino-world-v1"; plan: string; artifacts: { binding: string; target: string; digest: string }[]; versions: Record; } const fail = (path: string, message: string): never => { throw new ExecutionPlanError("INVALID_ARTIFACT", path, message); }; const object = (value: unknown, path: string): Record => { if (!value || typeof value !== "object" || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype) fail(path, "Expected a plain JSON record"); return value as Record; }; const keys = (record: Record, required: string[], optional: string[], path: string) => { if ( required.some((key) => !Object.hasOwn(record, key)) || Object.keys(record).some((key) => ![...required, ...optional].includes(key)) ) fail(path, "Unexpected or missing fields"); }; const text = (value: unknown, path: string): string => { if ( typeof value !== "string" || !value.length || value.length > 4096 || value.includes("\0") || Buffer.from(value, "utf8").toString("utf8") !== value ) fail(path, "Expected bounded nonempty text"); return value as string; }; const digest = (value: unknown, path: string): string => { if (typeof value !== "string" || !/^[0-9a-f]{64}$/.test(value)) fail(path, "Expected SHA-256 hex"); return value as string; }; const array = (value: unknown, path: string): unknown[] => { if (!Array.isArray(value) || value.length > 10000) fail(path, "Expected a bounded array"); return value as unknown[]; }; const unique = (values: string[], path: string) => { if (new Set(values).size !== values.length) fail(path, "Duplicate identities"); }; export function artifactPath(value: unknown): string { const path = text(value, "artifact path"); if ( path.startsWith("/") || path.includes("\\") || path.split("/").some((part) => !part || part === "." || part === "..") || /[\u0000-\u001f\u007f?#%]/.test(path) ) fail(path, "Expected a normalized relative artifact path"); return path; } /** No self-reference: the digest covers ABI/export metadata and the digests of every declared file. */ export function implementationDigest(implementation: Omit): string { return hexDigest({ ...implementation, exports: [...implementation.exports].sort(), files: [...implementation.files].sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)), }); } export function componentArtifactDigest(component: Omit): string { return hexDigest({ ...component, files: [...component.files].sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)), }); } function parseArtifactFiles(value: unknown, path: string): ArtifactFile[] { const files = array(value, path).map((value): ArtifactFile => { const file = object(value, path); keys(file, ["path", "digest", "bytes", "mediaType"], [], path); if (!Number.isSafeInteger(file.bytes) || (file.bytes as number) < 0 || (file.bytes as number) > 256 * 1024 * 1024) fail(path, "Artifact file exceeds size bound"); return { path: artifactPath(file.path), digest: digest(file.digest, path), bytes: file.bytes as number, mediaType: text(file.mediaType, path), }; }); unique( files.map((file) => file.path), path, ); return files.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)); } function parseComponent(value: unknown, index: number): ComponentArtifact { const path = `components[${index}]`, entry = object(value, path); keys( entry, ["id", "subject", "compatibility", "path", "exportName", "sharedModules", "files", "contentDigest"], [], path, ); if (entry.compatibility !== "org.quixos.react.esm/1") fail(path, "Unsupported component ABI"); const files = parseArtifactFiles(entry.files, `${path}.files`); const shared = object(entry.sharedModules, `${path}.sharedModules`); keys(shared, [...componentSharedModules], [], `${path}.sharedModules`); const sharedModules = Object.fromEntries( componentSharedModules.map((name) => [name, artifactPath(shared[name])]), ) as ComponentArtifact["sharedModules"]; const entryPath = artifactPath(entry.path), exportName = text(entry.exportName, path); if (!/^[$A-Z_a-z][$\w]*$/.test(exportName)) fail(path, "Expected a JavaScript component export name"); for (const modulePath of [entryPath, ...Object.values(sharedModules)]) if (!files.some((file) => file.path === modulePath && file.mediaType === "text/javascript")) fail(path, "Component entry and shared modules require declared JavaScript files"); const component: ComponentArtifact = { id: text(entry.id, path), subject: text(entry.subject, path), compatibility: "org.quixos.react.esm/1", path: entryPath, exportName, sharedModules, files, contentDigest: digest(entry.contentDigest, path), }; const { contentDigest, ...body } = component; if (componentArtifactDigest(body) !== contentDigest) fail(path, "Component metadata digest mismatch"); return component; } export function parseArtifactGroup(value: unknown): ArtifactGroup { const record = object(value, "manifest"); keys( record, ["schemaVersion", "packageRevisionId", "bindingDigest", "versions", "implementations"], ["components"], "manifest", ); if (record.schemaVersion !== 1) fail("manifest", "Unsupported artifact manifest version"); const versions = object(record.versions, "versions"); keys(versions, ["value", "reference", "ports", "crdt"], [], "versions"); for (const [key, value] of Object.entries(versions)) text(value, `versions.${key}`); const implementations = array(record.implementations, "implementations").map( (value, index): ArtifactImplementation => { const path = `implementations[${index}]`, entry = object(value, path); keys( entry, ["id", "target", "compatibility", "path", "ports", "exports", "files", "contentDigest"], ["registryExport"], path, ); if ( !["quixos-service-v1", "quixos-js-module-v1", "quixos-restricted-module-v1"].includes( String(entry.compatibility), ) ) fail(path, "Unsupported artifact ABI"); if (entry.ports !== "quixos-transaction-ports-v1") fail(path, "Unsupported transaction port ABI"); if ( entry.compatibility === "quixos-service-v1" && (entry.target !== "server" || entry.registryExport !== undefined) ) fail(path, "Service must target server and has no JS registry export"); if (entry.compatibility !== "quixos-service-v1") text(entry.registryExport, `${path}.registryExport`); if (entry.compatibility === "quixos-restricted-module-v1" && entry.target !== "server") fail(path, "Restricted modules must target server"); const exports = array(entry.exports, `${path}.exports`).map((value) => text(value, `${path}.exports`)); unique(exports, `${path}.exports`); const files = parseArtifactFiles(entry.files, `${path}.files`); const entryPath = artifactPath(entry.path); if (!files.some((file) => file.path === entryPath)) fail(path, "Entrypoint is not covered by the file manifest"); const result: ArtifactImplementation = { id: text(entry.id, path), target: text(entry.target, path), compatibility: entry.compatibility as ArtifactImplementation["compatibility"], path: entryPath, ports: "quixos-transaction-ports-v1", exports: exports.sort(), files: files.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)), contentDigest: digest(entry.contentDigest, path), ...(entry.registryExport !== undefined ? { registryExport: entry.registryExport as string } : {}), }; const { contentDigest, ...body } = result; if (implementationDigest(body) !== contentDigest) fail(path, "Implementation metadata digest mismatch"); return result; }, ); unique( implementations.map((implementation) => implementation.id), "implementations", ); const components = record.components === undefined ? undefined : array(record.components, "components").map(parseComponent); if (components) unique( components.map((component) => component.id), "components", ); return { schemaVersion: 1, packageRevisionId: text(record.packageRevisionId, "packageRevisionId"), bindingDigest: digest(record.bindingDigest, "bindingDigest"), versions: versions as unknown as PackageArtifacts["versions"], implementations, ...(components ? { components } : {}), }; } export function parsePackageArtifacts(value: unknown): PackageArtifacts { const { sourceDigest, ...group } = object(value, "manifest"); return { ...parseArtifactGroup(group), sourceDigest: digest(sourceDigest, "sourceDigest") }; } export function checkPackageCoverage( expected: Pick, manifest: PackageArtifacts, ): void { for (const module of expected.modules ?? []) if (!expected.components?.some((component) => component.id === module.id)) fail(module.id, `No artifact consumer for module contract ${module.contract} and its subject`); if (expected.bindingDigest !== manifest.bindingDigest || expected.sourceDigest !== manifest.sourceDigest) fail(expected.revision, "Substituted binding schema or source revision"); for (const component of manifest.components ?? []) { const declaration = expected.components?.find((entry) => entry.id === component.id); if (!declaration || declaration.subject !== component.subject || declaration.runtime !== "react") fail(component.id, "Component differs from its declared subject/runtime contract"); } for (const component of expected.components ?? []) if (!manifest.components?.some((entry) => entry.id === component.id)) fail(component.id, "Missing component artifact"); for (const implementation of manifest.implementations) for (const id of implementation.exports) { const entry = expected.exports.find((e) => e.id === id); if (!entry) fail(implementation.id, `Unknown export ${id}`); if ( implementation.compatibility === "quixos-restricted-module-v1" && (entry!.execution.kind === "remote" || !entry!.execution.targets.includes("server")) ) fail(implementation.id, `Export ${id} does not promise restricted server computation`); if ( implementation.target !== "server" && (!entry?.execution || entry.execution.kind === "remote" || !entry.execution.targets.includes(implementation.target)) ) fail(implementation.id, `Export ${id} does not promise target ${implementation.target}`); } for (const entry of expected.exports) { if (!manifest.implementations.some((i) => i.compatibility === "quixos-service-v1" && i.exports.includes(entry.id))) fail(expected.revision, `Missing service fallback for ${entry.id}`); if (entry.execution.kind !== "remote") for (const target of entry.execution.targets) if ( !manifest.implementations.some( (i) => i.target === target && i.exports.includes(entry.id) && (target === "server" || i.compatibility !== "quixos-service-v1"), ) ) fail(expected.revision, `Missing ${target} implementation for ${entry.id}`); } } export type ArtifactReader = (packageRevisionId: string, path: string, maxBytes: number) => Promise; /** Shared by standalone package checks and complete world installation. */ export async function checkArtifactFiles(manifest: ArtifactGroup, read: ArtifactReader): Promise { const files = new Map(); for (const artifact of [...manifest.implementations, ...(manifest.components ?? [])]) for (const file of artifact.files) { const existing = files.get(file.path); if (existing && canonicalJson(existing) !== canonicalJson(file)) fail(file.path, "Conflicting file descriptors"); files.set(file.path, file); } for (const file of files.values()) { const bytes = await read(manifest.packageRevisionId, file.path, file.bytes); if (bytes.byteLength !== file.bytes || createHash("sha256").update(bytes).digest("hex") !== file.digest) fail(file.path, "Artifact bytes do not match the checked content digest"); } } /** Caller supplies a reader confined to the resolved immutable package output, including symlink checks. */ export async function checkExecutionWorld( plan: ExecutionPlan, inputs: readonly unknown[], read: ArtifactReader, ): Promise { if (canonicalJson(plan.definition.versions) !== canonicalJson(executionVersions)) fail("world", "Unsupported plan codec versions"); if ((await executionPlanDigestAsync(plan)) !== plan.digest) fail("plan", "Plan digest mismatch"); const manifests = inputs.map(parsePackageArtifacts); unique( manifests.map((m) => m.packageRevisionId), "packages", ); if (manifests.length !== plan.definition.packages.length) fail("world", "Package closure differs from plan"); const artifacts: CheckedWorld["artifacts"] = []; for (const expected of plan.definition.packages) { const manifest = manifests.find((m) => m.packageRevisionId === expected.revision) ?? fail(expected.revision, "Missing package artifact"); checkPackageCoverage(expected, manifest); if (canonicalJson(manifest.versions) !== canonicalJson(plan.definition.versions)) fail(expected.revision, "Incompatible runtime codecs"); await checkArtifactFiles(manifest, read); for (const implementation of manifest.implementations) { artifacts.push({ binding: JSON.stringify([expected.revision, implementation.id]), target: implementation.target, digest: implementation.contentDigest, }); } for (const component of manifest.components ?? []) { artifacts.push({ binding: JSON.stringify([expected.revision, "component", component.id]), target: "browser-renderer", digest: component.contentDigest, }); } } return { codec: "camino-world-v1", plan: plan.digest, artifacts: artifacts.sort((a, b) => a.binding < b.binding ? -1 : a.binding > b.binding ? 1 : a.target < b.target ? -1 : a.target > b.target ? 1 : 0, ), versions: { ...plan.definition.versions }, }; } /** Node counterpart of replica-core worldDigest. The wire fixture checks cross-package agreement. */ export function checkedWorldDigest(world: CheckedWorld): string { const normalized = { ...world, artifacts: [...world.artifacts].sort((a, b) => a.binding < b.binding ? -1 : a.binding > b.binding ? 1 : a.target < b.target ? -1 : a.target > b.target ? 1 : 0, ), }; const json = canonicalJson(normalized), content = createHash("sha256").update(json).digest("hex"); const components = ["camino-world-v1", content].map((text) => Buffer.from(text, "utf8")); const count = Buffer.alloc(4); count.writeUInt32BE(components.length); const pieces = [count]; for (const bytes of components) { const length = Buffer.alloc(4); length.writeUInt32BE(bytes.length); pieces.push(length, bytes); } return createHash("sha256").update(Buffer.concat(pieces)).digest("hex"); }