From 09fd6b719060d66d2ac671a57bf05890b109c3e7 Mon Sep 17 00:00:00 2001 From: "Timothy J. Aveni" Date: Mon, 21 Sep 2026 12:52:21 -0700 Subject: [PATCH] Commit managed activation selections and reconcile forward (WI-05) --- flake.nix | 3 +- nix/checked-candidate.nix | 3 + src/execution-world/candidate.ts | 107 +++++++++++++++++++++++++++++++ src/execution-world/index.ts | 1 + test/emit-managed.ts | 38 +++++++++++ 5 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 src/execution-world/candidate.ts create mode 100644 test/emit-managed.ts diff --git a/flake.nix b/flake.nix index f805081..2e42917 100644 --- a/flake.nix +++ b/flake.nix @@ -70,6 +70,7 @@ runHook preCheck yarn test node dist/test/emit-portable-reader.js + node dist/test/emit-managed.js runHook postCheck ''; installPhase = '' @@ -85,7 +86,7 @@ cp --reflink=auto --recursive dist "$out/dist" cp package.json "$out/package.json" mkdir -p "$out/share/quixos-protocol/qualification" - cp -r dist/portable-reader "$out/share/quixos-protocol/qualification/" + cp -r dist/portable-reader dist/managed "$out/share/quixos-protocol/qualification/" mkdir -p "$out/bin" for tool in quixos-codegen-ts quixos-codegen-client quixos-qx; do printf '#!/bin/sh\nexec ${pkgs.nodejs_24}/bin/node "%s/libexec/quixos-protocol/%s.mjs" "$@"\n' "$out" "$tool" > "$out/bin/$tool" diff --git a/nix/checked-candidate.nix b/nix/checked-candidate.nix index e460047..0cba848 100644 --- a/nix/checked-candidate.nix +++ b/nix/checked-candidate.nix @@ -155,6 +155,9 @@ assert pkgs.lib.assertMsg (!execution || kind == "workspace") "Execution packages must be checked in their complete workspace; run qx-workspace check from the workspace root."; pkgs.runCommand (if contractOnly then "qx-contract" else "qx-checked-candidate") { } '' mkdir -p "$out" + cp ${ + pkgs.writeText "qx-candidate-source.json" (builtins.toJSON { inherit repository commit kind; }) + } "$out/source.json" cp ${contract}/candidate.json "$out/candidate.json" cp ${contract}/graph.json "$out/graph.json" cp ${manifest} "$out/checks.json" diff --git a/src/execution-world/candidate.ts b/src/execution-world/candidate.ts new file mode 100644 index 0000000..24046b7 --- /dev/null +++ b/src/execution-world/candidate.ts @@ -0,0 +1,107 @@ +import { open, lstat } from "node:fs/promises"; +import { constants } from "node:fs"; +import { join } from "node:path"; +import type { WorkspaceRevision } from "../capability-model/types.js"; +import { compileExecutionPlan, hexDigest, ExecutionPlanError } from "./plan.js"; +import { loadExecutionInstallation, type PackageInstallationSelection } from "./installation.js"; +import { compileKernelProgram } from "./kernel.js"; +import { compileQueryProgram } from "./queries.js"; +const rootPattern = /^\/nix\/store\/[a-z0-9]{32}-[^/\s]+$/; +async function readJson(root: string, file: string): Promise { + const handle = await open(join(root, file), constants.O_RDONLY | constants.O_NOFOLLOW); + try { + const metadata = await handle.stat(); + if (!metadata.isFile() || metadata.size > 32 * 1024 * 1024) throw Error(`Invalid checked candidate file: ${file}`); + return JSON.parse(await handle.readFile("utf8")); + } finally { + await handle.close(); + } +} +/** Revalidate the normal checked-candidate output. This is the shared artifact + * loader, not a second managed-only executable manifest or an activation grant. */ +export async function loadCheckedInstallationCandidate( + root: string, + generator: string, + selections: Readonly> = {}, +) { + if (!rootPattern.test(root) || !(await lstat(root)).isDirectory()) + throw Error("Candidate must be an immutable Nix output directory"); + const [candidate, recordedPlan, artifacts, source] = await Promise.all([ + readJson(root, "candidate.json"), + readJson(root, "execution-plan.json"), + readJson(root, "execution-artifacts.json"), + readJson(root, "source.json"), + ]); + const { executionContracts: _legacyContracts, ...workspace } = candidate; + const plan = compileExecutionPlan(workspace as WorkspaceRevision); + if (hexDigest(plan) !== hexDigest(recordedPlan)) + throw new ExecutionPlanError( + "CANDIDATE_PLAN_MISMATCH", + root, + "Recompiled source contract differs from the stored plan", + ); + if ( + source.kind !== "workspace" || + source.commit !== plan.definition.workspace.sourceRootCommit || + typeof source.repository !== "string" + ) + throw new ExecutionPlanError("CANDIDATE_SOURCE_MISMATCH", root, "Expected exact workspace source provenance"); + const repository = new URL(source.repository); + if ( + !["https:", "ssh:"].includes(repository.protocol) || + repository.username || + repository.password || + repository.hash || + repository.search + ) + throw new ExecutionPlanError("CANDIDATE_SOURCE_INVALID", root, "Expected a source URL without credentials"); + if ( + artifacts.codec !== "camino-checked-execution-v1" || + !artifacts.roots || + typeof artifacts.roots !== "object" || + Array.isArray(artifacts.roots) + ) + throw new ExecutionPlanError("CANDIDATE_ARTIFACTS_INVALID", root, "Expected checked package roots"); + for (const entry of Object.values(artifacts.roots)) + if (typeof entry !== "string" || !rootPattern.test(entry)) + throw new ExecutionPlanError( + "CANDIDATE_ARTIFACTS_INVALID", + root, + "Package artifacts must be immutable Nix roots", + ); + const installation = await loadExecutionInstallation(plan, artifacts.roots, generator, selections); + const kernel = compileKernelProgram(plan), + queries = compileQueryProgram(plan); + // The isolated runner and managed host consume the same compiled programs. + for (const [file, expected] of [ + ["kernel.json", kernel], + ["queries.json", queries], + ] as const) + if (hexDigest(await readJson(root, file)) !== hexDigest(expected)) + throw new ExecutionPlanError( + "CANDIDATE_PROGRAM_MISMATCH", + file, + "Stored interpreter input differs from checked compilation", + ); + const provenance = { + workspaceRevision: workspace.id as string, + source: { repository: source.repository as string, commit: source.commit as string }, + generator, + packages: plan.definition.packages.map((pkg) => ({ revision: pkg.revision, source: pkg.source })), + }; + const reference = { + root, + digest: hexDigest({ plan: plan.digest, world: installation.world, provenance, roots: artifacts.roots }), + }; + return { + reference, + workspace: plan.definition.workspace.workspaceId, + world: installation.world, + plan: plan.digest, + provenance, + kernel, + queries, + installation, + executionPlan: plan, + }; +} diff --git a/src/execution-world/index.ts b/src/execution-world/index.ts index d581c31..b9acf1d 100644 --- a/src/execution-world/index.ts +++ b/src/execution-world/index.ts @@ -14,3 +14,4 @@ export * from "./kernel.js"; export * from "./projections.js"; export * from "./queries.js"; export { generatePortableClientBindings } from "../bindings/portable-client.js"; +export * from "./candidate.js"; diff --git a/test/emit-managed.ts b/test/emit-managed.ts new file mode 100644 index 0000000..22e59c8 --- /dev/null +++ b/test/emit-managed.ts @@ -0,0 +1,38 @@ +/** Protocol/process qualification only; no application fixture enters runtime code. */ +import assert from "node:assert/strict"; +import { mkdir, writeFile } from "node:fs/promises"; +import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/index.js"; +import { compileExecutionPlan } from "../src/execution-world/plan.js"; +import { compileKernelProgram } from "../src/execution-world/kernel.js"; +import { compileQueryProgram } from "../src/execution-world/queries.js"; +const source = { repository: "https://example.test/device-owner.git", commit: "a".repeat(40) }; +const pkg = compileCapabilityResourceSource( + `package Owner id "package:owner" revision "package:owner@1" { + function identity id "identity" : int32 -> record { pid: int32; child: int32; } execution remote; +}`, + { source }, +); +assert.ok(pkg.ok && pkg.resource.kind === "package", JSON.stringify(pkg.diagnostics)); +for (const variant of ["base", "added"]) { + const commit = (variant === "base" ? "a" : "b").repeat(40); + const result = compileCapabilitySource( + `workspace Managed id "workspace:managed-process" revision "workspace:managed-process@${variant}" commit "${commit}" { + import package Owner; + ${variant === "added" ? 'atom Independent id "atom:independent";' : ""} + }`, + "workspace.qx", + { packages: new Map([["Owner", pkg.resource.revision]]), packageClosure: [pkg.resource.revision] }, + ); + assert.ok(result.ok, JSON.stringify(result.diagnostics)); + const plan = compileExecutionPlan(result.workspace), + root = `dist/managed/${variant}`; + await mkdir(root, { recursive: true }); + for (const [file, value] of Object.entries({ + "candidate.json": result.workspace, + "execution-plan.json": plan, + "kernel.json": compileKernelProgram(plan), + "queries.json": compileQueryProgram(plan), + "source.json": { kind: "workspace", repository: "https://example.test/managed.git", commit }, + })) + await writeFile(`${root}/${file}`, JSON.stringify(value)); +}