import fs from "node:fs/promises"; import path from "node:path"; import { execFile as callback, spawn } from "node:child_process"; import { createWriteStream } from "node:fs"; import { promisify } from "node:util"; import { fileURLToPath } from "node:url"; const execFile = promisify(callback); const environment = () => ({ ...process.env, QUIXOS_JJ_NO_CHECKPOINT: "1", GIT_TERMINAL_PROMPT: "0" }); export const checkerIdentity = () => process.env.QUIXOS_CHECK_GENERATOR ?? path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); /** Checking snapshots jj, but never publishes or activates the working copy. */ export async function snapshotCommit(root: string): Promise { const run = async (...args: string[]) => (await execFile("jj", args, { cwd: root, env: environment() })).stdout.trim(); // A single normal log snapshots the working copy and observes both values // from that exact revision. Separate status/log processes add no evidence. const [conflict, commit] = (await run("log", "--no-graph", "-r", "@", "-T", 'conflict ++ "\\n" ++ commit_id')).split( "\n", ); if (conflict !== "false") throw new Error("Resolve source conflicts before verification"); if (!commit || !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(commit)) throw new Error("Verification requires an exact jj commit"); await execFile("git", ["diff", "--exit-code", "--no-ext-diff", "--no-textconv", commit, "--"], { cwd: root, env: environment(), }); const { stdout } = await execFile("git", ["ls-files", "--others", "--exclude-standard", "-z"], { cwd: root }); if (stdout) throw new Error("Source contains files not captured by jj; inspect jj tracking before verification"); return commit; } /** Use Git's actual committed tree, never dirty overlays labelled as old pins. */ export async function checkoutCommit(root: string, commit: string, destination: string) { await fs.mkdir(destination, { recursive: true }); const archive = await execFile("git", ["archive", "--format=tar", commit], { cwd: root, encoding: "buffer", maxBuffer: 128 * 1024 * 1024, }); await new Promise((resolve, reject) => { const child = spawn("tar", ["-xf", "-", "-C", destination], { stdio: ["pipe", "ignore", "pipe"] }); let error = ""; child.stderr.on("data", (chunk) => { error += chunk; }); child.on("error", reject); child.on("close", (code) => code === 0 ? resolve() : reject(new Error(`Cannot extract committed source: ${error}`)), ); child.stdin.on("error", reject); child.stdin.end(archive.stdout); }); } /** Shared by provisional checks, template publication and host activation. * The Nix derivation is the cached check; its metadata is internal provenance, * not a certificate authored or approved by the workspace agent. */ export async function buildCheckedPackage(source: string, schema: string, packageRevisionId: string): Promise { const generator = process.env.QUIXOS_CHECK_GENERATOR ?? path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); if (!/^\/nix\/store\/[^/]+$/.test(generator)) throw new Error("Run verification with the installed Quixos tooling (its exact Nix checker is required)"); const builder = path.join(generator, "share/checked-package.nix"); await fs.access(builder); return await new Promise((resolve, reject) => { const child = spawn( "nix", [ "build", "--impure", "--file", builder, "--argstr", "source", source, "--argstr", "schema", schema, "--argstr", "generator", generator, "--argstr", "packageRevisionId", packageRevisionId, "--no-link", "--print-out-paths", "-L", ], { env: environment(), stdio: ["ignore", "pipe", "inherit"] }, ); let output = ""; child.stdout.on("data", (chunk) => { output += chunk; }); child.on("error", reject); child.on("close", (code) => { const artifact = output.trim(); if (code !== 0 || !/^\/nix\/store\/[a-z0-9]{32}-[^\s/]+$/.test(artifact)) reject(new Error(`Checked Nix build failed (${code}); see build diagnostics above`)); else resolve(artifact); }); }); } /** Exact remote source DAG; the Nix checker owns schema construction and all * nested fetches. Keep build noise in a named log, with a bounded failure tail. */ export async function buildImmutableCandidate( source: { repository: string; commit: string }, kind: "workspace" | "interface" | "package" | "build", logFile: string, contractOnly = false, observe?: (phase: "nixEvaluationMs" | "nixBuildMs", ms: number) => void, workspaceId?: string, platformSource?: { repository: string; commit: string; directory: string }, ): Promise { if (workspaceId !== undefined && (kind !== "workspace" || !/^[a-zA-Z0-9][a-zA-Z0-9:._-]{0,255}$/.test(workspaceId))) throw new Error("Instance binding requires a valid Workspace identity and a Workspace root"); if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(source.commit)) throw new Error("An immutable candidate requires an exact commit"); const url = new URL(source.repository); if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash) throw new Error("Candidate origin must be credential-free HTTPS"); if ( platformSource && (Object.keys(platformSource).sort().join(",") !== "commit,directory,repository" || !/^[a-f0-9]{40}$/.test(platformSource.commit) || !/^\/nix\/store\/[a-z0-9]{32}-[^/\s]+$/.test(platformSource.directory)) ) throw Error("Invalid immutable platform source input"); const generator = process.env.QUIXOS_CHECK_GENERATOR ?? path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); if (!/^\/nix\/store\/[^/]+$/.test(generator)) throw new Error("Use the installed Quixos checker"); const builder = path.join(generator, "share/checked-candidate.nix"); await fs.access(builder); const log = createWriteStream(logFile, { flags: "wx", mode: 0o600 }); await new Promise((resolve, reject) => { log.once("open", () => resolve()); log.once("error", reject); }); let logBytes = 0; const run = async (executable: string, args: string[]) => await new Promise((resolve, reject) => { let output = "", tail = "", failure: Error | undefined; const child = spawn(executable, args, { env: environment(), stdio: ["ignore", "pipe", "pipe"] }); const failedLog = (error: Error) => { failure = error; child.kill(); }; log.on("error", failedLog); child.stdout.on("data", (chunk) => { if (failure) return; if (Buffer.byteLength(output) + chunk.length > 65536) failedLog(new Error("Candidate checker output exceeds 64 KiB")); else output += chunk; }); child.stderr.on("data", (chunk) => { if (failure) return; logBytes += chunk.length; if (logBytes > 16 * 1024 * 1024) { failedLog(new Error("Candidate checker log exceeds 16 MiB")); return; } log.write(chunk); tail = (tail + String(chunk)).slice(-6000); }); child.on("error", (error) => { failure = error; }); child.on("close", (code) => { log.off("error", failedLog); if (failure) reject(failure); else if (code !== 0) reject(new Error(`Candidate Nix check failed (${code}). Full log: ${logFile}\n${tail}`)); else resolve(output.trim()); }); }); const timed = async (phase: "nixEvaluationMs" | "nixBuildMs", action: () => Promise) => { const started = performance.now(); try { return await action(); } finally { observe?.(phase, Math.round(performance.now() - started)); } }; let gcDirectory: string | undefined; try { // Evaluation includes import-from-derivation builds (locks and contracts). // Build the resulting derivation directly, without evaluating the DAG twice. // Keep the derivation alive across the two processes, including concurrent // GC. This temporary root is removed on success and on verification failure. gcDirectory = await fs.mkdtemp(path.join(path.dirname(logFile), ".gc-root-")); const gcRoot = path.join(gcDirectory, "candidate"); const derivation = await timed("nixEvaluationMs", async () => { await run("nix-instantiate", [ builder, "--argstr", "repository", source.repository, "--argstr", "commit", source.commit, "--argstr", "kind", kind, "--argstr", "generator", generator, "--arg", "contractOnly", contractOnly ? "true" : "false", ...(workspaceId === undefined ? [] : ["--argstr", "workspaceId", workspaceId]), ...(platformSource ? ["--argstr", "platformSourceJSON", JSON.stringify(platformSource)] : []), "--add-root", gcRoot, "--indirect", ]); return await fs.readlink(gcRoot); }); if (!/^\/nix\/store\/[a-z0-9]{32}-[^\s/]+\.drv$/.test(derivation)) throw new Error("Nix returned an invalid candidate derivation"); const artifact = await timed("nixBuildMs", () => run("nix", ["build", derivation + "^*", "--no-link", "--print-out-paths", "-L"]), ); if (!/^\/nix\/store\/[a-z0-9]{32}-[^\s/]+$/.test(artifact)) throw new Error("Nix returned an invalid candidate artifact"); return artifact; } finally { await new Promise((resolve) => log.end(resolve)); if (gcDirectory) await fs.rm(gcDirectory, { recursive: true, force: true }); } }