Files
ThothII/backend/scripts/p1-manual-acceptance.test.mjs
T

783 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: 4
id: p1-filesystem
name: P1 filesystem
language: en
dwh:
engine: postgres
database: postgres
schema: public
supported_transports: [postgres_direct]
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 revision={id:"p1-filesystem",commit,blob,snapshotPath};
const manifest=(entry=revision)=>({head:commit,revisions:[entry],files:{"p1-filesystem.yaml":snapshotSha}});
await writeFile(readPath,JSON.stringify({revision})); 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));
const legacyRevision={...revision}; legacyRevision[["st","ate"].join("")]=["oper","ational"].join("");
await writeFile(join(commitDir,"snapshot.json"),JSON.stringify(manifest(legacyRevision)));
await assert.rejects(execFileAsync("bash",[script],{cwd:repo}),/snapshot manifest revision is invalid/);
await writeFile(join(commitDir,"snapshot.json"),JSON.stringify(manifest({...revision,unexpected:"field"})));
await assert.rejects(execFileAsync("bash",[script],{cwd:repo}),/snapshot manifest revision is invalid/);
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));
for(const malformed of [
{id:"p1-filesystem",commit,blob},
{...revision,id:"p1-http"},
{...revision,commit:"c".repeat(40)},
{...revision,blob:"f".repeat(39)},
{...revision,blob:[blob]},
{...revision,snapshotPath:join(commitDir,"wrong.yaml")},
]){
await writeFile(join(commitDir,"snapshot.json"),JSON.stringify(manifest(malformed)));
await assert.rejects(execFileAsync("bash",[script2],{cwd:repo}),/snapshot manifest revision is invalid/);
}
await writeFile(join(commitDir,"snapshot.json"),JSON.stringify(manifest({...revision,blob:"f".repeat(40)})));
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:{...revision,blob:"f".repeat(40)}}));
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\(\)/);
});