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:
@@ -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 () => {
|
||||
|
||||
Reference in New Issue
Block a user