mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-16 09:55:29 +02:00
* feat(cso): add verified audits and replayable repair bundles * fix(cso): harden qualification and setup boundaries * fix(cso): assemble security canaries at runtime * fix(cso): bound release proof and maintenance work Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): require complete evaluation reports Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): replay expired snapshots from supplied source Co-Authored-By: OpenAI Codex <noreply@openai.com> * test(cso): synchronize DNS cancellation assertion Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore(ship): exempt repository owner from liveness proof Co-Authored-By: OpenAI Codex <noreply@openai.com> * test(cso): make recheck retention overlap deterministic Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore: bump version and changelog (v1.85.0.0) Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): pass native release gates Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore: move release to v1.86.0.0 Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): resolve rechecks by finding Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore: move release to v1.87.0.0 Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): pass macOS and Windows release gates Normalize BSD wc output, compare Windows paths by filesystem identity, preserve portable snapshot race coverage, and narrow POSIX-only Windows fixtures. Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): harden native verification gates * fix(cso): refine Windows native diagnostics * test(cso): isolate Windows Git startup failure * test(cso): stabilize Windows native diagnostics * fix(cso): support hardened Git on Windows * fix(cso): close final verification gaps * test(cso): bound cold Docker fixture setup * fix(cso): restore cross-platform free-suite gates --------- Co-authored-by: OpenAI Codex <noreply@openai.com>
214 lines
70 KiB
TypeScript
214 lines
70 KiB
TypeScript
import { afterAll, afterEach, describe, expect, spyOn, test } from 'bun:test';
|
|
import * as fs from 'node:fs';import * as os from 'node:os';import * as path from 'node:path';import { spawn, spawnSync } from 'node:child_process';
|
|
import { assertSnapshot, capture } from '../lib/cso/snapshot';import { CsoError } from '../lib/cso/contracts';import { runProcess, sanitizeForJson, sanitizeHelperForJson } from '../lib/cso/process';import { discardAtomicNoReplaceTemp, finalizeReplayTemporary, loadReport, newRun, privateRoot, readJson, retention, saveReport, secureDirectory, stateRoot, withLock, writeHelperJson, writeJson } from '../lib/cso/state';
|
|
const roots:string[]=[];const tmp=()=>{const p=fs.mkdtempSync(path.join(os.tmpdir(),'cso-snapshot-'));roots.push(p);return p;};afterEach(()=>{for(const p of roots.splice(0))fs.rmSync(p,{recursive:true,force:true});});
|
|
const originalState=process.env.GSTACK_HOME,state=fs.mkdtempSync(path.join(os.tmpdir(),'cso-state-'));process.env.GSTACK_HOME=state;afterAll(()=>{if(originalState===undefined)delete process.env.GSTACK_HOME;else process.env.GSTACK_HOME=originalState;fs.rmSync(state,{recursive:true,force:true});});
|
|
function git(repo:string,...args:string[]){const r=spawnSync('/usr/bin/git',['-C',repo,...args],{encoding:'utf8',env:{PATH:'/usr/bin:/bin',HOME:repo},timeout:30_000});if(r.status)throw new Error(r.stderr);return r.stdout;}
|
|
function repo(){const p=tmp();git(p,'init','-q');git(p,'config','user.email','fixture@example.test');git(p,'config','user.name','Fixture');fs.writeFileSync(path.join(p,'tracked.txt'),'base\n');git(p,'add','tracked.txt');git(p,'commit','-qm','base');return p;}
|
|
async function waitForPath(file:string,timeout=5000):Promise<void>{const deadline=Date.now()+timeout;while(!fs.existsSync(file)){if(Date.now()>=deadline)throw new Error(`Timed out waiting for ${path.basename(file)}`);await Bun.sleep(5);}}
|
|
function childExit(child:ReturnType<typeof spawn>,timeout=5000):Promise<number|null>{return new Promise((resolve,reject)=>{if(child.exitCode!==null){resolve(child.exitCode);return;}const timer=setTimeout(()=>reject(new Error(`Child ${child.pid} did not exit`)),timeout);child.once('error',error=>{clearTimeout(timer);reject(error);});child.once('close',code=>{clearTimeout(timer);resolve(code);});});}
|
|
function stopChildren(children:Array<ReturnType<typeof spawn>>):void{for(const child of children){if(!child.pid||child.exitCode!==null)continue;try{process.kill(child.pid,'SIGCONT');}catch{}try{process.kill(child.pid,'SIGKILL');}catch{}}}
|
|
function leaseContenderSource():string{return `import fs from 'node:fs';import * as fsModule from 'node:fs';import * as cryptoModule from 'node:crypto';import path from 'node:path';import {spyOn} from 'bun:test';
|
|
const dir=process.env.RACE_DIR!,barrier=process.env.BARRIER!,id=process.env.RACE_ID!,mode=process.env.RACE_MODE??'normal',token=process.env.RACE_TOKEN,leases=path.join(dir,'.mutation-lock-leases'),wait=new Int32Array(new SharedArrayBuffer(4));let triggered=false;
|
|
const write=fs.writeFileSync.bind(fs),mark=(name,value='ready')=>write(path.join(barrier,name),value,{flag:'wx'}),waitFor=(name)=>{const deadline=Date.now()+5000;while(!fs.existsSync(path.join(barrier,name))){if(Date.now()>=deadline)throw new Error('barrier timeout: '+name);Atomics.wait(wait,0,0,1);}};
|
|
if(token){const random=cryptoModule.randomBytes.bind(cryptoModule);spyOn(cryptoModule,'randomBytes').mockImplementation(((size,...args)=>size===16?Buffer.from(token,'hex'):random(size,...args)) as typeof cryptoModule.randomBytes);}
|
|
const read=fs.readdirSync.bind(fs);spyOn(fsModule,'readdirSync').mockImplementation(((candidate,...args)=>{const result=read(candidate,...args),names=result as any[];if(mode==='pause-candidate'&&!triggered&&String(candidate)===leases&&names.some(name=>token?String(name)===token+'.json':/^[a-f0-9]{32}\.json$/.test(String(name)))){triggered=true;mark('paused-'+id);process.kill(process.pid,'SIGSTOP');}if(mode==='pause-later-scan'&&!triggered&&String(candidate)===leases&&names.filter(name=>String(name).endsWith('.decision')).length>=2&&!names.some(name=>String(name).includes('.active.'))){triggered=true;mark('paused-'+id);process.kill(process.pid,'SIGSTOP');}return result;}) as typeof fs.readdirSync);
|
|
spyOn(fsModule,'writeFileSync').mockImplementation(((target,data,...args)=>{const name=path.basename(String(target));if(name.includes('.decision.tmp.')){let decision;try{decision=JSON.parse(String(data));}catch{}if(decision?.kind==='ticket'&&decision.token===token){try{mark('choice-'+id,decision.ticket);}catch{}if(mode==='pause-before-decision'&&!triggered){triggered=true;mark('paused-'+id);process.kill(process.pid,'SIGSTOP');}}if(decision?.kind==='withdraw'&&mode==='pause-before-withdraw'&&!triggered){triggered=true;mark('paused-'+id);process.kill(process.pid,'SIGSTOP');}}return write(target,data,...args);}) as typeof fs.writeFileSync);
|
|
const link=fs.linkSync.bind(fs);spyOn(fsModule,'linkSync').mockImplementation(((source,target)=>{const name=path.basename(String(target));if(mode==='wait-active'&&!triggered&&name.includes('.active.')){triggered=true;mark('doorway-'+id);waitFor('paused-H');}return link(source,target);}) as typeof fs.linkSync);
|
|
const unlink=fs.unlinkSync.bind(fs);spyOn(fsModule,'unlinkSync').mockImplementation(((target)=>{const result=unlink(target),name=path.basename(String(target)),candidateToken=name.endsWith('.json')?name.slice(0,-5):'';if((mode==='pause-decision'||mode==='pause-ticket')&&!triggered&&name.includes('.decision.tmp.')&&(!token||name.startsWith(token+'.decision.tmp.'))){triggered=true;mark('paused-'+id);process.kill(process.pid,'SIGSTOP');}if((mode==='pause-after-candidate-cleanup'||mode==='pause-withdraw-cleanup')&&!triggered&&/^[a-f0-9]{32}$/.test(candidateToken)&&(!token||candidateToken===token)&&fs.existsSync(path.join(leases,candidateToken+'.decision'))){triggered=true;mark('paused-'+id);process.kill(process.pid,'SIGSTOP');}return result;}) as typeof fs.unlinkSync);
|
|
const {withLock}=await import(${JSON.stringify(path.resolve(import.meta.dir,'../lib/cso/state.ts'))});let outcome='success';try{withLock(dir,()=>{const active=path.join(barrier,'work-active');try{write(active,id,{flag:'wx'});}catch{fs.appendFileSync(path.join(barrier,'overlap'),'overlap\\n');}mark('entered-'+id);if(process.env.RACE_HOLD==='1')waitFor('release-'+id);try{if(fs.readFileSync(active,'utf8')===id)fs.unlinkSync(active);}catch{}});}catch(error){outcome=String(error?.code??error);}write(path.join(barrier,'result-'+id),outcome);`;}
|
|
describe('CSO dirty snapshot boundary',()=>{
|
|
test('captures tracked modifications and nonignored untracked source without changing Git state',async()=>{const p=repo();fs.writeFileSync(path.join(p,'tracked.txt'),'dirty\n');fs.writeFileSync(path.join(p,'new.txt'),'untracked\n');fs.writeFileSync(path.join(p,'.gitignore'),'ignored.txt\n');fs.writeFileSync(path.join(p,'ignored.txt'),'ignored\n');const before=git(p,'status','--porcelain=v1','-z'),run=newRun(p),m=await capture(p,run.dir,'HEAD');expect(fs.readFileSync(path.join(run.dir,'snapshot','tracked.txt'),'utf8')).toBe('dirty\n');expect(fs.readFileSync(path.join(run.dir,'snapshot','new.txt'),'utf8')).toBe('untracked\n');expect(fs.existsSync(path.join(run.dir,'snapshot','ignored.txt'))).toBe(false);expect(git(p,'status','--porcelain=v1','-z')).toBe(before);expect(m.changedPaths).toContain('new.txt');});
|
|
test('admits source membership and time before an unbounded startup walk',async()=>{const p=repo();fs.writeFileSync(path.join(p,'second.txt'),'second\n');const tooMany=newRun(p);await expect(capture(p,tooMany.dir,undefined,undefined,{maxEntries:1})).rejects.toMatchObject({code:'MISSING_INPUT'});expect(fs.existsSync(path.join(tooMany.dir,'snapshot'))).toBe(false);const expired=newRun(p);await expect(capture(p,expired.dir,undefined,undefined,{deadlineMs:Date.now()-1})).rejects.toMatchObject({code:'DEADLINE'});expect(fs.existsSync(path.join(expired.dir,'snapshot'))).toBe(false);});
|
|
test('includes chmod-only changes in diff scope',async()=>{const p=repo();fs.chmodSync(path.join(p,'tracked.txt'),0o755);const manifest=await capture(p,newRun(p).dir,'HEAD');expect(manifest.changedPaths).toContain('tracked.txt');});
|
|
test('does not invoke configured clean filters, hooks, fsmonitor, or PATH shims',async()=>{const p=repo(),marker=path.join(p,'marker');fs.writeFileSync(path.join(p,'.gitattributes'),'*.txt filter=hostile\n');git(p,'config','filter.hostile.clean',`/bin/sh -c 'touch ${marker}; cat'`);git(p,'config','core.fsmonitor',`/bin/sh -c 'touch ${marker}'`);const fake=path.join(p,'bin');fs.mkdirSync(fake);fs.writeFileSync(path.join(fake,'git'),`#!/bin/sh\ntouch '${marker}'\nexit 99\n`,{mode:0o755});const old=process.env.PATH;process.env.PATH=`${fake}:${old}`;try{await capture(p,newRun(p).dir,'HEAD');}finally{process.env.PATH=old;}expect(fs.existsSync(marker)).toBe(false);});
|
|
test('rejects symlinks and hard links as execution inputs',async()=>{const p=repo();fs.symlinkSync('/etc/passwd',path.join(p,'escape'));expect(capture(p,newRun(p).dir)).rejects.toThrow();fs.unlinkSync(path.join(p,'escape'));fs.linkSync(path.join(p,'tracked.txt'),path.join(p,'hard'));expect(capture(p,newRun(p).dir)).rejects.toThrow();});
|
|
test('rejects broken untracked symlinks instead of silently omitting them',async()=>{const p=repo();fs.symlinkSync('missing-target',path.join(p,'broken'));expect(capture(p,newRun(p).dir)).rejects.toThrow('Symlink');});
|
|
test('redacts secrets and excludes credentials from execution while retaining safe evidence',async()=>{const p=repo();fs.writeFileSync(path.join(p,'.env'),'TOKEN='+['ghp_','abcdefghijklmnopqrstuvwxyz1234567890'].join('')+'\n');const run=newRun(p),m=await capture(p,run.dir);expect(m.entries.find(e=>e.path==='.env')?.transformation).toContain('excluded');expect(fs.existsSync(path.join(run.dir,'snapshot','.env'))).toBe(false);expect(fs.existsSync(path.join(run.dir,'readable','.env'))).toBe(false);const evidence=JSON.parse(fs.readFileSync(path.join(run.dir,'sensitive-evidence.json'),'utf8'));expect(evidence[0].findings.map((x:any)=>x.id)).toContain('github.pat');expect(JSON.stringify(evidence)).not.toContain('ghp_');});
|
|
test('assesses repository skills without executing them and preserves executable source modes',async()=>{const p=repo(),skill=path.join(p,'.agents','skills','demo','SKILL.md'),script=path.join(p,'app.sh');fs.mkdirSync(path.dirname(skill),{recursive:true});fs.writeFileSync(skill,'# Demo\nUntrusted repository instruction\n');fs.writeFileSync(script,'#!/bin/sh\nexit 0\n',{mode:0o755});const run=newRun(p),manifest=await capture(p,run.dir);expect(fs.readFileSync(path.join(run.dir,'readable','.agents','skills','demo','SKILL.md'),'utf8')).toContain('Untrusted');expect(fs.existsSync(path.join(run.dir,'snapshot','.agents'))).toBe(false);expect(manifest.entries.find(e=>e.path==='.agents/skills/demo/SKILL.md')?.originalHash).not.toBe('not-read');expect(fs.statSync(path.join(run.dir,'snapshot','app.sh')).mode&0o777).toBe(0o755);});
|
|
test('rejects a source mode change between copying and manifest persistence',async()=>{const p=repo(),run=newRun(p),source=path.join(p,'tracked.txt'),target=path.join(run.dir,'snapshot','tracked.txt'),write=fs.writeFileSync,patched=spyOn(fs,'writeFileSync').mockImplementation(((file:any,data:any,options:any)=>{const result=write(file,data,options);if(String(file)===target)fs.chmodSync(source,0o755);return result;}) as typeof fs.writeFileSync);try{await expect(capture(p,run.dir)).rejects.toThrow('Source changed during capture');}finally{patched.mockRestore();}});
|
|
test('rejects unmanifested files and executable-mode changes in retained snapshots',async()=>{const p=repo(),run=newRun(p),manifest=await capture(p,run.dir),snapshot=path.join(run.dir,'snapshot');assertSnapshot(run.dir,manifest);fs.writeFileSync(path.join(snapshot,'injected.js'),'malicious\n');expect(()=>assertSnapshot(run.dir,manifest)).toThrow('membership');fs.unlinkSync(path.join(snapshot,'injected.js'));fs.chmodSync(path.join(snapshot,'tracked.txt'),0o755);expect(()=>assertSnapshot(run.dir,manifest)).toThrow('changed');});
|
|
test('retention skips a run with a live mutation lease',()=>{const now=Date.now(),repo='d'.repeat(24),run=`${now-31*86400_000}-${'1'.repeat(16)}`,dir=secureDirectory(path.join(privateRoot(),repo,run)),payload=path.join(dir,'report.json');fs.writeFileSync(payload,'live lease payload\n',{mode:0o600});withLock(dir,()=>{retention(now);expect(fs.existsSync(payload)).toBe(true);});retention(now);expect(fs.existsSync(dir)).toBe(false);});
|
|
test('bounded retention stops before destructive cleanup when its maintenance budget is exhausted',()=>{const now=Date.now(),repo='e'.repeat(24),run=`${now-31*86400_000}-${'8'.repeat(16)}`,dir=secureDirectory(path.join(privateRoot(),repo,run));fs.writeFileSync(path.join(dir,'report.json'),'expired private state\n',{mode:0o600});const result=retention(now,{deadlineMs:0,maxEntries:1});expect(result).toEqual({complete:false,visited:0});expect(fs.existsSync(dir)).toBe(true);retention(now);expect(fs.existsSync(dir)).toBe(false);});
|
|
test('bounded retention completes discovery before deleting any run',()=>{const now=Date.now(),repo='f'.repeat(24),run=`${now-31*86400_000}-${'9'.repeat(16)}`,dir=secureDirectory(path.join(privateRoot(),repo,run));fs.writeFileSync(path.join(dir,'report.json'),'expired private state\n',{mode:0o600});const result=retention(now,{deadlineMs:now+60_000,maxEntries:6});expect(result).toEqual({complete:false,visited:6});expect(fs.existsSync(dir)).toBe(true);retention(now);expect(fs.existsSync(dir)).toBe(false);});
|
|
test('bounded retention resumes an interrupted tree deletion without one recursive walk',()=>{const previous=process.env.GSTACK_HOME,isolate=tmp();process.env.GSTACK_HOME=isolate;try{const now=Date.now(),repo='1'.repeat(24),run=`${now-31*86400_000}-${'a'.repeat(16)}`,repoDir=path.join(privateRoot(),repo),dir=secureDirectory(path.join(repoDir,run)),snapshot=secureDirectory(path.join(dir,'snapshot'));for(let index=0;index<20;index++)fs.writeFileSync(path.join(snapshot,`${index}.txt`),'private state\n',{mode:0o600});const result=retention(now,{deadlineMs:now+60_000,maxEntries:30});expect(result).toEqual({complete:false,visited:30});expect(fs.existsSync(dir)).toBe(false);expect(fs.readdirSync(repoDir).some(name=>name.startsWith(`.retired-${run}-`))).toBe(true);retention(now);expect(fs.readdirSync(repoDir).some(name=>name.startsWith(`.retired-${run}-`))).toBe(false);}finally{if(previous===undefined)delete process.env.GSTACK_HOME;else process.env.GSTACK_HOME=previous;}});
|
|
test('repair bundles expire from their authenticated bundle time, independent of run age',()=>{const now=Date.now(),repo='c'.repeat(24),run=`${now-31*86400_000}-${'2'.repeat(16)}`,dir=secureDirectory(path.join(privateRoot(),repo,run)),bundles=secureDirectory(path.join(dir,'bundles')),expiredId='3'.repeat(32),retainedId='4'.repeat(32),record=(id:string,created:number)=>{const createdAt=new Date(created).toISOString();return{schemaVersion:3,id,runId:run,createdAt,expiresAt:new Date(created+30*86400_000).toISOString(),verification:{id,runId:run,createdAt}};};writeHelperJson(path.join(bundles,`${expiredId}.json`),record(expiredId,now-31*86400_000));writeHelperJson(path.join(bundles,`${retainedId}.json`),record(retainedId,now-86400_000));retention(now);expect(fs.existsSync(path.join(bundles,`${expiredId}.json`))).toBe(false);expect(fs.existsSync(path.join(bundles,`${retainedId}.json`))).toBe(true);expect(fs.existsSync(dir)).toBe(true);retention(now+30*86400_000);expect(fs.existsSync(dir)).toBe(false);});
|
|
test('replay temporary state survives cleanup failure until every detached watchdog acknowledges cleanup',()=>{const now=Date.now(),repo='b'.repeat(24),run=`${now}-${'5'.repeat(16)}`,dir=secureDirectory(path.join(privateRoot(),repo,run)),control=secureDirectory(path.join(dir,'supervision','repair-attempt')),docker=secureDirectory(path.join(dir,'preparation-execution','offline-attempt'));fs.writeFileSync(path.join(control,'attempt.ready'),'ready\n',{mode:0o600});fs.writeFileSync(path.join(control,'attempt.terminal'),'normal cleanup complete\n',{mode:0o600});fs.writeFileSync(path.join(docker,'watchdog.ready'),'ready\n',{mode:0o600});fs.writeFileSync(path.join(docker,'watchdog.event'),'cleanup incomplete; retrying exact journaled resources\n',{mode:0o600});finalizeReplayTemporary(dir);expect(fs.existsSync(path.join(dir,'.ephemeral-replay.json'))).toBe(true);retention(now);expect(fs.existsSync(control)).toBe(true);expect(fs.existsSync(docker)).toBe(true);fs.writeFileSync(path.join(control,'attempt.stopped'),'normal cleanup acknowledged\n',{mode:0o600});retention(now);expect(fs.existsSync(dir)).toBe(true);fs.writeFileSync(path.join(docker,'watchdog.stopped'),'normal cleanup acknowledged\n',{mode:0o600});retention(now);expect(fs.existsSync(dir)).toBe(false);});
|
|
test('retention recovers a hidden run retirement left by a dead helper',()=>{const now=Date.now(),repo='a'.repeat(24),run=`${now-31*86400_000}-${'6'.repeat(16)}`,retired=secureDirectory(path.join(privateRoot(),repo,`.retired-${run}-${'7'.repeat(32)}`));fs.writeFileSync(path.join(retired,'payload'),'private state\n',{mode:0o600});retention(now);expect(fs.existsSync(retired)).toBe(false);});
|
|
});
|
|
describe('private state and process output',()=>{
|
|
test('state root mirrors the plugin convention and private writes use restrictive modes',()=>{const base=tmp(),root=stateRoot({HOME:base,GSTACK_HOME:'',CLAUDE_PLUGIN_ROOT:'',CLAUDE_PLUGIN_DATA:''});expect(root).toBe(path.join(base,'.gstack'));const dir=secureDirectory(path.join(base,'state')),file=path.join(dir,'x.json');writeJson(file,{token:'safe'});expect(fs.statSync(dir).mode&0o777).toBe(0o700);expect(fs.statSync(file).mode&0o777).toBe(0o600);});
|
|
test('private root preserves caller-owned container modes and secures only its own boundary',()=>{if(process.platform==='win32')return;const old=process.env.GSTACK_HOME,base=tmp(),selected=path.join(base,'selected'),security=path.join(selected,'security'),sentinel=path.join(selected,'keep');fs.mkdirSync(security,{recursive:true});fs.chmodSync(selected,0o755);fs.chmodSync(security,0o751);fs.writeFileSync(sentinel,'kept');const selectedInode=fs.statSync(selected).ino,securityInode=fs.statSync(security).ino;process.env.GSTACK_HOME=selected;try{expect(privateRoot()).toBe(path.join(security,'cso'));expect(privateRoot()).toBe(path.join(security,'cso'));expect(fs.statSync(selected).mode&0o777).toBe(0o755);expect(fs.statSync(security).mode&0o777).toBe(0o751);expect(fs.statSync(selected).ino).toBe(selectedInode);expect(fs.statSync(security).ino).toBe(securityInode);expect(fs.readFileSync(sentinel,'utf8')).toBe('kept');expect(fs.statSync(path.join(security,'cso')).mode&0o777).toBe(0o700);}finally{if(old===undefined)delete process.env.GSTACK_HOME;else process.env.GSTACK_HOME=old;}});
|
|
test('private root creates a missing selected container privately',()=>{const old=process.env.GSTACK_HOME,base=tmp(),selected=path.join(base,'missing');process.env.GSTACK_HOME=selected;try{expect(privateRoot()).toBe(path.join(selected,'security','cso'));for(const directory of [selected,path.join(selected,'security'),path.join(selected,'security','cso')])expect(fs.statSync(directory).mode&0o777).toBe(0o700);}finally{if(old===undefined)delete process.env.GSTACK_HOME;else process.env.GSTACK_HOME=old;}});
|
|
test('private root rejects unsafe or filesystem-root containers without repairing them',()=>{if(process.platform==='win32')return;const old=process.env.GSTACK_HOME,base=tmp(),selected=path.join(base,'unsafe');fs.mkdirSync(selected);fs.chmodSync(selected,0o770);const inode=fs.statSync(selected).ino;try{process.env.GSTACK_HOME=selected;expect(()=>privateRoot()).toThrow('group- or world-writable ancestor');expect(fs.statSync(selected).mode&0o777).toBe(0o770);expect(fs.statSync(selected).ino).toBe(inode);expect(fs.existsSync(path.join(selected,'security'))).toBe(false);process.env.GSTACK_HOME=path.parse(selected).root;const chmod=spyOn(fs,'chmodSync');try{expect(()=>privateRoot()).toThrow('filesystem root');expect(chmod.mock.calls.some(call=>path.resolve(String(call[0]))===path.parse(selected).root)).toBe(false);}finally{chmod.mockRestore();}}finally{if(old===undefined)delete process.env.GSTACK_HOME;else process.env.GSTACK_HOME=old;}});
|
|
test('concurrent first-run directory creation accepts only the expected EEXIST race',()=>{const base=tmp(),target=path.join(base,'first','second'),first=path.join(base,'first'),mkdir=fs.mkdirSync;let raced=false;const patched=spyOn(fs,'mkdirSync').mockImplementation(((candidate:any,options:any)=>{if(String(candidate)===first&&!raced){raced=true;mkdir(candidate,options);const error:any=new Error('created concurrently');error.code='EEXIST';throw error;}return mkdir(candidate,options);}) as typeof fs.mkdirSync);try{expect(secureDirectory(target)).toBe(target);expect(raced).toBe(true);expect(fs.statSync(target).mode&0o777).toBe(0o700);}finally{patched.mockRestore();}});
|
|
test('private state rejects a non-sticky group-writable ancestor',()=>{if(process.platform==='win32')return;const base=tmp();fs.chmodSync(base,0o770);expect(()=>secureDirectory(path.join(base,'private'))).toThrow('group- or world-writable ancestor');});
|
|
test('split process output is joined and redacted before return',async()=>{const dir=tmp(),r=await runProcess('/bin/sh',['-c',"printf 'ghp_abcdefghijklmnop'; printf 'qrstuvwxyz1234567890' >&2"],{cwd:dir,env:{PATH:'/usr/bin:/bin'}});expect(r.stdout+r.stderr).not.toContain('ghp_');expect(r.stdout.toLowerCase()).toContain('redacted');});
|
|
test('alternating stdout and stderr chunks cannot split a secret marker',async()=>{const dir=tmp(),r=await runProcess('/bin/sh',['-c',"printf g; sleep .02; printf hp_abcdefghijklmnop >&2; sleep .02; printf qrstuvwxyz1234567890"],{cwd:dir,env:{PATH:'/usr/bin:/bin'}});expect(r.stdout+r.stderr).not.toContain('abcdefghijklmnop');expect(r.stdout.toLowerCase()).toContain('redacted');});
|
|
test('marker-only private keys withhold the whole payload',async()=>{const dir=tmp();expect(runProcess('/bin/sh',['-c',"printf '%s' \"$1\"",'sh',['-----BEGIN ','PRIVATE KEY-----\nraw\n-----END ','PRIVATE KEY-----'].join('')],{cwd:dir,env:{PATH:'/usr/bin:/bin'}})).rejects.toMatchObject({code:'REDACTION_FAILED'});});
|
|
test('untrusted hash-like keys do not bypass structured redaction',()=>{const dir=tmp(),file=path.join(dir,'value.json');writeJson(file,{payloadHash:['ghp_','abcdefghijklmnopqrstuvwxyz1234567890'].join('')});expect(fs.readFileSync(file,'utf8')).not.toContain('ghp_');});
|
|
test('only schema-bound helper metadata bypasses content redaction',()=>{const token='1abcdefabcdefabcdefabcdefabcdefa',hash='a'.repeat(64),untrusted=sanitizeForJson({id:token,findingId:token,sourceHash:hash}) as any;expect(untrusted.id).not.toBe(token);expect(untrusted.findingId).not.toBe(token);const trusted=sanitizeHelperForJson({id:token,findingId:token,artifactId:token,reviewArtifactId:token,bundleId:token,sourceHash:hash,preparedManifestHash:hash}) as any;expect(trusted).toEqual({id:token,findingId:token,artifactId:token,reviewArtifactId:token,bundleId:token,sourceHash:hash,preparedManifestHash:hash});const dir=tmp(),file=path.join(dir,'claim.json');writeHelperJson(file,{findingId:token,outcome:'open'});expect(readJson(file)).toEqual({findingId:token,outcome:'open'});});
|
|
test('oversized report growth is rejected before replacing the last readable report',()=>{const dir=tmp(),report:any={schemaVersion:3,runId:'1'.repeat(13)+'-'+'a'.repeat(16),repoId:'b'.repeat(24),createdAt:new Date().toISOString(),deadline:new Date(Date.now()+60_000).toISOString(),status:'running',completeness:'not assessed',policy:{mode:'daily',scope:'default',diff:false,base:'origin/main',offline:true,budgetSeconds:600,maxWorkers:3,maxRepairs:3},source:{root:'/source',snapshotHash:'c'.repeat(64),originalHash:'d'.repeat(64)},application:{actors:[],assets:[],entrypoints:[],tenantBoundaries:[],sensitiveOperations:[],invariants:[]},coverage:[],findings:[],gaps:[],events:[]};saveReport(dir,report);const original=fs.readFileSync(path.join(dir,'report.json'),'utf8');report.events=Array.from({length:4000},(_,i)=>({at:new Date().toISOString(),kind:'evidence',message:`${i}:`+'x'.repeat(300)}));expect(()=>saveReport(dir,report)).toThrow('previous artifact was preserved');expect(fs.readFileSync(path.join(dir,'report.json'),'utf8')).toBe(original);expect(loadReport(dir).status).toBe('running');});
|
|
test('a fully published dead legacy owner migrates to the immutable lease protocol',()=>{const dir=tmp(),lock=path.join(dir,'.mutation-lock');fs.mkdirSync(lock);fs.writeFileSync(path.join(lock,'owner.json'),JSON.stringify({pid:2147483647,token:'old',createdAt:0,expiresAt:0}));expect(withLock(dir,()=>42)).toBe(42);expect(fs.lstatSync(lock).isFile()).toBe(true);expect(JSON.parse(fs.readFileSync(lock,'utf8')).protocol).toBe('immutable-lease-set-v3');expect(fs.readdirSync(path.join(dir,'.mutation-lock-leases'))).toEqual([]);});
|
|
test('a dead legacy migration claim is recovered after an interrupted migration',()=>{const dir=tmp(),lock=path.join(dir,'.mutation-lock'),claim=path.join(lock,'.v3-migration'),token='b'.repeat(32);fs.mkdirSync(lock);fs.writeFileSync(path.join(lock,'owner.json'),JSON.stringify({pid:2147483647,token:'old',createdAt:0}));fs.writeFileSync(claim,JSON.stringify({pid:2147483647,token,createdAt:0})+'\n',{mode:0o600,flag:'wx'});expect(withLock(dir,()=>42)).toBe(42);expect(fs.lstatSync(lock).isFile()).toBe(true);expect(fs.readdirSync(path.join(dir,'.mutation-lock-leases'))).toEqual([]);expect(fs.readdirSync(dir).some(name=>name.includes('.legacy-'))).toBe(false);});
|
|
test('an expired timestamp cannot steal a lock from a live owner',()=>{const dir=tmp(),lock=path.join(dir,'.mutation-lock');fs.mkdirSync(lock);fs.writeFileSync(path.join(lock,'owner.json'),JSON.stringify({pid:process.pid,token:'live',createdAt:0,expiresAt:0}));expect(()=>withLock(dir,()=>42)).toThrow('Another helper');});
|
|
test('an incomplete legacy lock is never age-reclaimed from a paused initializer',()=>{const dir=tmp(),lock=path.join(dir,'.mutation-lock'),entered=path.join(dir,'entered');fs.mkdirSync(lock);const old=new Date(Date.now()-60_000);fs.utimesSync(lock,old,old);expect(()=>withLock(dir,()=>fs.writeFileSync(entered,'unsafe'))).toThrow('may still be initializing');expect(fs.existsSync(entered)).toBe(false);expect(fs.lstatSync(lock).isDirectory()).toBe(true);fs.writeFileSync(path.join(lock,'owner.json'),JSON.stringify({pid:process.pid,token:'paused',createdAt:0,expiresAt:0}));expect(()=>withLock(dir,()=>fs.writeFileSync(entered,'unsafe'))).toThrow('Another helper');expect(fs.existsSync(entered)).toBe(false);});
|
|
test('a dead immutable lease is recovered without replacing its inode',()=>{const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token='a'.repeat(32),lease=path.join(leases,`${token}.json`);fs.writeFileSync(lease,JSON.stringify({pid:2147483647,token,createdAt:0})+'\n',{mode:0o600,flag:'wx'});expect(withLock(dir,()=>2)).toBe(2);expect(fs.existsSync(lease)).toBe(false);});
|
|
test('an in-flight cooperating lease publication is contention rather than poisoned state',()=>{const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token='9'.repeat(32),lease=path.join(leases,`${token}.json`),temporary=`${lease}.tmp.${process.pid}.deadbeef`,write=fs.writeFileSync,lstat=fs.lstatSync;let injected=false,transitioned=false,entered=false,caught:unknown;const writer=spyOn(fs,'writeFileSync').mockImplementation(((file:any,data:any,options:any)=>{const result=write(file,data,options);const candidate=String(file);if(!injected&&path.dirname(candidate)===leases&&/^[a-f0-9]{32}\.json\.tmp\.\d+\.[a-f0-9]{8}$/.test(path.basename(candidate))){injected=true;write(temporary,JSON.stringify({pid:process.pid,token,createdAt:Date.now()})+'\n',{mode:0o600,flag:'wx'});}return result;}) as typeof fs.writeFileSync),reader=spyOn(fs,'lstatSync').mockImplementation(((file:any,options?:any)=>{if(!transitioned&&String(file)===temporary){transitioned=true;fs.linkSync(temporary,lease);fs.unlinkSync(temporary);}return options===undefined?lstat(file):lstat(file,options);}) as typeof fs.lstatSync);try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}finally{reader.mockRestore();writer.mockRestore();}expect(injected).toBe(true);expect(transitioned).toBe(true);expect(entered).toBe(false);expect(caught).toMatchObject({code:'INSUFFICIENT_CAPACITY'});expect(fs.readdirSync(leases)).toEqual([path.basename(lease)]);});
|
|
test('a live publisher unlinking its temp after target observation remains ordinary contention',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);
|
|
const leases=path.join(dir,'.mutation-lock-leases'),token='7'.repeat(32),lease=path.join(leases,`${token}.json`),temporary=`${lease}.tmp.${process.pid}.abcdef12`;
|
|
fs.writeFileSync(temporary,JSON.stringify({pid:process.pid,token,createdAt:Date.now()})+'\n',{mode:0o600,flag:'wx'});fs.linkSync(temporary,lease);
|
|
const lstat=fs.lstatSync;let targetReads=0,transitioned=false,entered=false,caught:unknown;
|
|
const reader=spyOn(fs,'lstatSync').mockImplementation(((file:any,options?:any)=>{
|
|
if(String(file)===lease&&++targetReads===2){fs.unlinkSync(temporary);transitioned=true;}
|
|
return options===undefined?lstat(file):lstat(file,options);
|
|
}) as typeof fs.lstatSync);
|
|
try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}finally{reader.mockRestore();}
|
|
expect(transitioned).toBe(true);expect(entered).toBe(false);expect(caught).toMatchObject({code:'INSUFFICIENT_CAPACITY'});expect(fs.statSync(lease).nlink).toBe(1);
|
|
});
|
|
test('a live publisher unlinking its temp after canonical validation is rescanned as contention',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);
|
|
const leases=path.join(dir,'.mutation-lock-leases'),token='5'.repeat(32),lease=path.join(leases,`${token}.json`),temporary=`${lease}.tmp.${process.pid}.a1b2c3d4`;
|
|
fs.writeFileSync(temporary,JSON.stringify({pid:process.pid,token,createdAt:Date.now()})+'\n',{mode:0o600,flag:'wx'});fs.linkSync(temporary,lease);
|
|
const readdir=fs.readdirSync;let leaseReads=0,transitioned=false,entered=false,caught:unknown;
|
|
const reader=spyOn(fs,'readdirSync').mockImplementation(((directory:any,options?:any)=>{
|
|
if(String(directory)===leases&&++leaseReads===2){fs.unlinkSync(temporary);transitioned=true;}
|
|
return options===undefined?readdir(directory):readdir(directory,options);
|
|
}) as typeof fs.readdirSync);
|
|
try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}finally{reader.mockRestore();}
|
|
expect(transitioned).toBe(true);expect(entered).toBe(false);expect(caught).toMatchObject({code:'INSUFFICIENT_CAPACITY'});expect(fs.statSync(lease).nlink).toBe(1);
|
|
});
|
|
test('a live temp linked after the absent-target check remains ordinary contention',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);
|
|
const leases=path.join(dir,'.mutation-lock-leases'),token='8'.repeat(32),lease=path.join(leases,`${token}.json`),temporary=`${lease}.tmp.${process.pid}.1234abcd`;
|
|
fs.writeFileSync(temporary,JSON.stringify({pid:process.pid,token,createdAt:Date.now()})+'\n',{mode:0o600,flag:'wx'});
|
|
const exists=fs.existsSync;let transitioned=false,entered=false,caught:unknown;
|
|
const observer=spyOn(fs,'existsSync').mockImplementation(((file:any)=>{
|
|
const result=exists(file);if(!transitioned&&String(file)===lease&&!result){fs.linkSync(temporary,lease);transitioned=true;}return result;
|
|
}) as typeof fs.existsSync);
|
|
try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}finally{observer.mockRestore();}
|
|
expect(transitioned).toBe(true);expect(entered).toBe(false);expect(caught).toMatchObject({code:'INSUFFICIENT_CAPACITY'});expect(fs.statSync(lease).nlink).toBe(2);
|
|
});
|
|
test('an unrecognized multiply-linked lease temp remains poisoned state',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);
|
|
const leases=path.join(dir,'.mutation-lock-leases'),token='6'.repeat(32),temporary=path.join(leases,`${token}.json.tmp.2147483647.1234abcd`),outside=path.join(dir,'outside-link');
|
|
fs.writeFileSync(temporary,JSON.stringify({pid:2147483647,token,createdAt:0})+'\n',{mode:0o600,flag:'wx'});fs.linkSync(temporary,outside);
|
|
let entered=false,caught:unknown;try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}
|
|
expect(entered).toBe(false);expect(caught).toMatchObject({code:'UNSAFE_PATH'});expect(fs.existsSync(temporary)).toBe(true);expect(fs.existsSync(outside)).toBe(true);
|
|
});
|
|
test('a same-inode same-size content rewrite is not treated as publication progress',()=>{
|
|
const dir=tmp(),token='0'.repeat(32),publisherPid=2147483647,target=path.join(dir,`${token}.json`),temporary=`${target}.tmp.${publisherPid}.abcdef12`,original=JSON.stringify({pid:publisherPid,token,createdAt:0})+'\n',replacement=JSON.stringify({pid:publisherPid,token,createdAt:1})+'\n';expect(replacement.length).toBe(original.length);fs.writeFileSync(temporary,original,{mode:0o600,flag:'wx'});fs.linkSync(temporary,target);
|
|
const fstat=fs.fstatSync;let reads=0,rewritten=false;const reader=spyOn(fs,'fstatSync').mockImplementation(((fd:any,options?:any)=>{if(++reads===2){fs.writeFileSync(target,replacement);rewritten=true;}return options===undefined?fstat(fd):fstat(fd,options);}) as typeof fs.fstatSync);
|
|
let caught:unknown;try{discardAtomicNoReplaceTemp(temporary,publisherPid,{label:'Test publication',maxBytes:4096});}catch(error){caught=error;}finally{reader.mockRestore();}
|
|
expect(rewritten).toBe(true);expect(caught).toMatchObject({code:'SNAPSHOT_RACE'});expect(fs.existsSync(target)).toBe(true);expect(fs.existsSync(temporary)).toBe(true);
|
|
});
|
|
test('a live publisher identity cannot launder a stable same-size rewrite as contention',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token='f'.repeat(32),publisherPid=process.pid,target=path.join(leases,`${token}.json`),temporary=`${target}.tmp.${publisherPid}.abcdef12`,original=JSON.stringify({pid:publisherPid,token,createdAt:0})+'\n',replacement=JSON.stringify({pid:publisherPid,token,createdAt:1})+'\n';expect(replacement.length).toBe(original.length);fs.writeFileSync(temporary,original,{mode:0o600,flag:'wx'});fs.linkSync(temporary,target);
|
|
const fstat=fs.fstatSync;let reads=0,rewritten=false,entered=false,caught:unknown;const reader=spyOn(fs,'fstatSync').mockImplementation(((fd:any,options?:any)=>{if(++reads===2){fs.writeFileSync(target,replacement);rewritten=true;}return options===undefined?fstat(fd):fstat(fd,options);}) as typeof fs.fstatSync);try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}finally{reader.mockRestore();}
|
|
expect(rewritten).toBe(true);expect(entered).toBe(false);expect(caught).toMatchObject({code:'SNAPSHOT_RACE'});expect(fs.existsSync(target)).toBe(true);expect(fs.existsSync(temporary)).toBe(true);
|
|
});
|
|
test('a stable malformed hard-link publication stays unsafe even when its named PID is live',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token='9'.repeat(32),target=path.join(leases,`${token}.json`),temporary=`${target}.tmp.${process.pid}.deadbeef`;fs.writeFileSync(temporary,'{"malformed":\n',{mode:0o600,flag:'wx'});fs.linkSync(temporary,target);let entered=false,caught:unknown;try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}expect(entered).toBe(false);expect(caught).toMatchObject({code:'UNSAFE_PATH'});expect(fs.existsSync(target)).toBe(true);expect(fs.existsSync(temporary)).toBe(true);
|
|
});
|
|
test('a zero-byte hard-linked publication stays unsafe even when its named PID is live',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token='7'.repeat(32),target=path.join(leases,`${token}.json`),temporary=`${target}.tmp.${process.pid}.deadbeef`;fs.writeFileSync(temporary,'',{mode:0o600,flag:'wx'});fs.linkSync(temporary,target);let entered=false,caught:unknown;try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}expect(entered).toBe(false);expect(caught).toMatchObject({code:'UNSAFE_PATH'});expect(fs.statSync(target).nlink).toBe(2);expect(fs.statSync(temporary).nlink).toBe(2);
|
|
});
|
|
test('settled publication contention cannot launder a stable incoherent lease phase',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),poisonToken='a'.repeat(32),liveToken='b'.repeat(32),poison=path.join(leases,`${poisonToken}.active.0000000000000001`),temporary=path.join(leases,`${liveToken}.json.tmp.${process.pid}.abcdef12`);fs.writeFileSync(poison,JSON.stringify({pid:process.pid,token:poisonToken,createdAt:0})+'\n',{mode:0o600,flag:'wx'});
|
|
const write=fs.writeFileSync;let injected=false;const publisher=spyOn(fs,'writeFileSync').mockImplementation(((file:any,data:any,options:any)=>{const result=write(file,data,options),name=path.basename(String(file));if(!injected&&path.dirname(String(file))===leases&&/^[a-f0-9]{32}\.json\.tmp\.\d+\.[a-f0-9]{8}$/.test(name)&&!name.startsWith(liveToken)){injected=true;write(temporary,JSON.stringify({pid:process.pid,token:liveToken,createdAt:0})+'\n',{mode:0o600,flag:'wx'});}return result;}) as typeof fs.writeFileSync);
|
|
const wait=Atomics.wait.bind(Atomics);let settled=false,entered=false,caught:unknown;const sleeper=spyOn(Atomics,'wait').mockImplementation(((array:any,index:any,value:any,timeout?:any)=>{if(!settled&&fs.existsSync(temporary)){settled=true;fs.unlinkSync(temporary);}return wait(array,index,value,timeout);}) as typeof Atomics.wait);try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}finally{sleeper.mockRestore();publisher.mockRestore();}
|
|
expect(injected).toBe(true);expect(settled).toBe(true);expect(entered).toBe(false);expect(caught).toMatchObject({code:'UNSAFE_PATH'});expect(fs.existsSync(poison)).toBe(true);
|
|
});
|
|
test('successful recovery on the final bounded rescan remains transient capacity',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),liveToken='c'.repeat(32),temporary=path.join(leases,`${liveToken}.json.tmp.${process.pid}.abcdef12`),write=fs.writeFileSync;let injected=false;const publisher=spyOn(fs,'writeFileSync').mockImplementation(((file:any,data:any,options:any)=>{const result=write(file,data,options),name=path.basename(String(file));if(!injected&&path.dirname(String(file))===leases&&/^[a-f0-9]{32}\.json\.tmp\.\d+\.[a-f0-9]{8}$/.test(name)&&!name.startsWith(liveToken)){injected=true;write(temporary,JSON.stringify({pid:process.pid,token:liveToken,createdAt:0})+'\n',{mode:0o600,flag:'wx'});}return result;}) as typeof fs.writeFileSync);
|
|
const now=spyOn(Date,'now').mockReturnValue(1000),kill=process.kill.bind(process);let probes=0,entered=false,caught:unknown;const liveness=spyOn(process,'kill').mockImplementation(((pid:any,signal?:any)=>{if(Number(pid)===process.pid&&signal===0&&++probes===532){const error:any=new Error('gone');error.code='ESRCH';throw error;}return Number(pid)===process.pid&&signal===0?true:(signal===undefined?kill(pid):kill(pid,signal));}) as typeof process.kill);try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}finally{liveness.mockRestore();now.mockRestore();publisher.mockRestore();}
|
|
expect(injected).toBe(true);expect(probes).toBe(532);expect(entered).toBe(false);expect(caught).toMatchObject({code:'INSUFFICIENT_CAPACITY'});expect(fs.existsSync(temporary)).toBe(false);expect(fs.readdirSync(leases)).toEqual([]);
|
|
});
|
|
test('a settled publication remains bound to the originally observed inode',()=>{
|
|
const dir=tmp(),token='4'.repeat(32),publisherPid=2147483647,target=path.join(dir,`${token}.json`),temporary=`${target}.tmp.${publisherPid}.abcdef12`,parked=`${target}.replaced`,owner=JSON.stringify({pid:publisherPid,token,createdAt:0})+'\n';
|
|
fs.writeFileSync(temporary,owner,{mode:0o600,flag:'wx'});fs.linkSync(temporary,target);const original=fs.statSync(target).ino,lstat=fs.lstatSync;let targetReads=0,replaced=false,caught:unknown;
|
|
const reader=spyOn(fs,'lstatSync').mockImplementation(((file:any,options?:any)=>{
|
|
if(String(file)===target&&++targetReads===2){fs.unlinkSync(target);fs.renameSync(temporary,parked);fs.writeFileSync(target,owner,{mode:0o600,flag:'wx'});replaced=true;}
|
|
return options===undefined?lstat(file):lstat(file,options);
|
|
}) as typeof fs.lstatSync);
|
|
try{discardAtomicNoReplaceTemp(temporary,publisherPid,{label:'Test publication',maxBytes:4096,validate:(value,pid)=>{expect((value as any).token).toBe(token);expect(pid).toBe(publisherPid);}});}catch(error){caught=error;}finally{reader.mockRestore();}
|
|
expect(replaced).toBe(true);expect(caught).toMatchObject({code:'UNSAFE_PATH'});expect(fs.statSync(parked).ino).toBe(original);expect(fs.statSync(target).ino).not.toBe(original);
|
|
});
|
|
test('a link transition on an open inode cannot launder a replacement pathname',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);
|
|
const leases=path.join(dir,'.mutation-lock-leases'),token='3'.repeat(32),publisherPid=2147483647,target=path.join(leases,`${token}.json`),temporary=`${target}.tmp.${publisherPid}.1234abcd`,owner=JSON.stringify({pid:publisherPid,token,createdAt:0})+'\n';
|
|
fs.writeFileSync(temporary,owner,{mode:0o600,flag:'wx'});fs.linkSync(temporary,target);const original=fs.statSync(target).ino,fstat=fs.fstatSync;let reads=0,replaced=false,entered=false,caught:unknown;
|
|
const reader=spyOn(fs,'fstatSync').mockImplementation(((fd:any,options?:any)=>{
|
|
if(++reads===2){fs.unlinkSync(target);fs.writeFileSync(target,owner,{mode:0o600,flag:'wx'});replaced=true;}
|
|
return options===undefined?fstat(fd):fstat(fd,options);
|
|
}) as typeof fs.fstatSync);
|
|
try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}finally{reader.mockRestore();}
|
|
expect(replaced).toBe(true);expect(entered).toBe(false);expect(caught).toMatchObject({name:'CsoError',code:'SNAPSHOT_RACE'});expect(fs.statSync(target).ino).not.toBe(original);expect(fs.existsSync(temporary)).toBe(true);
|
|
});
|
|
test('a cooperating lease released between open and fstat is rescanned',()=>{
|
|
const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);
|
|
const leases=path.join(dir,'.mutation-lock-leases'),token='2'.repeat(32),lease=path.join(leases,`${token}.json`);fs.writeFileSync(lease,JSON.stringify({pid:process.pid,token,createdAt:Date.now()})+'\n',{mode:0o600,flag:'wx'});
|
|
const fstat=fs.fstatSync;let released=false,entered=false;const reader=spyOn(fs,'fstatSync').mockImplementation(((fd:any,options?:any)=>{if(!released){fs.unlinkSync(lease);released=true;}return options===undefined?fstat(fd):fstat(fd,options);}) as typeof fs.fstatSync);
|
|
try{withLock(dir,()=>{entered=true;});}finally{reader.mockRestore();}
|
|
expect(released).toBe(true);expect(entered).toBe(true);expect(fs.existsSync(lease)).toBe(false);
|
|
});
|
|
test('recovers the exact no-replace lease hard link left by a dead publisher',()=>{const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token='1'.repeat(32),lease=path.join(leases,`${token}.json`),temporary=`${lease}.tmp.2147483647.deadbeef`;fs.writeFileSync(lease,JSON.stringify({pid:2147483647,token,createdAt:0})+'\n',{mode:0o600,flag:'wx'});fs.linkSync(lease,temporary);expect(fs.statSync(lease).nlink).toBe(2);expect(withLock(dir,()=>2)).toBe(2);expect(fs.existsSync(lease)).toBe(false);expect(fs.existsSync(temporary)).toBe(false);});
|
|
test('private immutable reads recover only a recognized same-inode no-replace temp',()=>{const dir=tmp(),artifact=path.join(dir,'artifact.json'),temporary=`${artifact}.tmp.2147483647.cafebabe`;fs.writeFileSync(artifact,JSON.stringify({value:'bound'})+'\n',{mode:0o600,flag:'wx'});fs.linkSync(artifact,temporary);expect(readJson(artifact)).toEqual({value:'bound'});expect(fs.statSync(artifact).nlink).toBe(1);expect(fs.existsSync(temporary)).toBe(false);const poisoned=path.join(dir,'poisoned.json'),unrecognized=`${poisoned}.tmp.dead.bad`;fs.writeFileSync(poisoned,'{}\n',{mode:0o600,flag:'wx'});fs.linkSync(poisoned,unrecognized);expect(()=>readJson(poisoned)).toThrow('hard link does not match');expect(fs.existsSync(unrecognized)).toBe(true);});
|
|
test('private JSON reads reject rename and symlink substitutions between validation and open',()=>{for(const kind of ['rename','symlink'] as const){const dir=tmp(),artifact=path.join(dir,'artifact.json'),original=path.join(dir,'original.json'),poison=path.join(dir,'poison.json');fs.writeFileSync(artifact,JSON.stringify({value:'bound'})+'\n',{mode:0o600});fs.writeFileSync(poison,JSON.stringify({value:'poison'})+'\n',{mode:0o600});const open=fs.openSync,patched=spyOn(fs,'openSync').mockImplementation(((candidate:any,flags:any,mode?:any)=>{if(String(candidate)===artifact){fs.renameSync(artifact,original);if(kind==='rename')fs.renameSync(poison,artifact);else fs.symlinkSync(poison,artifact);}return mode===undefined?open(candidate,flags):open(candidate,flags,mode);}) as typeof fs.openSync);try{expect(()=>readJson(artifact)).toThrow(/changed while it was opened/);}finally{patched.mockRestore();}}});
|
|
test('mismatched lease publisher identity fails closed',()=>{const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token='2'.repeat(32),lease=path.join(leases,`${token}.json`),temporary=`${lease}.tmp.2147483646.abcdef12`;fs.writeFileSync(lease,JSON.stringify({pid:2147483647,token,createdAt:0})+'\n',{mode:0o600,flag:'wx'});fs.linkSync(lease,temporary);expect(()=>withLock(dir,()=>2)).toThrow('does not match its publisher');expect(fs.statSync(lease).nlink).toBe(2);});
|
|
test('malformed and multiply-linked immutable owners fail closed instead of being reclaimed',()=>{for(const kind of ['schema','hardlink'] as const){const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token=(kind==='schema'?'c':'d').repeat(32),lease=path.join(leases,`${token}.json`),value=JSON.stringify(kind==='schema'?{pid:'dead',token,createdAt:0}:{pid:2147483647,token,createdAt:0})+'\n';fs.writeFileSync(lease,value,{mode:0o600,flag:'wx'});if(kind==='hardlink')fs.linkSync(lease,path.join(dir,'outside-link'));let entered=false;expect(()=>withLock(dir,()=>{entered=true;})).toThrow('Run mutation lease');expect(entered).toBe(false);expect(fs.existsSync(lease)).toBe(true);}});
|
|
test('PID reuse is distinguished by the Linux process-start identity',()=>{if(process.platform!=='linux')return;const raw=fs.readFileSync(`/proc/${process.pid}/stat`,'utf8'),tail=raw.slice(raw.lastIndexOf(')')+2).trim().split(/\s+/),identity=BigInt(tail[19]),dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token='e'.repeat(32),lease=path.join(leases,`${token}.json`);fs.writeFileSync(lease,JSON.stringify({pid:process.pid,processIdentity:`linux:${identity+1n}`,token,createdAt:0})+'\n',{mode:0o600,flag:'wx'});expect(withLock(dir,()=>2)).toBe(2);expect(fs.existsSync(lease)).toBe(false);});
|
|
test('interrupted lease publications use process identity to distinguish PID reuse',()=>{if(process.platform!=='linux')return;const raw=fs.readFileSync(`/proc/${process.pid}/stat`,'utf8'),tail=raw.slice(raw.lastIndexOf(')')+2).trim().split(/\s+/),identity=BigInt(tail[19]);for(const linked of [false,true]){const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token=(linked?'b':'a').repeat(32),lease=path.join(leases,`${token}.json`),temporary=`${lease}.tmp.${process.pid}.abcdef12`,owner=JSON.stringify({pid:process.pid,processIdentity:`linux:${identity+1n}`,token,createdAt:0})+'\n';fs.writeFileSync(temporary,owner,{mode:0o600,flag:'wx'});if(linked)fs.linkSync(temporary,lease);expect(withLock(dir,()=>2)).toBe(2);expect(fs.existsSync(temporary)).toBe(false);expect(fs.existsSync(lease)).toBe(false);}});
|
|
test('EPERM liveness keeps an active cross-process lease intact',()=>{const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),token='d'.repeat(32),pid=2147483647,createdAt=0,candidate=path.join(leases,`${token}.json`),decision=path.join(leases,`${token}.decision`),ticket='1'.padStart(16,'0'),active=path.join(leases,`${token}.active.${ticket}`);fs.writeFileSync(candidate,JSON.stringify({pid,token,createdAt})+'\n',{mode:0o600,flag:'wx'});const stat=fs.statSync(candidate);fs.writeFileSync(decision,JSON.stringify({schemaVersion:1,token,kind:'ticket',ticket,candidateDev:String(stat.dev),candidateIno:String(stat.ino),ownerPid:pid,ownerCreatedAt:createdAt,publisherPid:pid,createdAt})+'\n',{mode:0o600,flag:'wx'});fs.linkSync(candidate,active);const kill=process.kill.bind(process),probe=spyOn(process,'kill').mockImplementation(((target:any,signal?:any)=>{if(Number(target)===pid){const error:any=new Error('not permitted');error.code='EPERM';throw error;}return signal===undefined?kill(target):kill(target,signal);}) as typeof process.kill);let entered=false,caught:unknown;try{withLock(dir,()=>{entered=true;});}catch(error){caught=error;}finally{probe.mockRestore();}expect(entered).toBe(false);expect(caught).toMatchObject({code:'INSUFFICIENT_CAPACITY'});expect([candidate,decision,active].every(file=>fs.existsSync(file))).toBe(true);expect(fs.statSync(candidate).nlink).toBe(2);expect(fs.statSync(decision).nlink).toBe(1);});
|
|
test('an active lease binds a separate decision to its candidate and active inode',()=>{const dir=tmp();withLock(dir,()=>{const leases=path.join(dir,'.mutation-lock-leases'),names=fs.readdirSync(leases);expect(names.length).toBe(3);const candidate=names.find(name=>name.endsWith('.json'))!,decision=names.find(name=>name.endsWith('.decision'))!,active=names.find(name=>name.includes('.active.'))!,candidateStat=fs.statSync(path.join(leases,candidate)),decisionStat=fs.statSync(path.join(leases,decision)),activeStat=fs.statSync(path.join(leases,active)),record=JSON.parse(fs.readFileSync(path.join(leases,decision),'utf8'));expect(`${candidateStat.dev}:${candidateStat.ino}`).toBe(`${activeStat.dev}:${activeStat.ino}`);expect(candidateStat.nlink).toBe(2);expect(activeStat.nlink).toBe(2);expect(`${decisionStat.dev}:${decisionStat.ino}`).not.toBe(`${candidateStat.dev}:${candidateStat.ino}`);expect(decisionStat.nlink).toBe(1);expect(record.kind).toBe('ticket');expect(record.candidateDev).toBe(String(candidateStat.dev));expect(record.candidateIno).toBe(String(candidateStat.ino));});expect(fs.readdirSync(path.join(dir,'.mutation-lock-leases'))).toEqual([]);});
|
|
test('post-link verification failure cleans every recorded lease phase',()=>{const dir=tmp();expect(withLock(dir,()=>1)).toBe(1);const leases=path.join(dir,'.mutation-lock-leases'),fakeToken='f'.repeat(32),fakeTemp=path.join(leases,`${fakeToken}.json.tmp.${process.pid}.deadbeef`),link=fs.linkSync,injectedOwner=JSON.stringify({pid:process.pid,token:fakeToken,createdAt:Date.now()})+'\n';let injected=false,caught:unknown;const publisher=spyOn(fs,'linkSync').mockImplementation(((source:any,target:any)=>{const result=link(source,target);if(!injected&&String(target).includes('.active.')){injected=true;fs.writeFileSync(fakeTemp,injectedOwner,{mode:0o600,flag:'wx'});}return result;}) as typeof fs.linkSync);try{withLock(dir,()=>1);}catch(error){caught=error;}finally{publisher.mockRestore();}expect(injected).toBe(true);expect(caught).toMatchObject({code:'INSUFFICIENT_CAPACITY'});expect(fs.readdirSync(leases)).toEqual([path.basename(fakeTemp)]);fs.unlinkSync(fakeTemp);expect(withLock(dir,()=>2)).toBe(2);expect(fs.readdirSync(leases)).toEqual([]);});
|
|
test('an async callback retains its lease until settlement without blocking its own event loop',async()=>{const dir=tmp();let release!:()=>void;const pending=new Promise<void>(resolve=>{release=resolve;}),outer=withLock(dir,async()=>{await pending;return 7;}),started=Date.now();expect(()=>withLock(dir,()=>99)).toThrow('Another operation in this helper');expect(Date.now()-started).toBeLessThan(200);release();expect(await outer).toBe(7);expect(withLock(dir,()=>9)).toBe(9);});
|
|
test('a synchronous exact-release failure is attempted only once',()=>{const dir=tmp(),lstat=fs.lstatSync;let observed=0,reader:any;try{expect(()=>withLock(dir,()=>{const leases=path.join(dir,'.mutation-lock-leases'),names=fs.readdirSync(leases),candidate=path.join(leases,names.find(name=>name.endsWith('.json'))!),active=path.join(leases,names.find(name=>name.includes('.active.'))!),value=fs.readFileSync(active);fs.unlinkSync(active);fs.writeFileSync(active,value,{mode:0o600,flag:'wx'});reader=spyOn(fs,'lstatSync').mockImplementation(((file:any,options?:any)=>{if(String(file)===candidate)observed++;return options===undefined?lstat(file):lstat(file,options);}) as typeof fs.lstatSync);})).toThrow('active phase changed before cleanup');expect(observed).toBe(1);}finally{reader?.mockRestore();}});
|
|
test('exact release rejects active or decision inode substitution and overrides callback success or failure',()=>{for(const phase of ['active','decision'] as const){const dir=tmp();let replacement='',parked='';expect(()=>withLock(dir,()=>{const leases=path.join(dir,'.mutation-lock-leases'),name=fs.readdirSync(leases).find(value=>phase==='active'?value.includes('.active.'):value.endsWith('.decision'))!,lease=path.join(leases,name),value=fs.readFileSync(lease);parked=`${lease}.replaced`;fs.renameSync(lease,parked);fs.writeFileSync(lease,value,{mode:0o600,flag:'wx'});replacement=lease;if(phase==='active')throw new Error('callback failed');return 1;})).toThrow(/changed before (cleanup|exact release)/);expect(fs.existsSync(replacement)).toBe(true);expect(fs.existsSync(parked)).toBe(true);expect(fs.statSync(replacement).ino).not.toBe(fs.statSync(parked).ino);fs.rmSync(dir,{recursive:true,force:true});}});
|
|
test('concurrent stale-lock recovery never admits overlapping report writers',async()=>{const dir=tmp(),lock=path.join(dir,'.mutation-lock'),script=path.join(dir,'racer.ts');fs.mkdirSync(lock);fs.writeFileSync(path.join(lock,'owner.json'),JSON.stringify({pid:2147483647,token:'stale',createdAt:0,expiresAt:0}));fs.writeFileSync(script,`import fs from 'node:fs';import path from 'node:path';import {withLock} from ${JSON.stringify(path.resolve(import.meta.dir,'../lib/cso/state.ts'))};const dir=process.env.RACE_DIR!;try{await withLock(dir,async()=>{const active=path.join(dir,'active');try{fs.writeFileSync(active,String(process.pid),{flag:'wx'});}catch{fs.appendFileSync(path.join(dir,'overlap'),'yes\\n');}await Bun.sleep(50);try{if(fs.readFileSync(active,'utf8')===String(process.pid))fs.unlinkSync(active);}catch{}});}catch{}`);const children=Array.from({length:8},()=>spawn(process.execPath,[script],{env:{...process.env,RACE_DIR:dir},stdio:'ignore'}));await Promise.all(children.map(child=>new Promise<void>(resolve=>child.on('close',()=>resolve()))));expect(fs.existsSync(path.join(dir,'overlap'))).toBe(false);});
|
|
test('concurrent recovery of one dead hard-link publication has a winner and no raw race errors',async()=>{
|
|
const dir=tmp(),barrier=path.join(dir,'barrier'),script=path.join(dir,'recovery-racer.ts');fs.mkdirSync(barrier);expect(withLock(dir,()=>1)).toBe(1);
|
|
const leases=path.join(dir,'.mutation-lock-leases'),token='c'.repeat(32),lease=path.join(leases,`${token}.json`),temporary=`${lease}.tmp.2147483647.deadbeef`;
|
|
fs.writeFileSync(temporary,JSON.stringify({pid:2147483647,token,createdAt:0})+'\n',{mode:0o600,flag:'wx'});fs.linkSync(temporary,lease);
|
|
fs.writeFileSync(script,`import fs from 'node:fs';import path from 'node:path';import {withLock} from ${JSON.stringify(path.resolve(import.meta.dir,'../lib/cso/state.ts'))};const dir=process.env.RACE_DIR!,barrier=process.env.BARRIER!,id=process.env.RACE_ID!,wait=new Int32Array(new SharedArrayBuffer(4));fs.writeFileSync(path.join(barrier,'ready-'+id),'ready',{flag:'wx'});while(!fs.existsSync(path.join(barrier,'go')))Atomics.wait(wait,0,0,1);let outcome='success';try{withLock(dir,()=>{const active=path.join(barrier,'work-active');try{fs.writeFileSync(active,id,{flag:'wx'});}catch{fs.appendFileSync(path.join(barrier,'overlap'),'yes\\n');}Atomics.wait(wait,0,0,20);try{if(fs.readFileSync(active,'utf8')===id)fs.unlinkSync(active);}catch{}});}catch(error){outcome=String(error?.code??error)+':'+String(error?.message??'');}fs.writeFileSync(path.join(barrier,'result-'+id),outcome);`);
|
|
const children=Array.from({length:8},(_,index)=>spawn(process.execPath,[script],{env:{...process.env,RACE_DIR:dir,BARRIER:barrier,RACE_ID:String(index)},stdio:'ignore'})),done=children.map(child=>childExit(child));
|
|
try{
|
|
for(let index=0;index<children.length;index++)await waitForPath(path.join(barrier,`ready-${index}`));fs.writeFileSync(path.join(barrier,'go'),'go');await Promise.all(done);
|
|
const outcomes=children.map((_,index)=>fs.readFileSync(path.join(barrier,`result-${index}`),'utf8'));
|
|
expect(outcomes).toContain('success');expect(outcomes.filter(value=>value!=='success'&&!value.startsWith('INSUFFICIENT_CAPACITY:'))).toEqual([]);
|
|
expect(fs.existsSync(path.join(barrier,'overlap'))).toBe(false);expect(fs.readdirSync(leases)).toEqual([]);
|
|
}finally{stopChildren(children);}
|
|
});
|
|
test('two synchronized cooperating publishers admit work without overlap or an all-loser outcome',async()=>{
|
|
const dir=tmp(),barrier=path.join(dir,'barrier'),script=path.join(dir,'contender.ts');fs.mkdirSync(barrier);expect(withLock(dir,()=>1)).toBe(1);
|
|
fs.writeFileSync(script,`import fs from 'node:fs';import path from 'node:path';import {withLock} from ${JSON.stringify(path.resolve(import.meta.dir,'../lib/cso/state.ts'))};
|
|
const dir=process.env.RACE_DIR!,barrier=process.env.BARRIER!,id=process.env.RACE_ID!,leases=path.join(dir,'.mutation-lock-leases'),read=fs.readdirSync;let reads=0;
|
|
fs.readdirSync=((candidate,...args)=>{if(String(candidate)===leases&&++reads===2){fs.writeFileSync(path.join(barrier,'ready-'+id),'ready',{flag:'wx'});const deadline=Date.now()+5000;while(fs.readdirSync(barrier).filter(name=>name.startsWith('ready-')).length<2){if(Date.now()>deadline)throw new Error('barrier timeout');Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,1);}}return read.call(fs,candidate,...args);});
|
|
let outcome='success';try{withLock(dir,()=>{const active=path.join(barrier,'active');try{fs.writeFileSync(active,id,{flag:'wx'});}catch{fs.writeFileSync(path.join(barrier,'overlap'),'overlap');}Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,25);try{if(fs.readFileSync(active,'utf8')===id)fs.unlinkSync(active);}catch{}});}catch(error){outcome=String(error?.code??error);}fs.writeFileSync(path.join(barrier,'result-'+id),outcome);`);
|
|
const children=['a','b'].map(id=>spawn(process.execPath,[script],{env:{...process.env,RACE_DIR:dir,BARRIER:barrier,RACE_ID:id},stdio:'ignore'}));
|
|
await Promise.all(children.map(child=>new Promise<void>((resolve,reject)=>child.on('error',reject).on('close',code=>code===0?resolve():reject(new Error(`contender exited ${code}`))))));
|
|
const outcomes=['a','b'].map(id=>fs.readFileSync(path.join(barrier,`result-${id}`),'utf8'));
|
|
expect(outcomes.filter(value=>value==='success').length).toBeGreaterThan(0);expect(outcomes.every(value=>value==='success'||value==='INSUFFICIENT_CAPACITY')).toBe(true);expect(fs.existsSync(path.join(barrier,'overlap'))).toBe(false);
|
|
});
|
|
test('equal ticket decisions use token order and a late withdrawal cannot revoke the active winner',async()=>{
|
|
if(process.platform==='win32')return;
|
|
const dir=tmp(),barrier=path.join(dir,'barrier'),script=path.join(dir,'contender.ts'),lowToken='1'.repeat(32),highToken='e'.repeat(32);fs.mkdirSync(barrier);expect(withLock(dir,()=>1)).toBe(1);fs.writeFileSync(script,leaseContenderSource());
|
|
const env={...process.env,RACE_DIR:dir,BARRIER:barrier},children:Array<ReturnType<typeof spawn>>=[];
|
|
try{
|
|
const low=spawn(process.execPath,[script],{env:{...env,RACE_ID:'L',RACE_MODE:'pause-before-decision',RACE_TOKEN:lowToken,RACE_HOLD:'1'},stdio:'ignore'});children.push(low);const lowDone=childExit(low);await waitForPath(path.join(barrier,'paused-L'));expect(fs.readFileSync(path.join(barrier,'choice-L'),'utf8')).toBe('0000000000000001');
|
|
const high=spawn(process.execPath,[script],{env:{...env,RACE_ID:'H',RACE_MODE:'pause-before-withdraw',RACE_TOKEN:highToken},stdio:'ignore'});children.push(high);const highDone=childExit(high);await waitForPath(path.join(barrier,'paused-H'),2500);expect(fs.readFileSync(path.join(barrier,'choice-H'),'utf8')).toBe('0000000000000001');
|
|
process.kill(low.pid!,'SIGCONT');await waitForPath(path.join(barrier,'entered-L'));const decision=JSON.parse(fs.readFileSync(path.join(dir,'.mutation-lock-leases',lowToken+'.decision'),'utf8'));expect(decision.kind).toBe('ticket');expect(decision.ticket).toBe('0000000000000001');
|
|
process.kill(high.pid!,'SIGCONT');await waitForPath(path.join(barrier,'result-H'));expect(fs.readFileSync(path.join(barrier,'result-H'),'utf8')).toBe('INSUFFICIENT_CAPACITY');expect(await highDone).toBe(0);
|
|
fs.writeFileSync(path.join(barrier,'release-L'),'release');await waitForPath(path.join(barrier,'result-L'));expect(fs.readFileSync(path.join(barrier,'result-L'),'utf8')).toBe('success');expect(await lowDone).toBe(0);expect(fs.existsSync(path.join(barrier,'overlap'))).toBe(false);expect(fs.readdirSync(path.join(dir,'.mutation-lock-leases'))).toEqual([]);
|
|
}finally{stopChildren(children);}
|
|
});
|
|
test('a paused candidate is fenced so a progressing ticket wins within the bound',async()=>{if(process.platform==='win32')return;const dir=tmp(),barrier=path.join(dir,'barrier'),script=path.join(dir,'contender.ts');fs.mkdirSync(barrier);expect(withLock(dir,()=>1)).toBe(1);fs.writeFileSync(script,leaseContenderSource());const env={...process.env,RACE_DIR:dir,BARRIER:barrier},children:Array<ReturnType<typeof spawn>>=[];try{const earlier=spawn(process.execPath,[script],{env:{...env,RACE_ID:'L',RACE_MODE:'pause-candidate'},stdio:'ignore'});children.push(earlier);const earlierDone=childExit(earlier);await waitForPath(path.join(barrier,'paused-L'));const started=Date.now(),later=spawn(process.execPath,[script],{env:{...env,RACE_ID:'H',RACE_MODE:'normal'},stdio:'ignore'});children.push(later);const laterDone=childExit(later);await waitForPath(path.join(barrier,'result-H'),2500);expect(Date.now()-started).toBeLessThan(2000);expect(fs.readFileSync(path.join(barrier,'result-H'),'utf8')).toBe('success');expect(await laterDone).toBe(0);process.kill(earlier.pid!,'SIGCONT');await waitForPath(path.join(barrier,'result-L'));expect(fs.readFileSync(path.join(barrier,'result-L'),'utf8')).toBe('INSUFFICIENT_CAPACITY');expect(await earlierDone).toBe(0);expect(fs.existsSync(path.join(barrier,'overlap'))).toBe(false);expect(fs.readdirSync(path.join(dir,'.mutation-lock-leases'))).toEqual([]);}finally{stopChildren(children);}});
|
|
test('a paused earlier ticket bounds later contenders without withdrawing the winner',async()=>{if(process.platform==='win32')return;const dir=tmp(),barrier=path.join(dir,'barrier'),script=path.join(dir,'contender.ts');fs.mkdirSync(barrier);expect(withLock(dir,()=>1)).toBe(1);fs.writeFileSync(script,leaseContenderSource());const env={...process.env,RACE_DIR:dir,BARRIER:barrier},children:Array<ReturnType<typeof spawn>>=[];try{const earlier=spawn(process.execPath,[script],{env:{...env,RACE_ID:'L',RACE_MODE:'pause-ticket'},stdio:'ignore'});children.push(earlier);const earlierDone=childExit(earlier);await waitForPath(path.join(barrier,'paused-L'));const started=Date.now(),later=spawn(process.execPath,[script],{env:{...env,RACE_ID:'H',RACE_MODE:'normal'},stdio:'ignore'});children.push(later);const laterDone=childExit(later);await waitForPath(path.join(barrier,'result-H'),2500);expect(Date.now()-started).toBeLessThan(2000);expect(fs.readFileSync(path.join(barrier,'result-H'),'utf8')).toBe('INSUFFICIENT_CAPACITY');expect(await laterDone).toBe(0);process.kill(earlier.pid!,'SIGCONT');await waitForPath(path.join(barrier,'result-L'));expect(fs.readFileSync(path.join(barrier,'result-L'),'utf8')).toBe('success');expect(await earlierDone).toBe(0);expect(fs.existsSync(path.join(barrier,'overlap'))).toBe(false);expect(fs.readdirSync(path.join(dir,'.mutation-lock-leases'))).toEqual([]);}finally{stopChildren(children);}});
|
|
test('a paused loser cleanup leaves only an ineligible decision and cannot block the winner',async()=>{if(process.platform==='win32')return;const dir=tmp(),barrier=path.join(dir,'barrier'),script=path.join(dir,'contender.ts');fs.mkdirSync(barrier);expect(withLock(dir,()=>1)).toBe(1);fs.writeFileSync(script,leaseContenderSource());const env={...process.env,RACE_DIR:dir,BARRIER:barrier},children:Array<ReturnType<typeof spawn>>=[];try{const winner=spawn(process.execPath,[script],{env:{...env,RACE_ID:'L',RACE_MODE:'pause-ticket'},stdio:'ignore'});children.push(winner);const winnerDone=childExit(winner);await waitForPath(path.join(barrier,'paused-L'));const loser=spawn(process.execPath,[script],{env:{...env,RACE_ID:'H',RACE_MODE:'pause-withdraw-cleanup'},stdio:'ignore'});children.push(loser);const loserDone=childExit(loser);await waitForPath(path.join(barrier,'paused-H'));const phases=fs.readdirSync(path.join(dir,'.mutation-lock-leases'));expect(phases.filter(name=>name.endsWith('.decision')).length).toBe(2);expect(phases.filter(name=>name.endsWith('.json')).length).toBe(1);process.kill(winner.pid!,'SIGCONT');await waitForPath(path.join(barrier,'result-L'));expect(fs.readFileSync(path.join(barrier,'result-L'),'utf8')).toBe('success');expect(await winnerDone).toBe(0);process.kill(loser.pid!,'SIGCONT');await waitForPath(path.join(barrier,'result-H'));expect(fs.readFileSync(path.join(barrier,'result-H'),'utf8')).toBe('INSUFFICIENT_CAPACITY');expect(await loserDone).toBe(0);expect(fs.existsSync(path.join(barrier,'overlap'))).toBe(false);expect(fs.readdirSync(path.join(dir,'.mutation-lock-leases'))).toEqual([]);}finally{stopChildren(children);}});
|
|
test('a paused later contender cannot turn a cached lower ticket into an all-loser outcome',async()=>{if(process.platform==='win32')return;const dir=tmp(),barrier=path.join(dir,'barrier'),script=path.join(dir,'contender.ts');fs.mkdirSync(barrier);expect(withLock(dir,()=>1)).toBe(1);fs.writeFileSync(script,leaseContenderSource());const env={...process.env,RACE_DIR:dir,BARRIER:barrier},children:Array<ReturnType<typeof spawn>>=[];try{const earlier=spawn(process.execPath,[script],{env:{...env,RACE_ID:'L',RACE_MODE:'wait-active',RACE_HOLD:'1'},stdio:'ignore'});children.push(earlier);const earlierDone=childExit(earlier);await waitForPath(path.join(barrier,'doorway-L'));const later=spawn(process.execPath,[script],{env:{...env,RACE_ID:'H',RACE_MODE:'pause-later-scan'},stdio:'ignore'});children.push(later);const laterDone=childExit(later);await waitForPath(path.join(barrier,'paused-H'));await waitForPath(path.join(barrier,'entered-L'));process.kill(later.pid!,'SIGCONT');await waitForPath(path.join(barrier,'result-H'),2500);expect(fs.readFileSync(path.join(barrier,'result-H'),'utf8')).toBe('INSUFFICIENT_CAPACITY');expect(await laterDone).toBe(0);fs.writeFileSync(path.join(barrier,'release-L'),'release');await waitForPath(path.join(barrier,'result-L'));expect(fs.readFileSync(path.join(barrier,'result-L'),'utf8')).toBe('success');expect(await earlierDone).toBe(0);expect(fs.existsSync(path.join(barrier,'overlap'))).toBe(false);expect(fs.readdirSync(path.join(dir,'.mutation-lock-leases'))).toEqual([]);}finally{stopChildren(children);}});
|
|
test('legacy report imports expire after thirty days without following links',()=>{const old=process.env.GSTACK_HOME,base=tmp();process.env.GSTACK_HOME=base;try{const archive=secureDirectory(path.join(base,'security','cso','legacy-imports')),expired=path.join(archive,'a'.repeat(64)+'.json'),retained=path.join(archive,'b'.repeat(64)+'.json');fs.writeFileSync(expired,'{}');fs.writeFileSync(retained,'{}');const now=Date.now();fs.utimesSync(expired,new Date(now-31*86400_000),new Date(now-31*86400_000));retention(now);expect(fs.existsSync(expired)).toBe(false);expect(fs.existsSync(retained)).toBe(true);const unsafe=path.join(archive,'c'.repeat(64)+'.json');fs.symlinkSync(retained,unsafe);expect(()=>retention(now)).toThrow('unsafe artifact');expect(fs.readFileSync(retained,'utf8')).toBe('{}');}finally{if(old===undefined)delete process.env.GSTACK_HOME;else process.env.GSTACK_HOME=old;}});
|
|
test('an active recheck pins only its expired parent report, never expired repair material',()=>{const now=Date.now(),repo='f'.repeat(24),oldRun=`${now-31*86400_000}-${'a'.repeat(16)}`,childRun=`${now}-${'b'.repeat(16)}`,findingId='c'.repeat(32),repoDir=secureDirectory(path.join(privateRoot(),repo)),parent=secureDirectory(path.join(repoDir,oldRun)),child=secureDirectory(path.join(repoDir,childRun)),bundles=secureDirectory(path.join(parent,'bundles')),reviews=secureDirectory(path.join(parent,'reviews')),attempts=secureDirectory(path.join(parent,'verification-attempts'));writeHelperJson(path.join(parent,'report.json'),{schemaVersion:3,runId:oldRun,repoId:repo,status:'finished',coverage:[],findings:[{id:findingId}]});writeJson(path.join(bundles,'bundle.json'),{schemaVersion:3});writeJson(path.join(reviews,'review.json'),{schemaVersion:3});writeJson(path.join(attempts,'attempt.json'),{schemaVersion:3});writeHelperJson(path.join(child,'report.json'),{schemaVersion:3,runId:childRun,repoId:repo,status:'running',deadline:new Date(now+60_000).toISOString(),coverage:[],findings:[],parent:{runId:oldRun,findingId,kind:'recheck'}});retention(now);expect(fs.existsSync(path.join(parent,'report.json'))).toBe(true);expect(fs.existsSync(bundles)).toBe(false);expect(fs.existsSync(reviews)).toBe(false);expect(fs.existsSync(attempts)).toBe(false);fs.rmSync(child,{recursive:true});retention(now);expect(fs.existsSync(parent)).toBe(false);});
|
|
test('finished, expired, and malformed child reports cannot extend parent retention',()=>{const now=Date.now(),repo='e'.repeat(24),repoDir=secureDirectory(path.join(privateRoot(),repo)),findingId='d'.repeat(32);for(const [index,childValue] of [[0,{status:'finished',repoId:repo,deadline:new Date(now+60_000).toISOString()}],[1,{status:'running',repoId:repo,deadline:new Date(now-1).toISOString()}],[2,{status:'running',repoId:'0'.repeat(24),deadline:new Date(now+60_000).toISOString()}]] as const){const parentRun=`${now-(31+index)*86400_000}-${String(index+1).repeat(16)}`,childRun=`${now-index}-${String(index+4).repeat(16)}`,parent=secureDirectory(path.join(repoDir,parentRun)),child=secureDirectory(path.join(repoDir,childRun));writeHelperJson(path.join(parent,'report.json'),{schemaVersion:3,runId:parentRun,repoId:repo,status:'finished',coverage:[],findings:[{id:findingId}]});writeHelperJson(path.join(child,'report.json'),{schemaVersion:3,runId:childRun,repoId:childValue.repoId,status:childValue.status,deadline:childValue.deadline,coverage:[],findings:[],parent:{runId:parentRun,findingId,kind:'recheck'}});}retention(now);for(const name of fs.readdirSync(repoDir).filter(name=>Number(name.split('-')[0])<now-30*86400_000))expect(fs.existsSync(path.join(repoDir,name))).toBe(false);});
|
|
});
|