import assert from 'node:assert/strict'; import { readFileSync, writeFileSync, symlinkSync, rmSync, existsSync } from 'node:fs'; import path from 'node:path'; import test from 'node:test'; import { spawnSync } from 'node:child_process'; import { fixture } from './fixtures/release-gate-fixture.mjs'; const entries=['ci-release','all','deploy','bootstrap','existing','raw']; const syntheticEnv={ DEPLOY_SERVER:'fixture-target',DEPLOY_REFRESH_SERVER:'fixture-refresh', REMOTE_DIR:'/fixture/app',POSTGRES_DATA_DIR:'/fixture/db',STORAGE_HOST_DIR:'/fixture/storage', COMPOSE_PROJECT_NAME:'fixture-project',DEPLOY_DATA_MODE:'existing', EXPECTED_PRODUCTION_ORIGIN:'https://fixture.invalid',EXPECTED_PRODUCTION_DB_NAME_SHA256:'a'.repeat(64), EXPECTED_PENDING_MIGRATIONS:'',EXPECTED_DEPLOY_SERVER:'fixture-target',EXPECTED_REMOTE_DIR:'/fixture/app', EXPECTED_COMPOSE_PROJECT_NAME:'fixture-project', }; const output=r=>r.stdout+r.stderr; const named=(r,name,suffix)=>r.commands.filter(c=>c.name===name&&(!suffix||c.args[0]?.endsWith(suffix))); const writes=r=>r.commands.filter(c=>c.name==='rsync'||c.name==='ssh'&&(/mkdir -p|BUILD_SHA=|^refresh$/.test(c.args.at(-1)))); function blockedBeforeAccess(r) { assert.notEqual(r.status,0,output(r)); assert.equal(writes(r).length,0); assert.equal(named(r,'ssh').length,0); assert.equal(named(r,'config-read').length,0); assert.equal(named(r,'node','check-source-provenance.mjs').length,0); } function complete(f) { const r=f.run();assert.equal(r.status,0,output(r)); f.env.RELEASE_GATE_RECEIPT_DIR=f.env.RELEASE_GATE_ARTIFACT_DIR; return r; } function replace(f,relative,from,to) { const file=path.join(f.root,relative),source=readFileSync(file,'utf8'); assert.equal(source.split(from).length,2,'mutation must hit exactly once'); writeFileSync(file,source.replace(from,to));f.commit(); } for(const entry of entries)test(`${entry}: explicit bad receipts cannot reach config, provenance or remote actions`,context=>{ const f=fixture(context,syntheticEnv);complete(f); const file=path.join(f.env.RELEASE_GATE_RECEIPT_DIR,'release-result.json'),original=readFileSync(file,'utf8'); const mutations=[ record=>{record.profile='focused';}, record=>{record.sourceBefore.commit='f'.repeat(40);}, record=>{record.executionExit=130;record.status='PASS';record.deploymentEligible=true;}, record=>{record.phases.stages.pop();}, record=>{record.policy.toolchain.node='stale';}, ]; for(const mutate of mutations) { const record=JSON.parse(original);mutate(record);writeFileSync(file,JSON.stringify(record)); blockedBeforeAccess(f.invoke(entry)); } writeFileSync(file,original); blockedBeforeAccess(f.invoke(entry,{RELEASE_GATE_RECEIPT_DIR:''})); blockedBeforeAccess(f.invoke(entry,{RELEASE_GATE_RECEIPT_DIR:path.join(f.root,'missing')})); writeFileSync(file,'{');blockedBeforeAccess(f.invoke(entry));writeFileSync(file,original); writeFileSync(path.join(f.root,'client/package.json'),'{"changed":true}'); blockedBeforeAccess(f.invoke(entry));writeFileSync(path.join(f.root,'client/package.json'),'{}'); for(const value of ['yes','01','']) { blockedBeforeAccess(f.invoke(entry,{PRODUCTION_READ_ONLY_PREFLIGHT:value})); blockedBeforeAccess(f.invoke(entry,{PRODUCTION_IDENTITY_ONLY:value,PRODUCTION_READ_ONLY_PREFLIGHT:'1'})); } }); for(const entry of ['deploy','bootstrap','existing','raw'])test(`${entry}: missing receipt refuses without starting tests`,context=>{ const f=fixture(context,syntheticEnv),r=f.invoke(entry); blockedBeforeAccess(r);assert.equal(named(r,'npm').length,0); }); for(const entry of entries)test(`${entry}: valid explicit receipt reaches exactly one synthetic deployment`,context=>{ const f=fixture(context,syntheticEnv);complete(f); const r=f.invoke(entry);assert.equal(r.status,0,output(r)); assert.equal(named(r,'rsync').length,1); assert.equal(named(r,'npm').length,0); assert.equal(named(r,'bash','run-web-gates.sh').filter(c=>c.args[1]==='full-local').length,0); assert.equal(r.commands.filter(c=>c.name==='ssh'&&c.args.at(-1).includes('BUILD_SHA=')).length,1); const firstWrite=r.commands.findIndex(c=>writes({commands:[c]}).length); const checks=r.commands.slice(0,firstWrite).filter(c=>c.name==='node'&&c.args[0]?.endsWith('release-gate-result.mjs')&&c.args[1]==='require'); assert.ok(checks.length>=3,'raw deployment must recheck receipt before every write boundary'); }); for(const entry of ['ci-release','all'])test(`${entry}: no explicit receipt runs static/full-local once with no recursive deployment`,context=>{ const f=fixture(context,syntheticEnv),r=f.invoke(entry);assert.equal(r.status,0,output(r)); assert.equal(named(r,'bash','run-release-gate.sh').length,1); assert.equal(named(r,'bash','run-web-gates.sh').filter(c=>c.args[1]==='full-local').length,1); assert.equal(named(r,'npm').filter(c=>c.args[0]==='test').length,1); assert.equal(named(r,'node','production-identity-bootstrap.mjs').length,1); assert.equal(named(r,'rsync').length,1); const web=named(r,'bash','run-web-gates.sh').map(c=>c.args[1]); assert.deepEqual(web,entry==='all'?['smoke-local','full-local']:['full-local']); }); for(const entry of ['ci-release','all'])test(`${entry}: failed verification never enters production chain`,context=>{ const f=fixture(context,{...syntheticEnv,FAIL_STATIC:'1'}),r=f.invoke(entry); blockedBeforeAccess(r);assert.equal(named(r,'node','production-identity-bootstrap.mjs').length,0); assert.equal(named(r,'bash','run-release-gate.sh').length,1); }); for(const [entry,flag] of [['bootstrap','PRODUCTION_IDENTITY_ONLY'],['bootstrap','PRODUCTION_READ_ONLY_PREFLIGHT'],['existing','PRODUCTION_READ_ONLY_PREFLIGHT']])test(`${entry}/${flag}: synthetic read-only route terminates without receipt or writes`,context=>{ const f=fixture(context,syntheticEnv),r=f.invoke(entry,{[flag]:'1'}); assert.equal(r.status,0,output(r));assert.equal(writes(r).length,0); assert.equal(named(r,'bash','deploy.sh').length,0); if(flag==='PRODUCTION_IDENTITY_ONLY') { assert.equal(named(r,'bash','deploy-existing.sh').length,0); assert.ok(!named(r,'ssh').some(c=>c.args.at(-1).includes("IDENTITY_BOOTSTRAP_MODE='database'"))); } }); for(const entry of ['ci-release','all','deploy','raw'])test(`${entry}: read-only flags cannot masquerade as successful publication`,context=>{ const f=fixture(context,syntheticEnv); for(const flag of ['PRODUCTION_IDENTITY_ONLY','PRODUCTION_READ_ONLY_PREFLIGHT'])blockedBeforeAccess(f.invoke(entry,{[flag]:'1'})); }); for(const [entry,point] of [['bootstrap','origin'],['existing','preflight'],['raw','remote-preflight']])test(`${entry}: source or receipt changed after initial check cannot write`,context=>{ const f=fixture(context,syntheticEnv);complete(f); const r=f.invoke(entry,{HYB_MUTATE_AT:point}); assert.notEqual(r.status,0,output(r));assert.equal(writes(r).length,0); assert.equal(named(r,'bash','deploy.sh').length,0); }); for(const kind of ['head','index','receipt'])test(`raw: ${kind} drift during remote preflight fails final recheck`,context=>{ const f=fixture(context,syntheticEnv);complete(f); const r=f.invoke('raw',{HYB_MUTATE_AT:'remote-preflight',HYB_MUTATE_KIND:kind}); assert.notEqual(r.status,0,output(r));assert.equal(writes(r).length,0); }); test('raw: provenance commit must equal receipt/HEAD before archive or environment reads',context=>{ const f=fixture(context,syntheticEnv);complete(f); const r=f.invoke('raw',{HYB_WRONG_SOURCE:'1'}); assert.notEqual(r.status,0,output(r));assert.equal(writes(r).length,0); assert.equal(named(r,'node','validate-env-contract.js').length,0); }); test('caller expected commit is an additional constraint, never an override',context=>{ const f=fixture(context,syntheticEnv);complete(f); blockedBeforeAccess(f.invoke('bootstrap',{RELEASE_GATE_EXPECTED_COMMIT:'f'.repeat(40)})); blockedBeforeAccess(f.invoke('raw',{RELEASE_GATE_EXPECTED_COMMIT:''})); }); test('skip/internal flags never authorize a lower-level write',context=>{ const f=fixture(context,syntheticEnv);complete(f); for(const entry of entries)blockedBeforeAccess(f.invoke(entry,{PROJECT_WIDE_SKIP_VISUAL:'1',PROJECT_WIDE_SKIP_REASON:'synthetic',PROJECT_WIDE_SKIP_OPERATOR:'fixture',PROJECT_WIDE_SKIP_APPROVAL_REF:'fixture'})); delete f.env.RELEASE_GATE_RECEIPT_DIR; for(const entry of ['bootstrap','existing','raw'])blockedBeforeAccess(f.invoke(entry,{GATE_PASSED:'1',SKIP_RELEASE_GATE:'1',DEPLOY_DEFER_FINAL_SUCCESS:'1'})); }); test('receipt directory or record symlinks and outside paths are refused',context=>{ const f=fixture(context,syntheticEnv);complete(f); const link=path.join(f.root,'artifacts/release-gate/linked'); symlinkSync(f.env.RELEASE_GATE_RECEIPT_DIR,link); blockedBeforeAccess(f.invoke('raw',{RELEASE_GATE_RECEIPT_DIR:link})); blockedBeforeAccess(f.invoke('raw',{RELEASE_GATE_RECEIPT_DIR:f.root})); const file=path.join(f.env.RELEASE_GATE_RECEIPT_DIR,'release-result.json'); rmSync(file);symlinkSync('/synthetic-missing-target',file); blockedBeforeAccess(f.invoke('raw')); }); test('removing bootstrap first check is caught by config-access assertion',context=>{ const f=fixture(context,syntheticEnv);blockedBeforeAccess(f.invoke('bootstrap')); replace(f,'deploy/trialrun/production-identity-bootstrap.mjs', 'const release = identityOnly === "1" || preflightOnly ? null : requireReleaseReceipt();', 'const release = null; // isolated mutation'); assert.throws(()=>blockedBeforeAccess(f.invoke('bootstrap')),assert.AssertionError); }); test('removing final raw check makes the no-write counterexample fail',context=>{ const f=fixture(context,syntheticEnv); replace(f,'deploy/trialrun/deploy.sh', 'node "$ROOT_DIR/scripts/qa/release-gate-result.mjs" require "${RELEASE_GATE_RECEIPT_DIR:-}" "$SOURCE_COMMIT" >/dev/null\n\necho ">>> 3.1', ': # isolated mutation\n\necho ">>> 3.1'); complete(f);const r=f.invoke('raw',{HYB_MUTATE_AT:'remote-preflight'}); assert.throws(()=>assert.equal(writes(r).length,0),assert.AssertionError); }); test('removing existing-wrapper recheck is caught before lower-level invocation',context=>{ const f=fixture(context,syntheticEnv); replace(f,'deploy/trialrun/deploy-existing.sh', 'node "$ROOT_DIR/scripts/qa/release-gate-result.mjs" require "${RELEASE_GATE_RECEIPT_DIR:-}" "$source_commit" >/dev/null', ': # isolated mutation'); complete(f);const r=f.invoke('existing',{HYB_MUTATE_AT:'preflight'}); assert.equal(writes(r).length,0); // Raw entry still independently protects writes. assert.throws(()=>assert.equal(named(r,'bash','deploy.sh').length,0),assert.AssertionError); }); test('relaxing expected commit binding is caught before environment/archive',context=>{ const f=fixture(context,syntheticEnv); replace(f,'scripts/qa/release-gate-result.mjs', "expected!==undefined && (!/^[a-f0-9]{40}$/.test(expected) || expected!==current.source.commit)", 'false'); complete(f);const r=f.invoke('raw',{HYB_WRONG_SOURCE:'1'}); assert.throws(()=>assert.equal(named(r,'node','validate-env-contract.js').length,0),assert.AssertionError); }); test('removing bootstrap second check is caught before wrapper invocation',context=>{ const f=fixture(context,syntheticEnv); replace(f,'deploy/trialrun/production-identity-bootstrap.mjs', 'if (release) requireReleaseReceipt(release.directory, release.commit);', '// isolated mutation'); complete(f);const r=f.invoke('bootstrap',{HYB_MUTATE_AT:'origin'}); assert.equal(writes(r).length,0); assert.throws(()=>assert.equal(named(r,'bash','deploy-existing.sh').length,0),assert.AssertionError); }); test('relaxing clean-candidate validation makes the dirty receipt counterexample fail',context=>{ const f=fixture(context,syntheticEnv); replace(f,'scripts/qa/release-gate-result.mjs','source.dirty===false','true'); writeFileSync(path.join(f.root,'client/package.json'),'{"dirty":true}'); const r=f.run(); // Deliberate verifier mutation admits a consistently dirty fixture. The // ordinary shell suite independently requires PARTIAL/2 for this same case. assert.throws(()=>assert.equal(r.status,2,output(r)),assert.AssertionError); assert.equal(r.status,0,output(r)); }); test('private fixture rejects unknown tools and never falls back to real SSH/Docker',context=>{ const f=fixture(context,syntheticEnv); assert.equal(existsSync(path.join(f.root,'bin/docker')),true); assert.equal(f.env.PATH,path.join(f.root,'bin')); assert.equal(f.env.HOME,path.join(f.root,'bin/home')); for(const command of ['ssh','docker','git']) { const r=spawnSync(path.join(f.root,'bin',command),['unexpected'],{env:f.env,cwd:f.root,encoding:'utf8'}); assert.equal(r.status,97,r.stdout+r.stderr); } });