Files
ThothII/backend/scripts/p1-manual-acceptance.test.mjs
T
marcopan c7338969d7 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.
2026-08-10 17:36:24 +02:00

772 lines
63 KiB
JavaScript

import assert from "node:assert/strict";
import { execFile, spawn } from "node:child_process";
import { createHash } from "node:crypto";
import { chmod, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, symlink, writeFile } from "node:fs/promises";
import net from "node:net";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import test from "node:test";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
import {
cleanupManual, fixedManualRoot, prepareManual, readManualOwnership, serveManual, stopManual,
} from "./p1-manual-acceptance.mjs";
const roots = [];
async function fakeRepo() {
const root = await realpath(await mkdtemp(join(tmpdir(), "p1-manual-repo-")));
roots.push(root);
for (const path of ["scripts/p1-acceptance.sh", "scripts/test-p1-acceptance.sh", "backend/scripts/p1-acceptance.mjs", "backend/dist/server.js"]) {
await mkdir(dirname(join(root, path)), { recursive: true });
await writeFile(join(root, path), path.endsWith(".sh") ? "#!/bin/sh\n" : "export {};\n", { mode: 0o700 });
}
await symlink(new URL("../node_modules", import.meta.url).pathname, join(root, "backend", "node_modules"), "dir");
await mkdir(join(root, "harness", ".venv", "bin"), { recursive: true });
await writeFile(join(root, "harness", ".venv", "bin", "tht"), "#!/bin/sh\n", { mode: 0o700 });
await chmod(join(root, "harness", ".venv", "bin", "tht"), 0o700);
await mkdir(join(root, "harness", "workspaces"), { recursive: true });
return root;
}
test.afterEach(async () => Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true }))));
test("prepare refuses a pre-existing or symlink fixed root", async () => {
const repo = await fakeRepo(); const root = fixedManualRoot(repo);
await mkdir(root, { recursive: true });
await assert.rejects(prepareManual({ repositoryRoot: repo, skipBuild: true }), /already exists/);
await rm(root, { recursive: true });
const target = `${root}-target`; await mkdir(target, { recursive: true }); await symlink(target, root);
await assert.rejects(prepareManual({ repositoryRoot: repo, skipBuild: true }), /already exists|symlink/);
});
test("prepare requires Task 8 and prerequisites before creating state", async () => {
const repo = await fakeRepo(); await rm(join(repo, "scripts", "p1-acceptance.sh"));
await assert.rejects(prepareManual({ repositoryRoot: repo, skipBuild: true }), /Task 8/);
await assert.rejects(lstat(fixedManualRoot(repo)));
});
test("public wrapper exposes only four actions and rejects automated-run prepare input", async () => {
const wrapper=new URL("../../scripts/p1-manual-acceptance.sh",import.meta.url),source=await readFile(wrapper,"utf8");
assert.match(source,/prepare\|serve\|stop\|cleanup/); assert.doesNotMatch(source,/integration\|automated|prepare\|serve\|stop\|cleanup\|/);
await assert.rejects(execFileAsync("bash",[wrapper.pathname,"prepare",".artifacts/p1-integration/run"]),error=>error.code===2&&/usage:/.test(error.stderr));
});
test("prepare rejects unknown automated-run input before creating its root", async () => {
const repo = await fakeRepo();
await assert.rejects(
prepareManual({ repositoryRoot: repo, skipBuild: true, automatedRun: join(repo, ".artifacts", "p1-integration") }),
/unknown|automated/i,
);
await assert.rejects(lstat(fixedManualRoot(repo)));
});
test("prepare requires the non-Task-8 tht prerequisite before creating state", async () => {
const repo = await fakeRepo(); await rm(join(repo, "harness", ".venv", "bin", "tht"));
await assert.rejects(prepareManual({ repositoryRoot: repo, skipBuild: true }), /missing prerequisite.*tht/);
await assert.rejects(lstat(fixedManualRoot(repo)));
});
test("prepare and permanent docs declare the python3 extractor prerequisite", async () => {
const source=await readFile(new URL("./p1-manual-acceptance.mjs",import.meta.url),"utf8"),docs=await readFile(new URL("../../docs/testing/p1-manual-acceptance.md",import.meta.url),"utf8");
assert.match(source,/for\(const command of \[.*["']python3["']/s); assert.match(docs,/python3/);
});
test("prepare creates independent pending topology, fixtures, commands and guide without verdict", async () => {
const repo = await fakeRepo(); const run = await prepareManual({ repositoryRoot: repo, skipBuild: true });
assert.equal(run.root, fixedManualRoot(repo));
const owned = await readManualOwnership({ repositoryRoot: repo });
assert.equal(owned.status, "PENDING"); assert.equal(owned.listener.host, "127.0.0.1"); assert.equal(owned.listener.port, 8791);
for (const path of ["remote.git/HEAD", "author/.git", "installation/registry", "fixture-secrets/dwh-password", "fixtures/descriptors/p1-filesystem.json", "requests/status.json", "responses", "exports", "rendered", "logs", "commands/render-1.sh", "commands/render-2.sh", "logs/backend.log", "GUIDE.md"]) await lstat(join(run.root, path));
await assert.rejects(lstat(join(run.root, "VERDICT.md")));
const guide = await readFile(join(run.root, "GUIDE.md"), "utf8");
let previous = -1; for (let n = 1; n <= 14; n++) { const at = guide.indexOf(`${n}. `); assert.ok(at > previous, `step ${n} ordered`); previous = at; }
assert.doesNotMatch(guide, /cat .*fixture-secrets|show.*secret contents/i); for(const id of ["p1-filesystem","p1-http","p1-s3"])assert.match(guide,new RegExp(`extract-export\\.sh[^\\n]+${id}`));
for(const contract of [/stable repository-root/,/ownership-first recovery/,/one production Node PID owns both/,/opened no-follow descriptor/,/arbitrary `.git` repository/,/name\/path bytes/,/artifacts\/evidence/,/opened no-follow `rendered` directory/])assert.match(guide,contract);
const traversal=JSON.parse(await readFile(join(run.root,"requests","invalid-traversal.json"),"utf8")); assert.match(traversal.workspace.evidence.source.uri,/\.\./);
const bindings=await readFile(join(run.root,"installation","bindings.env"),"utf8"); assert.match(bindings,new RegExp(`^THT_WORKSPACE_SECRET_ROOTS=.*fixture-secrets`,"m")); const scan=await readFile(join(run.root,"commands","secret-scan.sh"),"utf8"),extract=await readFile(join(run.root,"commands","extract-export.sh"),"utf8"); assert.match(scan,/batch-all-objects/); assert.match(scan,/cat-file/); assert.match(scan,/maybeGitDir/); assert.match(extract,/ZIP contains a symlink or nonregular entry/);
const pubFs=await readFile(join(run.root,"commands","http-05-publish-p1-filesystem.sh"),"utf8"),pubHttp=await readFile(join(run.root,"commands","http-06-publish-p1-http.sh"),"utf8"),pubS3=await readFile(join(run.root,"commands","http-07-publish-p1-s3.sh"),"utf8"); assert.match(pubFs,/responses\/status\.json/); assert.match(pubHttp,/responses\/publish-p1-filesystem\.json/); assert.match(pubS3,/responses\/publish-p1-http\.json/); assert.doesNotMatch(pubFs,/REPLACE_WITH/);
const render = await readFile(join(run.root, "commands", "render-1.sh"), "utf8");
for(const name of await readdir(join(run.root,"commands")))if(name.endsWith(".sh"))await execFileAsync("bash",["-n",join(run.root,"commands",name)]);
assert.match(render, /read-p1-filesystem\.json/); assert.match(render, /responses\/pull\.json/); assert.doesNotMatch(render, /responses\/publish-p1-filesystem\.json/); assert.match(render, /snapshotPath/); assert.match(render, /p1-render-snapshot\.mjs/);
});
test("cleanup rejects unowned, live, mismatched and symlink state and preserves siblings", async () => {
const repo = await fakeRepo(); const integration = join(repo, ".artifacts", "p1-integration"); const sibling = join(repo, ".artifacts", "manual-acceptance", "foreign");
await mkdir(integration, { recursive: true }); await writeFile(join(integration, "sentinel"), "keep");
await mkdir(sibling, { recursive: true }); await writeFile(join(sibling, "sentinel"), "keep");
await assert.rejects(cleanupManual({ repositoryRoot: repo }), /ownership|root/);
const run = await prepareManual({ repositoryRoot: repo, skipBuild: true });
const ownershipPath = join(run.root, "ownership.json"); const owned = JSON.parse(await readFile(ownershipPath)); owned.root += "-wrong"; await writeFile(ownershipPath, JSON.stringify(owned));
await assert.rejects(cleanupManual({ repositoryRoot: repo }), /identity/); assert.equal((await lstat(run.root)).isDirectory(), true);
assert.equal(await readFile(join(integration, "sentinel"), "utf8"), "keep"); assert.equal(await readFile(join(sibling, "sentinel"), "utf8"), "keep");
});
test("cleanup removes only the exact stopped owned root and never creates verdict", async () => {
const repo = await fakeRepo(); const run = await prepareManual({ repositoryRoot: repo, skipBuild: true });
await cleanupManual({ repositoryRoot: repo }); await assert.rejects(lstat(run.root));
});
async function installFakeServer(repo, { startupDelay = 0, healthStatus = 200, marker } = {}) {
await writeFile(join(repo, "backend", "dist", "server.js"), `import http from "node:http";
${marker ? `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(marker)}, "executed");` : ""}
const server=http.createServer((req,res)=>{res.statusCode=req.url==="/health"?${healthStatus}:200;res.setHeader("content-type","application/json");res.end(JSON.stringify({status:"ok",ambient:process.env.THT_DWH_API_KEY,maintenance:process.env.MAINTENANCE_STATE_FILE,wrongMaintenance:process.env.THT_MAINTENANCE_STATE_FILE}));});
setTimeout(()=>server.listen(Number(process.env.PORT),process.env.HOST),${startupDelay});
`);
}
async function matchingManualServerPids(root, nonce) {
const { stdout } = await execFileAsync("ps", ["ax", "-o", "pid=,command="]);
const nonceArg = `--p1-manual-nonce=${nonce}`, rootArg = `--p1-root=${root}`;
return stdout.split("\n").filter(line => line.includes(nonceArg) && line.includes(rootArg))
.map(line => Number(line.trim().match(/^(\d+)/)?.[1])).filter(Number.isSafeInteger);
}
async function listenerPids() {
try {
const { stdout } = await execFileAsync("lsof", ["-nP", "-t", "-iTCP:8791", "-sTCP:LISTEN"]);
return [...new Set(stdout.trim().split("\n").filter(Boolean).map(Number))];
} catch (error) {
if (error.code === 1) return [];
throw error;
}
}
test("prepare and cleanup share one external lifecycle lock for the whole transaction", { concurrency: false }, async () => {
const repo=await fakeRepo(),realGit=(await execFileAsync("which",["git"])).stdout.trim();
const bin=join(repo,"blocking-bin"),entered=join(repo,"prepare-entered"),release=join(repo,"prepare-release");
await mkdir(bin); await writeFile(join(bin,"git"),`#!/bin/sh
if [ "$1" = init ] && [ ! -e ${JSON.stringify(entered)} ]; then
: > ${JSON.stringify(entered)}
n=0
while [ ! -e ${JSON.stringify(release)} ] && [ "$n" -lt 250 ]; do sleep 0.02; n=$((n + 1)); done
[ -e ${JSON.stringify(release)} ] || exit 99
fi
exec ${JSON.stringify(realGit)} "$@"
`,{mode:0o700});
const priorPath=process.env.PATH; process.env.PATH=`${bin}:${priorPath}`;
try {
const preparing=prepareManual({repositoryRoot:repo,skipBuild:true});
for(let n=0;n<200;n++){try{await lstat(entered);break;}catch{} await new Promise(r=>setTimeout(r,10));}
await lstat(entered);
const lock=join(repo,".p1-manual-acceptance.lifecycle.lock");
const lockEntry=await lstat(lock); assert.equal(lockEntry.isFile(),true); assert.equal(lockEntry.mode&0o777,0o600);
const lockBytes=await readFile(lock,"utf8"),lockValue=JSON.parse(lockBytes);
assert.deepEqual(Object.keys(lockValue).sort(),["kind","lifecycleNonce","operation","repositoryRoot","root","schemaVersion"].sort());
assert.equal(lockValue.kind,"p1-manual-lifecycle"); assert.equal(lockValue.operation,"prepare");
assert.match(lockValue.lifecycleNonce,/^[0-9a-f]{64}$/); assert.equal(lockValue.repositoryRoot,repo); assert.equal(lockValue.root,fixedManualRoot(repo));
assert.equal(lockBytes,`${JSON.stringify(lockValue,null,2)}\n`);
await assert.rejects(cleanupManual({repositoryRoot:repo}),/lifecycle lock.*exists|operator inspection/i);
await writeFile(release,"go"); const run=await preparing;
await readManualOwnership({repositoryRoot:repo}); await assert.rejects(lstat(lock));
await cleanupManual({repositoryRoot:repo}); await assert.rejects(lstat(run.root));
} finally { process.env.PATH=priorPath; await writeFile(release,"go").catch(()=>{}); }
});
test("the external lifecycle lock prevents old-root/new-root ABA and ownership is read only under lock", async () => {
const source=await readFile(new URL("./p1-manual-acceptance.mjs",import.meta.url),"utf8");
assert.match(source,/\.p1-manual-acceptance\.lifecycle\.lock/);
const repo=await fakeRepo(),run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const lockPath=join(repo,".p1-manual-acceptance.lifecycle.lock"),nonce="f".repeat(64),bytes=`${nonce}\n`;
const handle=await open(lockPath,"wx",0o600); await handle.writeFile(bytes); await handle.sync();
try {
const old=JSON.parse(await readFile(join(run.root,"ownership.json"),"utf8"));
await rm(run.root,{recursive:true}); await mkdir(run.root,{recursive:true});
await writeFile(join(run.root,"ownership.json"),JSON.stringify({...old,nonce:"e".repeat(64)}),{mode:0o600});
for(const operation of [serveManual,stopManual,cleanupManual]){
await assert.rejects(operation({repositoryRoot:repo}),/lifecycle lock.*exists|operator inspection/i);
assert.equal((await lstat(run.root)).isDirectory(),true);
}
} finally { await handle.close(); await rm(lockPath,{force:true}); }
});
test("external lifecycle lock release preserves an exact-byte inode replacement", { concurrency: false }, async () => {
const repo=await fakeRepo(),realGit=(await execFileAsync("which",["git"])).stdout.trim();
const bin=join(repo,"replacement-bin"),entered=join(repo,"replacement-entered"),release=join(repo,"replacement-release");
await mkdir(bin); await writeFile(join(bin,"git"),`#!/bin/sh
if [ "$1" = init ] && [ ! -e ${JSON.stringify(entered)} ]; then
: > ${JSON.stringify(entered)}
n=0
while [ ! -e ${JSON.stringify(release)} ] && [ "$n" -lt 250 ]; do sleep 0.02; n=$((n + 1)); done
[ -e ${JSON.stringify(release)} ] || exit 99
fi
exec ${JSON.stringify(realGit)} "$@"
`,{mode:0o700});
const priorPath=process.env.PATH; process.env.PATH=`${bin}:${priorPath}`; let preparing;
try {
preparing=prepareManual({repositoryRoot:repo,skipBuild:true});
for(let n=0;n<200;n++){try{await lstat(entered);break;}catch{} await new Promise(r=>setTimeout(r,10));}
await lstat(entered);
const lock=join(repo,".p1-manual-acceptance.lifecycle.lock"),bytes=await readFile(lock);
const original=await lstat(lock),replacement=join(dirname(lock),".replacement-lifecycle-lock");
await writeFile(replacement,bytes,{mode:0o600}); const replacementEntry=await lstat(replacement);
assert.notEqual(replacementEntry.ino,original.ino); await rename(replacement,lock); await writeFile(release,"go");
await assert.rejects(preparing,/lifecycle record.*unsafe|lifecycle record.*changed|operator inspection/i); preparing=undefined;
const retained=await lstat(lock); assert.equal(retained.dev,replacementEntry.dev); assert.equal(retained.ino,replacementEntry.ino);
assert.deepEqual(await readFile(lock),bytes);
} finally {
process.env.PATH=priorPath; await writeFile(release,"go").catch(()=>{}); if(preparing)await preparing.catch(()=>{});
}
});
test("prepare records one regular 0600 backend log and no generated supervisor", async () => {
const repo=await fakeRepo(),run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const owned=await readManualOwnership({repositoryRoot:repo}),entry=await lstat(join(run.root,"logs/backend.log"));
assert.equal(entry.isFile(),true); assert.equal(entry.isSymbolicLink(),false); assert.equal(entry.mode&0o777,0o600);
assert.deepEqual(owned.backendLog,{path:join(run.root,"logs/backend.log"),dev:entry.dev,ino:entry.ino});
await assert.rejects(lstat(join(run.root,"installation/runtime/p1-backend-supervisor.mjs")));
});
// A delayed real listener leaves the pre-fix port-check/spawn window open long enough for every
// overlapping call. The backend.pid reservation, rather than scheduler timing, must pick one owner.
test("concurrent serves reserve one exact process and leave no orphan after stop", { concurrency: false }, async () => {
const repo=await fakeRepo(); await installFakeServer(repo,{startupDelay:400});
const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const owned=await readManualOwnership({repositoryRoot:repo}); let winner;
try {
const results=await Promise.allSettled(Array.from({length:12},()=>serveManual({repositoryRoot:repo})));
const fulfilled=results.filter(result=>result.status==="fulfilled");
assert.equal(fulfilled.length,1,`one serve fulfills: ${results.map(result=>result.status).join(",")}`);
assert.equal(results.filter(result=>result.status==="rejected").length,11);
winner=fulfilled[0].value;
const pidPath=join(run.root,"backend.pid"),record=JSON.parse(await readFile(pidPath,"utf8")),entry=await lstat(pidPath);
assert.equal(entry.mode&0o777,0o600); assert.equal(record.status,"RUNNING");
assert.match(record.reservationNonce,/^[0-9a-f]{64}$/); assert.equal(record.pid,winner);
assert.equal(record.nonce,owned.nonce); assert.equal(record.root,run.root); assert.equal(record.repositoryRoot,repo);
assert.deepEqual(await matchingManualServerPids(run.root,owned.nonce),[winner]);
assert.deepEqual(await listenerPids(),[winner]); assert.doesNotThrow(()=>process.kill(winner,0));
await stopManual({repositoryRoot:repo});
await assert.rejects(lstat(pidPath)); assert.deepEqual(await matchingManualServerPids(run.root,owned.nonce),[]);
assert.deepEqual(await listenerPids(),[]); assert.throws(()=>process.kill(winner,0));
await cleanupManual({repositoryRoot:repo}); await assert.rejects(lstat(run.root));
} finally {
for(const pid of await matchingManualServerPids(run.root,owned.nonce))try{process.kill(pid,"SIGTERM");}catch{}
await new Promise(resolvePromise=>setTimeout(resolvePromise,50));
for(const pid of await matchingManualServerPids(run.root,owned.nonce))try{process.kill(pid,"SIGKILL");}catch{}
await rm(run.root,{recursive:true,force:true});
}
});
test("cooperative stop is serialized and production never sends a numeric terminating signal", { concurrency: false }, async () => {
const source=await readFile(new URL("./p1-manual-acceptance.mjs",import.meta.url),"utf8");
assert.doesNotMatch(source,/process\.kill\([^,]+,\s*["']SIG(?:TERM|KILL|INT)/);
const repo=await fakeRepo(); await installFakeServer(repo); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const owned=await readManualOwnership({repositoryRoot:repo}); const pid=await serveManual({repositoryRoot:repo});
const record=JSON.parse(await readFile(join(run.root,"backend.pid"),"utf8")); assert.equal(record.control.host,"127.0.0.1");
const unauthorized=await new Promise((resolvePromise,reject)=>{const socket=net.createConnection(record.control),timer=setTimeout(()=>socket.destroy(new Error("control timeout")),1000);let bytes="";socket.setEncoding("utf8");socket.on("connect",()=>socket.end(JSON.stringify({action:"stop",nonce:"0".repeat(64)})));socket.on("data",chunk=>bytes+=chunk);socket.on("error",reject);socket.on("close",()=>{clearTimeout(timer);resolvePromise(bytes);});});
assert.equal(unauthorized,""); assert.doesNotThrow(()=>process.kill(pid,0));
const stopped=await Promise.allSettled([stopManual({repositoryRoot:repo}),stopManual({repositoryRoot:repo})]);
assert.equal(stopped.filter(result=>result.status==="fulfilled").length,1);
assert.equal(stopped.filter(result=>result.status==="rejected").length,1);
await assert.rejects(lstat(join(run.root,"backend.pid"))); assert.deepEqual(await listenerPids(),[]);
assert.deepEqual(await matchingManualServerPids(run.root,owned.nonce),[]); assert.throws(()=>process.kill(pid,0));
await cleanupManual({repositoryRoot:repo});
});
test("serve binds the one fixed loopback address, refuses a second PID, and guarded stop removes identity", { concurrency: false }, async () => {
const repo=await fakeRepo(); await installFakeServer(repo); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const priorAmbient=process.env.THT_DWH_API_KEY; process.env.THT_DWH_API_KEY="AMBIENT-MUST-NOT-PASS"; const pid=await serveManual({repositoryRoot:repo}); assert.equal(Number.isSafeInteger(pid),true);
const health=await (await fetch("http://127.0.0.1:8791/health")).json(); assert.equal(health.status,"ok"); assert.equal(health.ambient,undefined); assert.equal(health.wrongMaintenance,undefined); assert.equal(health.maintenance,join(run.root,"installation/data/maintenance.json")); if(priorAmbient===undefined)delete process.env.THT_DWH_API_KEY;else process.env.THT_DWH_API_KEY=priorAmbient;
await assert.rejects(serveManual({repositoryRoot:repo}),/PID record/);
await stopManual({repositoryRoot:repo}); await assert.rejects(lstat(join(run.root,"backend.pid")));
await assert.rejects(fetch("http://127.0.0.1:8791/health",{signal:AbortSignal.timeout(200)}));
await cleanupManual({repositoryRoot:repo});
});
test("serve requires a 2xx HTTP health check and leaves no orphan on 503", { concurrency: false }, async () => {
const repo=await fakeRepo(); await installFakeServer(repo,{healthStatus:503}); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const owned=await readManualOwnership({repositoryRoot:repo});
await assert.rejects(serveManual({repositoryRoot:repo}),/health|readiness/i);
await assert.rejects(lstat(join(run.root,"backend.pid")));
assert.deepEqual(await listenerPids(),[]); assert.deepEqual(await matchingManualServerPids(run.root,owned.nonce),[]);
});
test("serve launches exact server.js with immutable preload and fixed owned control port", { concurrency: false }, async () => {
const repo=await fakeRepo(); await installFakeServer(repo); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const pid=await serveManual({repositoryRoot:repo}),record=JSON.parse(await readFile(join(run.root,"backend.pid"),"utf8"));
assert.equal(record.pid,pid); assert.equal(record.script,join(repo,"backend/dist/server.js"));
assert.equal(record.control.host,"127.0.0.1"); assert.equal(record.control.port,8792);
assert.match(record.preload,/^data:text\/javascript;base64,/);
const args=(await execFileAsync("ps",["-ww","-p",String(pid),"-o","command="])).stdout.trim();
assert.equal(args,[process.execPath,"--import",record.preload,record.script,`--p1-manual-nonce=${record.nonce}`,`--p1-root=${run.root}`,`--p1-control-nonce=${record.reservationNonce}`,`--p1-entry-sha256=${record.entrypoint.sha256}`,`--p1-entry-dev=${record.entrypoint.dev}`,`--p1-entry-ino=${record.entrypoint.ino}`].join(" "));
await stopManual({repositoryRoot:repo});
});
test("serve refuses legacy supervisor, runtime, server and log substitutions before code or outside writes", { concurrency: false }, async () => {
for(const kind of ["legacy-supervisor","runtime-symlink","server-symlink","log-symlink","log-replaced"]){
const repo=await fakeRepo(),marker=join(repo,`outside-${kind}.marker`); await installFakeServer(repo,{marker});
const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),outside=join(repo,`outside-${kind}`); await mkdir(outside);
if(kind==="legacy-supervisor")await symlink(join(outside,"outside.mjs"),join(run.root,"installation/runtime/p1-backend-supervisor.mjs"));
if(kind==="runtime-symlink"){await rm(join(run.root,"installation/runtime"),{recursive:true});await symlink(outside,join(run.root,"installation/runtime"));}
if(kind==="server-symlink"){
const external=join(outside,"server.js"); await writeFile(external,`import {writeFileSync} from "node:fs";writeFileSync(${JSON.stringify(marker)},"bad");`);
await rm(join(repo,"backend/dist/server.js")); await symlink(external,join(repo,"backend/dist/server.js"));
}
if(kind==="log-symlink"){await rm(join(run.root,"logs/backend.log"));await symlink(join(outside,"captured.log"),join(run.root,"logs/backend.log"));}
if(kind==="log-replaced"){await rm(join(run.root,"logs/backend.log"));await writeFile(join(run.root,"logs/backend.log"),"",{mode:0o600});}
await assert.rejects(serveManual({repositoryRoot:repo}),/unsafe|identity|symlink|legacy|realpath|log/i,kind);
await assert.rejects(lstat(marker),undefined,`${kind} must refuse before server execution`);
assert.deepEqual(await readdir(outside),kind==="server-symlink"?["server.js"]:[]);
await assert.rejects(lstat(join(run.root,"backend.pid")));
await rm(run.root,{recursive:true,force:true});
}
});
test("serve refuses an occupied fixed control port before spawning", { concurrency: false }, async () => {
const repo=await fakeRepo(),marker=join(repo,"server-executed"); await installFakeServer(repo,{marker}); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const blocker=net.createServer(); await new Promise((resolvePromise,reject)=>blocker.once("error",reject).listen(8792,"127.0.0.1",resolvePromise));
try { await assert.rejects(serveManual({repositoryRoot:repo}),/8792.*occupied|control.*occupied/); } finally { await new Promise(resolvePromise=>blocker.close(resolvePromise)); }
await assert.rejects(lstat(marker)); await assert.rejects(lstat(join(run.root,"backend.pid")));
});
test("serve refuses an occupied fixed port and never creates a PID or verdict", { concurrency: false }, async () => {
const repo=await fakeRepo(); await installFakeServer(repo); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const blocker=net.createServer(); await new Promise((resolvePromise,reject)=>blocker.once("error",reject).listen(8791,"127.0.0.1",resolvePromise));
try { await assert.rejects(serveManual({repositoryRoot:repo}),/occupied/); } finally { await new Promise(resolvePromise=>blocker.close(resolvePromise)); }
await assert.rejects(lstat(join(run.root,"backend.pid"))); await assert.rejects(lstat(join(run.root,"VERDICT.md")));
});
test("serve and cleanup refuse stale or mismatched PID records without signaling", async () => {
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
await writeFile(join(run.root,"backend.pid"),JSON.stringify({pid:999999,nonce:"wrong"}),{mode:0o600});
await assert.rejects(serveManual({repositoryRoot:repo}),/PID record/);
await assert.rejects(stopManual({repositoryRoot:repo}),/identity mismatch/);
await assert.rejects(cleanupManual({repositoryRoot:repo}),/identity|stale/);
assert.equal((await lstat(run.root)).isDirectory(),true);
});
test("serve refuses non-loopback ownership without creating process state", async () => {
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const ownershipPath=join(run.root,"ownership.json"),owned=JSON.parse(await readFile(ownershipPath,"utf8"));
owned.listener.host="0.0.0.0"; await writeFile(ownershipPath,JSON.stringify(owned));
await assert.rejects(serveManual({repositoryRoot:repo}),/identity|loopback|bind/);
await assert.rejects(lstat(join(run.root,"backend.pid")));
});
test("cleanup refuses a correctly owned live server until guarded stop", { concurrency: false }, async () => {
const repo=await fakeRepo(); await installFakeServer(repo); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const pid=await serveManual({repositoryRoot:repo});
try {
await assert.rejects(cleanupManual({repositoryRoot:repo}),/owned backend is live|stop first/);
assert.doesNotThrow(()=>process.kill(pid,0));
} finally {
try { await stopManual({repositoryRoot:repo}); } catch { try { process.kill(pid,"SIGTERM"); } catch {} }
}
await cleanupManual({repositoryRoot:repo}); await assert.rejects(lstat(run.root));
});
async function processStartIdentity(pid) {
return (await execFileAsync("ps",["-p",String(pid),"-o","lstart="])).stdout.trim();
}
async function stopTestProcess(child) {
if (child.exitCode === null) child.kill("SIGTERM");
if (child.exitCode === null) await new Promise(resolvePromise=>child.once("exit",resolvePromise));
}
test("live foreign executable, cwd, start and args mismatches are never signaled", async () => {
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true});
const owned=JSON.parse(await readFile(join(run.root,"ownership.json"),"utf8"));
const script=join(run.root,"installation/runtime/p1-backend-supervisor.mjs"),nonceArg=`--p1-manual-nonce=${owned.nonce}`,rootArg=`--p1-root=${run.root}`,reservationNonce="a".repeat(64),controlArg=`--p1-control-nonce=${reservationNonce}`;
await writeFile(script,"setInterval(()=>{},1000);\n",{mode:0o600});
const cases=[
["executable",()=>spawn("bash",["-c","while :; do sleep 1; done",script,nonceArg,rootArg,controlArg],{cwd:repo,stdio:"ignore"}),{}],
["cwd",()=>spawn(process.execPath,[script,nonceArg,rootArg,controlArg],{cwd:tmpdir(),stdio:"ignore"}),{}],
["start",()=>spawn(process.execPath,[script,nonceArg,rootArg,controlArg],{cwd:repo,stdio:"ignore"}),{startIdentity:"foreign-start"}],
["args",()=>spawn(process.execPath,[script],{cwd:repo,stdio:"ignore"}),{}],
];
for(const [name,start,override] of cases){
const child=start();
try {
let actualStart=""; for(let n=0;n<50&&!actualStart;n++){try{actualStart=await processStartIdentity(child.pid);}catch{} if(!actualStart)await new Promise(r=>setTimeout(r,20));}
assert.ok(actualStart,`live ${name} process started`);
const record={schemaVersion:1,kind:"p1-manual-backend",status:"RUNNING",pid:child.pid,reservationNonce,nonce:owned.nonce,root:run.root,repositoryRoot:repo,executable:process.execPath,script,startIdentity:actualStart,control:{host:"127.0.0.1",port:1},...override};
await writeFile(join(run.root,"backend.pid"),JSON.stringify(record),{mode:0o600});
await assert.rejects(stopManual({repositoryRoot:repo}),/process identity mismatch|refusing cooperative control/);
assert.doesNotThrow(()=>process.kill(child.pid,0));
await rm(join(run.root,"backend.pid"));
} finally { await stopTestProcess(child); await rm(join(run.root,"backend.pid"),{force:true}); }
}
});
test("generated render command validates saved responses and owned snapshot before renderer", async () => {
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}); const script=join(run.root,"commands/render-1.sh"), output=join(run.root,"rendered/runtime-1.yaml");
const invoke=()=>execFileAsync("bash",[script],{cwd:repo});
await assert.rejects(invoke(),/saved response is missing/);
await writeFile(join(run.root,"responses/read-p1-filesystem.json"),"{"); await writeFile(join(run.root,"responses/pull.json"),"{}");
await assert.rejects(invoke(),/malformed JSON/);
const a="a".repeat(40),b="b".repeat(40),outside=join(repo,"outside.yaml"); await writeFile(outside,"x");
await writeFile(join(run.root,"responses/read-p1-filesystem.json"),JSON.stringify({revision:{commit:a,snapshotPath:outside}})); await writeFile(join(run.root,"responses/pull.json"),JSON.stringify({head:b}));
await assert.rejects(invoke(),/revisions differ/);
await writeFile(join(run.root,"responses/pull.json"),JSON.stringify({head:a})); await assert.rejects(invoke(),/snapshot escapes/);
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}={}) {
const source=join(directory,`${name}-source`),zip=join(directory,`${name}.zip`); await mkdir(source,{recursive:true});
const files={"workspace.yaml":`workspace:\n id: ${workspaceId}\n`,"contract.env.example":"SAFE=path\n","README.md":"# Safe\n",...payloads};
const value=manifest??{schema_version:1,workspace_id:workspaceId,files:Object.fromEntries(Object.entries(files).map(([n,b])=>[n,sha256(b)]))};
await writeFile(join(source,"manifest.json"),JSON.stringify(value));
for(const [file,bytes] of Object.entries(files))if(!(symlinkReadme&&file==="README.md"))await writeFile(join(source,file),bytes);
if(symlinkReadme)await symlink("workspace.yaml",join(source,"README.md"));
if(extra)await writeFile(join(source,"extra.txt"),"extra");
const names=["manifest.json","workspace.yaml","contract.env.example","README.md",...(extra?["extra.txt"]:[])];
await execFileAsync("zip",["-q",...(symlinkReadme?["-y"]:[]),zip,...names],{cwd:source}); return zip;
}
test("generated ZIP verifier enforces exact manifest mapping, hashes, entries and regular files", async () => {
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),extract=join(run.root,"commands/extract-export.sh");
const invoke=async(name,options={})=>execFileAsync("bash",[extract,await makeExportZip(run.root,name,options),join(run.root,"exports/extracted",name),"p1-filesystem"],{cwd:repo});
await invoke("valid");
const safe={"workspace.yaml":"workspace:\n id: p1-filesystem\n","contract.env.example":"SAFE=path\n","README.md":"# Safe\n"};
const hashes=Object.fromEntries(Object.entries(safe).map(([n,b])=>[n,sha256(b)]));
await assert.rejects(invoke("missing-map",{manifest:{schema_version:1,workspace_id:"p1-filesystem",files:{"workspace.yaml":hashes["workspace.yaml"],"contract.env.example":hashes["contract.env.example"]}}}),/manifest/i);
await assert.rejects(invoke("short-hash",{manifest:{schema_version:1,workspace_id:"p1-filesystem",files:{...hashes,"README.md":"abc"}}}),/manifest/i);
await assert.rejects(invoke("extra-entry",{extra:true}),/unsafe-zip/);
await assert.rejects(invoke("nonregular",{symlinkReadme:true}),/symlink|nonregular/);
});
test("generated ZIP verifier binds identity, stages source once, and rejects symlink output ancestry", async () => {
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),extract=join(run.root,"commands/extract-export.sh");
for(const id of ["p1-filesystem","p1-http","p1-s3"]){
const zip=await makeExportZip(run.root,`valid-${id}`,{workspaceId:id});
await execFileAsync("bash",[extract,zip,join(run.root,"exports/extracted",id),id],{cwd:repo});
}
const wrong=await makeExportZip(run.root,"wrong-valid-id",{workspaceId:"p1-http"});
await assert.rejects(execFileAsync("bash",[extract,wrong,join(run.root,"exports/extracted/wrong-id"),"p1-s3"],{cwd:repo}),/workspace.*identity|workspace_id/i);
const descriptorMismatch=await makeExportZip(run.root,"descriptor-mismatch",{workspaceId:"p1-http",payloads:{"workspace.yaml":"workspace:\n id: p1-s3\n"}});
await assert.rejects(execFileAsync("bash",[extract,descriptorMismatch,join(run.root,"exports/extracted/descriptor-mismatch"),"p1-http"],{cwd:repo}),/workspace.*identity|descriptor/i);
const outside=join(repo,"outside-extract"); await mkdir(outside); await rm(join(run.root,"exports/extracted"),{recursive:true}); await symlink(outside,join(run.root,"exports/extracted"));
const safe=await makeExportZip(run.root,"symlink-parent");
await assert.rejects(execFileAsync("bash",[extract,safe,join(run.root,"exports/extracted/escape"),"p1-filesystem"],{cwd:repo}),/symlink|owned|unsafe/i);
assert.deepEqual(await readdir(outside),[]); await rm(join(run.root,"exports/extracted")); await mkdir(join(run.root,"exports/extracted"));
const original=await makeExportZip(run.root,"replace-original"),replacement=await makeExportZip(run.root,"replace-malicious",{extra:true});
const bin=join(run.root,"swap-bin"),markerPath=join(run.root,"swap-once"); await mkdir(bin);
const realUnzip=(await execFileAsync("which",["unzip"])).stdout.trim();
await writeFile(join(bin,"unzip"),`#!/bin/sh
if [ ! -e "$P1_SWAP_MARKER" ]; then cp "$P1_SWAP_REPLACEMENT" "$P1_SWAP_ORIGINAL"; : > "$P1_SWAP_MARKER"; fi
exec ${realUnzip} "$@"
`,{mode:0o700});
await execFileAsync("bash",[extract,original,join(run.root,"exports/extracted/staged-source"),"p1-filesystem"],{cwd:repo,env:{...process.env,PATH:`${bin}:${process.env.PATH}`,P1_SWAP_MARKER:markerPath,P1_SWAP_REPLACEMENT:replacement,P1_SWAP_ORIGINAL:original}});
await lstat(markerPath); await lstat(join(run.root,"exports/extracted/staged-source/manifest.json"));
const generated=await readFile(extract,"utf8"); assert.match(generated,/source_fd = os\.open\(zip_path/); assert.match(generated,/dir_fd=base_fd/); assert.match(generated,/O_NOFOLLOW/); assert.match(generated,/staged archive SHA mismatch/);
});
test("generated ZIP verifier anchors output when the extraction base is swapped on first unzip", async () => {
const repo=await fakeRepo(),run=await prepareManual({repositoryRoot:repo,skipBuild:true}),extract=join(run.root,"commands/extract-export.sh");
const zip=await makeExportZip(run.root,"ancestor-swap"),base=join(run.root,"exports/extracted"),moved=join(run.root,"exports/extracted-original"),outside=join(repo,"outside-extraction-race");
const bin=join(repo,"unzip-swap-bin"),marker=join(repo,"unzip-swapped"),realUnzip=(await execFileAsync("which",["unzip"])).stdout.trim();
await mkdir(bin); await mkdir(outside);
await writeFile(join(bin,"unzip"),`#!/bin/sh
if [ ! -e "$P1_SWAP_MARKER" ]; then
mv "$P1_SWAP_BASE" "$P1_SWAP_MOVED"
ln -s "$P1_SWAP_OUTSIDE" "$P1_SWAP_BASE"
: > "$P1_SWAP_MARKER"
fi
exec ${realUnzip} "$@"
`,{mode:0o700});
await assert.rejects(execFileAsync("bash",[extract,zip,join(base,"escaped"),"p1-filesystem"],{cwd:repo,env:{...process.env,PATH:`${bin}:${process.env.PATH}`,P1_SWAP_MARKER:marker,P1_SWAP_BASE:base,P1_SWAP_MOVED:moved,P1_SWAP_OUTSIDE:outside}}),/owned extraction root|identity|changed|unsafe/i);
await lstat(marker); assert.deepEqual(await readdir(outside),[]);
});
test("generated ZIP verifier scans all four extracted byte streams for Evidence and canaries", async () => {
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),extract=join(run.root,"commands/extract-export.sh");
const markers=["P1 manually curated Evidence","DWH-"+"d".repeat(32),"CANARY-MUST-BE-REJECTED"];
for(const marker of markers)for(const target of ["manifest.json","workspace.yaml","contract.env.example","README.md"]){
const name=`scan-${markers.indexOf(marker)}-${target.replaceAll(".","-")}`,payloads=target==="manifest.json"?{}:{[target]:marker};
const files={"workspace.yaml":"workspace:\n id: p1-filesystem\n","contract.env.example":"SAFE=path\n","README.md":"# Safe\n",...payloads};
const manifest={schema_version:1,workspace_id:target==="manifest.json"?marker:"p1-filesystem",files:Object.fromEntries(Object.entries(files).map(([n,b])=>[n,sha256(b)]))};
const zip=await makeExportZip(run.root,name,{payloads,manifest});
await assert.rejects(execFileAsync("bash",[extract,zip,join(run.root,"exports/extracted",name),"p1-filesystem"],{cwd:repo}),error=>/Evidence|canary/.test(error.stderr)&&!error.stderr.includes(marker),`${target} must reject ${marker.slice(0,8)}`);
}
});
test("generated secret scan excludes only the exact request fixture and hides fixed canary", async () => {
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}); const installed=join(run.root,"installation/registry/repo"),scan=join(run.root,"commands/secret-scan.sh"),canary="CANARY-MUST-BE-REJECTED";
await execFileAsync("git",["clone",join(run.root,"remote.git"),installed]); await execFileAsync("bash",[scan],{cwd:repo});
const leak=join(run.root,"responses/requests/invalid-credential.json"); await mkdir(dirname(leak),{recursive:true}); await writeFile(leak,canary);
await assert.rejects(execFileAsync("bash",[scan],{cwd:repo}),error=>/secret canary found/.test(error.stderr)&&!error.stderr.includes(canary));
});
test("generated secret scan reads Git metadata and arbitrary dot-git directories without printing values", async () => {
for(const rel of ["author/.git/manual-leak","responses/.git/leak"]){
const canary="SECRET-"+"a".repeat(32),repo=await fakeRepo(),run=await prepareManual({repositoryRoot:repo,skipBuild:true}),scan=join(run.root,"commands/secret-scan.sh");
await execFileAsync("git",["clone",join(run.root,"remote.git"),join(run.root,"installation/registry/repo")]);
await mkdir(dirname(join(run.root,rel)),{recursive:true}); await writeFile(join(run.root,rel),canary);
await assert.rejects(execFileAsync("bash",[scan],{cwd:repo}),error=>/secret canary found/.test(error.stderr)&&!error.stderr.includes(canary),`${rel} must be scanned with a redacted finding`);
await rm(run.root,{recursive:true,force:true});
}
});
test("generated secret scan reads raw dangling commit, tag, and tree objects without printing values", async () => {
for(const kind of ["commit","tag","tree"]){
const canary="SESSION-"+({commit:"b",tag:"c",tree:"d"}[kind]).repeat(32),repo=await fakeRepo(),run=await prepareManual({repositoryRoot:repo,skipBuild:true}),author=join(run.root,"author"),scan=join(run.root,"commands/secret-scan.sh");
await execFileAsync("git",["clone",join(run.root,"remote.git"),join(run.root,"installation/registry/repo")]);
if(kind==="commit"){
await execFileAsync("git",["commit","--allow-empty","-m",canary],{cwd:author}); await execFileAsync("git",["reset","--hard","HEAD^"],{cwd:author});
}else if(kind==="tag"){
await execFileAsync("git",["tag","-a","temporary-canary-tag","-m",canary],{cwd:author}); await execFileAsync("git",["tag","-d","temporary-canary-tag"],{cwd:author});
}else{
await writeFile(join(author,canary),"safe tree payload\n"); await execFileAsync("git",["add",canary],{cwd:author}); await execFileAsync("git",["write-tree"],{cwd:author}); await execFileAsync("git",["reset","--hard","HEAD"],{cwd:author});
}
await assert.rejects(execFileAsync("bash",[scan],{cwd:repo}),error=>/Git object/.test(error.stderr)&&!error.stderr.includes(canary),`${kind} raw bytes must be scanned with a redacted finding`);
await rm(run.root,{recursive:true,force:true});
}
});
test("generated secret scan checks unreachable blobs and dangling commits without printing values", async () => {
for(const kind of ["unreachable-blob","dangling-commit"]){
const value=kind==="unreachable-blob"?"SECRET-"+"e".repeat(32):"SECRET-"+"f".repeat(32);
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}); const author=join(run.root,"author"),installed=join(run.root,"installation/registry/repo"),scan=join(run.root,"commands/secret-scan.sh");
await execFileAsync("git",["clone",join(run.root,"remote.git"),installed]); const file=join(author,"dangling-secret"); await writeFile(file,value);
if(kind==="unreachable-blob"){await execFileAsync("git",["hash-object","-w",file],{cwd:author}); await rm(file);}
else {await execFileAsync("git",["add","dangling-secret"],{cwd:author}); await execFileAsync("git",["commit","-m","dangling secret"],{cwd:author}); await execFileAsync("git",["reset","--hard","HEAD^"],{cwd:author});}
await assert.rejects(execFileAsync("bash",[scan],{cwd:repo}),error=>/Git blob/.test(error.stderr)&&!error.stderr.includes(value),`${kind} must be scanned`);
await rm(run.root,{recursive:true,force:true});
}
});
test("generated secret scan checks randomized and fixed canaries in reachable Git without printing values", async () => {
for(const canary of ["DWH-"+"c".repeat(32),"CANARY-MUST-BE-REJECTED"]){
const repo=await fakeRepo(); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}); const installed=join(run.root,"installation/registry/repo"),author=join(run.root,"author"),scan=join(run.root,"commands/secret-scan.sh");
await execFileAsync("git",["clone",join(run.root,"remote.git"),installed]);
await writeFile(join(author,"temporary-secret"),canary); await execFileAsync("git",["add","temporary-secret"],{cwd:author}); await execFileAsync("git",["commit","-m","temporary canary"],{cwd:author}); await execFileAsync("git",["rm","temporary-secret"],{cwd:author}); await execFileAsync("git",["commit","-m","remove canary"],{cwd:author});
await assert.rejects(execFileAsync("bash",[scan],{cwd:repo}),error=>/Git blob/.test(error.stderr)&&!error.stderr.includes(canary));
await rm(run.root,{recursive:true,force:true});
}
});
test("prepare publishes cleanable ownership before lab population", { concurrency: false }, async () => {
const repo=await fakeRepo(),realGit=(await execFileAsync("which",["git"])).stdout.trim(),bin=join(repo,"failing-bin");
await installFakeServer(repo); await mkdir(bin);
await writeFile(join(bin,"git"),`#!/bin/sh
if [ "$1" = init ]; then exit 71; fi
exec ${JSON.stringify(realGit)} "$@"
`,{mode:0o700});
const prior=process.env.PATH; process.env.PATH=`${bin}:${prior}`;
try { await assert.rejects(prepareManual({repositoryRoot:repo,skipBuild:true})); }
finally { process.env.PATH=prior; }
const owned=await readManualOwnership({repositoryRoot:repo});
assert.equal(owned.stage,"PREPARING");
await cleanupManual({repositoryRoot:repo});
await assert.rejects(lstat(fixedManualRoot(repo)));
});
test("stable repo-root lifecycle namespace survives manual-parent rename and cleans partial prepare", { concurrency: false }, async () => {
const repo=await fakeRepo(),realGit=(await execFileAsync("which",["git"])).stdout.trim();
const bin=join(repo,"rename-lock-bin"),entered=join(repo,"rename-entered"),release=join(repo,"rename-release");
await installFakeServer(repo); await mkdir(bin);
await writeFile(join(bin,"git"),`#!/bin/sh
if [ "$1" = init ] && [ ! -e ${JSON.stringify(entered)} ]; then
: > ${JSON.stringify(entered)}
while [ ! -e ${JSON.stringify(release)} ]; do sleep 0.01; done
fi
exec ${JSON.stringify(realGit)} "$@"
`,{mode:0o700});
const prior=process.env.PATH; process.env.PATH=`${bin}:${prior}`; let preparing;
const parent=join(repo,".artifacts/manual-acceptance"),moved=join(repo,".artifacts/manual-acceptance-moved");
try {
preparing=prepareManual({repositoryRoot:repo,skipBuild:true});
for(let n=0;n<300;n++){try{await lstat(entered);break;}catch{} await new Promise(r=>setTimeout(r,10));}
await lstat(entered); await rename(parent,moved); await mkdir(parent,{recursive:true}); await writeFile(join(parent,"public-sibling"),"keep"); await writeFile(join(moved,"moved-sibling"),"keep");
await assert.rejects(cleanupManual({repositoryRoot:repo}),/lifecycle lock|operator inspection/i);
await writeFile(release,"go"); await assert.rejects(preparing,/identity|changed|unsafe|manual/i); preparing=undefined;
assert.equal(await readFile(join(parent,"public-sibling"),"utf8"),"keep");
assert.equal(await readFile(join(moved,"moved-sibling"),"utf8"),"keep");
await assert.rejects(lstat(join(moved,"p1")));
await assert.rejects(lstat(join(repo,".p1-manual-acceptance.lifecycle.lock")));
} finally { process.env.PATH=prior; await writeFile(release,"go").catch(()=>{}); if(preparing)await preparing.catch(()=>{}); }
});
test("all four lifecycle operations serialize on the stable repo-root lock", async () => {
const repo=await fakeRepo(); await installFakeServer(repo); await prepareManual({repositoryRoot:repo,skipBuild:true});
const lock=join(repo,".p1-manual-acceptance.lifecycle.lock"); await writeFile(lock,"foreign",{mode:0o600});
try {
for(const operation of [prepareManual,serveManual,stopManual,cleanupManual])
await assert.rejects(operation({repositoryRoot:repo,skipBuild:true}),/lifecycle lock|operator inspection/i);
} finally { await rm(lock,{force:true}); }
});
test("prepare binds production entry bytes and serve rejects a regular replacement", { concurrency: false }, async () => {
const repo=await fakeRepo(),malicious=join(repo,"malicious-executed"); await installFakeServer(repo);
const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),owned=await readManualOwnership({repositoryRoot:repo}),script=join(repo,"backend/dist/server.js");
const prepared=await readFile(script); assert.equal(owned.entrypoint.sha256,sha256(prepared));
await rm(script); await writeFile(script,`import {writeFileSync} from "node:fs";writeFileSync(${JSON.stringify(malicious)},"bad");setInterval(()=>{},1000);`);
await assert.rejects(serveManual({repositoryRoot:repo}),/entrypoint|production server.*identity/i);
await assert.rejects(lstat(malicious)); await assert.rejects(lstat(join(run.root,"backend.pid")));
});
test("serve rejects replacement of an imported production dependency", { concurrency: false }, async () => {
const repo=await fakeRepo(),malicious=join(repo,"dependency-executed"); await installFakeServer(repo);
const server=join(repo,"backend/dist/server.js"), original=await readFile(server); await writeFile(join(repo,"backend/dist/dep.js"),"export const dependency = true;\n"); await writeFile(server,`import \"./dep.js\";\n${original}`);
const run=await prepareManual({repositoryRoot:repo,skipBuild:true}); const before=await readFile(server); await writeFile(join(repo,"backend/dist/dep.js"),`import {writeFileSync} from \"node:fs\"; writeFileSync(${JSON.stringify(malicious)},\"bad\");\n`);
assert.deepEqual(await readFile(server),before); await assert.rejects(serveManual({repositoryRoot:repo}),/distribution|identity|manifest/i); await assert.rejects(lstat(malicious)); await assert.rejects(lstat(join(run.root,"backend.pid")));
});
test("serve refuses a replaced backend dist dependency after prepare", { concurrency: false }, async () => {
const repo=await fakeRepo(); await installFakeServer(repo);
const dependency=join(repo,"backend/dist/dependency.js"); await writeFile(dependency,"export const value = 1;\n");
const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),marker=join(repo,"dependency-replaced-executed");
await writeFile(dependency,`import { writeFileSync } from "node:fs";writeFileSync(${JSON.stringify(marker)},"bad");export const value = 2;\n`);
await assert.rejects(serveManual({repositoryRoot:repo}),/distribution|manifest|identity/i);
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"),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|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 () => {
const repo=await fakeRepo(),entered=join(repo,"entry-loaded"); await installFakeServer(repo,{startupDelay:700,marker:entered});
const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),owned=await readManualOwnership({repositoryRoot:repo});
const serving=serveManual({repositoryRoot:repo});
for(let n=0;n<300;n++){try{await lstat(entered);break;}catch{} await new Promise(r=>setTimeout(r,5));}
await lstat(entered); const foreign=net.createServer((socket)=>socket.end("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\nforeign"));
await new Promise((resolvePromise,reject)=>foreign.once("error",reject).listen(8791,"127.0.0.1",resolvePromise));
try {
await assert.rejects(serving,/readiness|listener|entrypoint|backend failed/i);
await assert.rejects(lstat(join(run.root,"backend.pid")));
assert.equal((await listenerPids()).includes(process.pid),true);
assert.deepEqual(await matchingManualServerPids(run.root,owned.nonce),[]);
} finally { await new Promise(resolvePromise=>foreign.close(resolvePromise)); }
});
test("absence gate rejects evidence and every P2 materialization artifact name", async () => {
for(const rel of ["artifacts/evidence/generation/chunk.md","responses/materialization","responses/preprocess-state","responses/embedding-cache","responses/qdrant-state","responses/ACTIVE","responses/retention-policy"]){
const repo=await fakeRepo(); await installFakeServer(repo); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),check=join(run.root,"commands/absence-check.sh"),target=join(run.root,rel);
if(rel.endsWith("materialization"))await mkdir(target,{recursive:true}); else {await mkdir(dirname(target),{recursive:true}); await writeFile(target,"safe");}
await assert.rejects(execFileAsync("bash",[check],{cwd:repo}),/out-of-scope/i,rel);
await rm(run.root,{recursive:true,force:true});
}
});
test("secret scan discovers every arbitrary git repository including unreachable objects", async () => {
const repo=await fakeRepo(); await installFakeServer(repo); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),gitdir=join(run.root,"responses/.git"),scan=join(run.root,"commands/secret-scan.sh"),canary="SECRET-"+"9".repeat(32);
await execFileAsync("git",["init","--bare",gitdir]); const blob=join(run.root,"responses/canary-blob"); await writeFile(blob,canary); await execFileAsync("git",["--git-dir",gitdir,"hash-object","-w",blob]); await rm(blob);
await assert.rejects(execFileAsync("bash",[scan],{cwd:repo}),error=>/Git object|secret canary/.test(error.stderr)&&!error.stderr.includes(canary));
});
test("secret scan bounds and scans filesystem names plus loose ref names", async () => {
for(const kind of ["file","directory","loose-ref"]){
const repo=await fakeRepo(); await installFakeServer(repo); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),scan=join(run.root,"commands/secret-scan.sh"),canary="SESSION-"+"8".repeat(32);
if(kind==="file")await writeFile(join(run.root,"responses",canary),"safe");
if(kind==="directory")await mkdir(join(run.root,"responses",canary));
if(kind==="loose-ref"){const ref=join(run.root,"author/.git/refs/heads",canary);await mkdir(dirname(ref),{recursive:true});await writeFile(ref,"0".repeat(40)+"\n");}
await assert.rejects(execFileAsync("bash",[scan],{cwd:repo}),error=>/secret canary/.test(error.stderr)&&!error.stderr.includes(canary),kind);
await rm(run.root,{recursive:true,force:true});
}
});
test("extractor and scanner operational diagnostics redact canary-bearing paths", async () => {
const repo=await fakeRepo(); await installFakeServer(repo); const run=await prepareManual({repositoryRoot:repo,skipBuild:true}),canary="SECRET-"+"7".repeat(32),extract=join(run.root,"commands/extract-export.sh"),scan=join(run.root,"commands/secret-scan.sh");
const missing=join(run.root,"exports/raw",`${canary}.zip`),output=join(run.root,"exports/extracted",canary);
await assert.rejects(execFileAsync("bash",[extract,missing,output,"p1-filesystem"],{cwd:repo}),error=>!error.stderr.includes(canary)&&/redacted|refused|unsafe/i.test(error.stderr));
const oversized=join(run.root,"responses","oversized"); const handle=await open(oversized,"w"); await handle.truncate(33554433); await handle.close();
await assert.rejects(execFileAsync("bash",[scan],{cwd:repo}),error=>!error.stderr.includes(canary)&&/redacted|failed|bound/i.test(error.stderr));
});
test("public prepare build is inside the stable lifecycle transaction", async()=>{
const wrapper=await readFile(new URL("../../scripts/p1-manual-acceptance.sh",import.meta.url),"utf8"),source=await readFile(new URL("./p1-manual-acceptance.mjs",import.meta.url),"utf8");
assert.doesNotMatch(wrapper,/npm .*run build/); assert.match(source,/action==="prepare"\)await prepareManual\(\)/);
});