fix: bind complete P1 manual dist graph and snapshot identity

prepare records an immutable manifest of every regular backend/dist file
(path/size/sha256/dev/ino) in the owned root and binds its record identity
in ownership; serve revalidates record and every file before spawn, passes
the manifest to the child on fd 4, and the immutable preload hash-verifies
all files at startup and serves only cached verified bytes for any import
below backend/dist, so imported dependency replacement is refused before
RUNNING or never executes. The render command validates the commit
snapshot.json manifest, binds snapshot bytes to the manifest digest and the
installed Git blob, and passes the expected digest to the renderer, which
revalidates head/files digest with bounded no-follow reads and renders only
verified bytes with lease release on refusal.
This commit is contained in:
2026-08-10 17:36:24 +02:00
parent 1c11d61f78
commit c7338969d7
6 changed files with 323 additions and 73 deletions
+92 -2
View File
@@ -402,6 +402,64 @@ test("generated render command validates saved responses and owned snapshot befo
await assert.rejects(lstat(output));
});
const renderSnapshotYaml=`workspace:
schema_version: 3
id: p1-filesystem
name: P1 filesystem
language: en
dwh:
engine: postgres
database: postgres
schema: public
supported_transports: [postgres_direct]
semantic_index:
vector_store: {engine: qdrant, collection: p1-filesystem, dimensions: 1024, distance: cosine}
embedding: {provider: ollama_internal, model: qwen3-embedding:0.6b, dimensions: 1024}
llm_policy:
allowed: [zai/glm-5.2]
evidence:
source: {type: filesystem, uri: workspace-content/p1-filesystem/evidence, patterns: ["**/*.md"], max_bytes: 10485760}
policy: {max_chunk_chars: 4000, retain_published_generations: 3}
`;
test("generated render command binds snapshot bytes to the commit manifest and Git blob end to end", async () => {
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const author=join(run.root,"author"); await mkdir(join(author,"workspaces"),{recursive:true});
await writeFile(join(author,"workspaces","p1-filesystem.yaml"),renderSnapshotYaml);
await execFileAsync("git",["add","workspaces"],{cwd:author}); await execFileAsync("git",["commit","-m","publish p1"],{cwd:author}); await execFileAsync("git",["push","origin","main"],{cwd:author});
const commit=(await execFileAsync("git",["rev-parse","HEAD"],{cwd:author})).stdout.trim();
const blob=(await execFileAsync("git",["rev-parse","HEAD:workspaces/p1-filesystem.yaml"],{cwd:author})).stdout.trim();
await execFileAsync("git",["clone",join(run.root,"remote.git"),join(run.root,"installation/registry/repo")]);
const commitDir=join(run.root,"installation/registry/snapshots",commit); await mkdir(commitDir,{recursive:true});
const snapshot=join(commitDir,"p1-filesystem.yaml"),snapshotPath=snapshot,snapshotSha=sha256(renderSnapshotYaml);
await writeFile(snapshot,renderSnapshotYaml);
const readPath=join(run.root,"responses/read-p1-filesystem.json"),pullPath=join(run.root,"responses/pull.json"),script=join(run.root,"commands/render-1.sh"),script2=join(run.root,"commands/render-2.sh"),output=join(run.root,"rendered/runtime-1.yaml"),output2=join(run.root,"rendered/runtime-2.yaml");
const rendererStub=join(repo,"backend/scripts/p1-render-snapshot.mjs"),stubArgs=join(run.root,"rendered/stub-args.json");
await writeFile(rendererStub,`import { writeFileSync } from "node:fs";\nwriteFileSync(${JSON.stringify(stubArgs)}, JSON.stringify(process.argv.slice(2)));\n`);
const manifest=()=>({head:commit,revisions:[{id:"p1-filesystem",commit,blob,snapshotPath,state:"operational"}],files:{"p1-filesystem.yaml":snapshotSha}});
await writeFile(readPath,JSON.stringify({revision:{id:"p1-filesystem",commit,blob,snapshotPath,state:"operational"}})); await writeFile(pullPath,JSON.stringify({head:commit}));
await assert.rejects(execFileAsync("bash",[script],{cwd:repo}),/snapshot manifest.*(missing|unbounded)/i);
await assert.rejects(lstat(output));
await writeFile(join(commitDir,"snapshot.json"),JSON.stringify(manifest()));
await execFileAsync("bash",[script],{cwd:repo});
assert.deepEqual(JSON.parse(await readFile(stubArgs,"utf8")),["--ownership",join(run.root,"ownership.json"),"--snapshot",snapshot,"--output",output,"--snapshot-sha256",snapshotSha]);
await writeFile(snapshot,renderSnapshotYaml.replace("max_chunk_chars: 4000","max_chunk_chars: 3999"));
await assert.rejects(execFileAsync("bash",[script2],{cwd:repo}),/snapshot bytes differ from manifest digest/);
await assert.rejects(lstat(output2));
await writeFile(snapshot,renderSnapshotYaml);
await writeFile(join(commitDir,"snapshot.json"),JSON.stringify({...manifest(),head:"c".repeat(40)}));
await assert.rejects(execFileAsync("bash",[script2],{cwd:repo}),/snapshot manifest identity is invalid/);
await assert.rejects(lstat(output2));
await writeFile(join(commitDir,"snapshot.json"),JSON.stringify(manifest()));
await writeFile(join(commitDir,"snapshot.json"),JSON.stringify({...manifest(),revisions:[{id:"p1-filesystem",commit,blob:"f".repeat(40),snapshotPath,state:"operational"}]}));
await assert.rejects(execFileAsync("bash",[script2],{cwd:repo}),/saved revision blob differs from snapshot manifest/);
await assert.rejects(lstat(output2));
await writeFile(join(commitDir,"snapshot.json"),JSON.stringify(manifest()));
await writeFile(readPath,JSON.stringify({revision:{id:"p1-filesystem",commit,blob:"f".repeat(40),snapshotPath,state:"operational"}}));
await assert.rejects(execFileAsync("bash",[script2],{cwd:repo}),/saved revision blob differs/);
await assert.rejects(lstat(output2));
});
const sha256=bytes=>createHash("sha256").update(bytes).digest("hex");
async function makeExportZip(directory,name,{payloads={},manifest,workspaceId="p1-filesystem",extra=false,symlinkReadme=false}={}) {
@@ -617,12 +675,44 @@ test("serve refuses a replaced backend dist dependency after prepare", { concurr
await assert.rejects(lstat(marker)); await assert.rejects(lstat(join(run.root,"backend.pid")));
});
test("serve refuses a deterministic dependency check/load swap before execution", { concurrency: false }, async () => {
const repo=await fakeRepo(),marker=join(repo,"dep-swap-executed");
await writeFile(join(repo,"backend/dist/dep.js"),`export function start(){}\n`);
await writeFile(join(repo,"backend/dist/server.js"),`import http from "node:http";\nimport { start } from "./dep.js";\nstart();\nconst server=http.createServer((req,res)=>{res.statusCode=req.url==="/health"?200:200;res.setHeader("content-type","application/json");res.end(JSON.stringify({status:"ok"}));});\nserver.listen(Number(process.env.PORT),process.env.HOST);\n`);
const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),owned=await readManualOwnership({repositoryRoot:repo}),replacement=join(repo,"dep-replacement.js");
await writeFile(replacement,`import {writeFileSync} from "node:fs";writeFileSync(${JSON.stringify(marker)},"executed");export function start(){}\n`);
await assert.rejects(serveManual({repositoryRoot:repo,beforeSpawn:async()=>rename(replacement,join(repo,"backend/dist/dep.js"))}),/identity|changed|refused|distribution|module|readiness|failed/i);
await assert.rejects(lstat(marker)); await assert.rejects(lstat(join(run.root,"backend.pid")));
assert.deepEqual(await matchingManualServerPids(run.root,owned.nonce),[]); assert.deepEqual(await listenerPids(),[]);
});
test("immutable loader serves verified cached dependency bytes after a same-path regular replacement", { concurrency: false }, async () => {
const repo=await fakeRepo(),marker=join(repo,"dep-replacement-executed");
await writeFile(join(repo,"backend/dist/dep.js"),`export function mark(){ globalThis.__depSource = "original"; }\n`);
await writeFile(join(repo,"backend/dist/server.js"),`import http from "node:http";\nlet n = 0;\nconst server=http.createServer(async (req,res)=>{ if(req.url==="/load"){ await import(\`./dep.js?v=\${++n}\`).then(m=>m.mark()); } res.setHeader("content-type","application/json"); res.end(JSON.stringify({status:"ok",dep:globalThis.__depSource??"unset"})); });\nserver.listen(Number(process.env.PORT),process.env.HOST);\n`);
const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),owned=await readManualOwnership({repositoryRoot:repo});
const pid=await serveManual({repositoryRoot:repo});
try {
const health=async()=>(await (await fetch("http://127.0.0.1:8791/health")).json());
const load=async()=>{ await fetch("http://127.0.0.1:8791/load"); return (await health()).dep; };
for(let n=0;n<60;n++){try{if((await health()).status==="ok")break;}catch{}await new Promise(r=>setTimeout(r,50));}
assert.equal(await load(),"original");
await writeFile(join(repo,"backend/dist/dep.js"),`import {writeFileSync} from "node:fs";writeFileSync(${JSON.stringify(marker)},"executed");export function mark(){ globalThis.__depSource = "replaced"; }\n`);
assert.equal(await load(),"original"); await assert.rejects(lstat(marker));
await writeFile(join(repo,"backend/dist/dep.js"),`export function mark(){ globalThis.__depSource = "original"; }\n`);
} finally {
try { await stopManual({repositoryRoot:repo}); } catch { try { process.kill(pid,"SIGTERM"); } catch {} }
}
await cleanupManual({repositoryRoot:repo});
});
test("opened production FD prevents deterministic check-spawn replacement execution", { concurrency: false }, async () => {
const repo=await fakeRepo(),safe=join(repo,"safe-executed"),malicious=join(repo,"malicious-executed"); await installFakeServer(repo,{marker:safe});
const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),script=join(repo,"backend/dist/server.js"),replacement=join(repo,"replacement-server.js");
const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),script=join(repo,"backend/dist/server.js"),replacement=join(repo,"replacement-server.js"),owned=await readManualOwnership({repositoryRoot:repo});
await writeFile(replacement,`import {writeFileSync} from "node:fs";writeFileSync(${JSON.stringify(malicious)},"bad");setInterval(()=>{},1000);`);
await assert.rejects(serveManual({repositoryRoot:repo,beforeSpawn:async()=>rename(replacement,script)}),/entrypoint|identity|changed/i);
await assert.rejects(serveManual({repositoryRoot:repo,beforeSpawn:async()=>rename(replacement,script)}),/entrypoint|identity|changed|readiness|failed|distribution|module/i);
await assert.rejects(lstat(malicious)); await assert.rejects(lstat(join(run.root,"backend.pid")));
assert.deepEqual(await matchingManualServerPids(run.root,owned.nonce),[]);
});
test("foreign 8791 health can never make a delayed authenticated child RUNNING", { concurrency: false }, async () => {