import { readFile } from "node:fs/promises"; import type { CheckedResourceResolver } from "./assembly.js"; import type { CapabilityResource } from "./parser.js"; /** Internal compiler inputs produced by checked-candidate.nix, not authoring * receipts. The Nix composition owns their derivations and exact toolchain. * Ordinary compiler callers omit this map and run all checks directly. */ export async function loadCheckedResources(filename?: string): Promise { if (!filename) return undefined; const entries = JSON.parse(await readFile(filename, "utf8")) as Array<{ kind: string; repository: string; commit: string; artifact: string; }>; const resources = new Map(); for (const entry of entries) { const key = `${entry.kind}\0${entry.repository}\0${entry.commit}`; if (resources.has(key)) throw new Error("Repeated checked resource input"); if (!/^\/nix\/store\/[^/]+$/.test(entry.artifact)) throw new Error("Checked resources must be immutable Nix outputs"); resources.set(key, entry.artifact); } return async (kind, source, lock, dependencies) => { const artifact = resources.get(`${kind}\0${source.repository}\0${source.commit}`); if (!artifact) return undefined; const graph = JSON.parse(await readFile(`${artifact}/graph.json`, "utf8")); const expected = [...dependencies].map(([binding, node]) => ({ binding, resourceKey: node.key })); if ( graph.quixos.commit !== lock.quixos.commit || graph.quixos.repository !== lock.quixos.repository || graph.root.kind !== kind || graph.root.source.repository !== source.repository || graph.root.source.commit !== source.commit || JSON.stringify(graph.root.dependencies) !== JSON.stringify(expected) ) throw new Error("Checked resource input does not match its locked dependency graph"); return JSON.parse(await readFile(`${artifact}/candidate.json`, "utf8")) as CapabilityResource; }; }