import { afterAll, beforeAll, describe, expect, test } from 'bun:test'; import * as fs from 'node:fs'; import * as os from 'node:os'; import * as path from 'node:path'; import { createHash } from 'node:crypto'; import { spawn, spawnSync } from 'node:child_process'; const ROOT = path.resolve(import.meta.dir, '..'); const windows = process.platform === 'win32'; const required = process.env.GSTACK_CSO_WINDOWS_TESTS === '1'; if (required && !windows) throw new Error('GSTACK_CSO_WINDOWS_TESTS=1 requires native Windows; emulation does not qualify the launcher.'); let temporary = '', invocationCwd = '', launcher = '', core = '', marker = '', preload = '', publisher = '', buildStage = ''; beforeAll(() => { if (!windows) return; const installed = path.join(ROOT, 'bin', 'gstack-cso-launcher.exe'); if (!fs.existsSync(installed)) throw new Error('Native CSO launcher is missing; run bun run build:cso with MSVC first.'); temporary = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'CSO launcher 空間 ')); launcher = path.join(temporary, 'gstack-cso-launcher.exe'); core = path.join(temporary, 'gstack-cso-core.exe'); invocationCwd = path.join(temporary, 'audited cwd'); fs.mkdirSync(invocationCwd); marker = path.join(temporary, 'preload-ran'); preload = path.join(temporary, 'preload.ts'); fs.writeFileSync(preload, `import {writeFileSync} from 'node:fs'; writeFileSync(${JSON.stringify(marker)}, 'startup injection');`); const source = path.join(temporary, 'core-fixture.ts'); fs.writeFileSync(source, `import {existsSync,writeFileSync} from 'node:fs'; const hold=process.argv.indexOf('--hold-until'); if(hold>=0){writeFileSync(process.argv[hold+1],String(process.pid));while(!existsSync(process.argv[hold+2]))await Bun.sleep(10);writeFileSync(process.argv[hold+3],'exited');} process.stdout.write(JSON.stringify({argv:process.argv.slice(2),env:process.env,cwd:process.cwd()})); if(process.argv.includes('--exit-23'))process.exit(23);`); const compiled = spawnSync(process.execPath, ['build', '--compile', '--no-compile-autoload-dotenv', '--no-compile-autoload-bunfig', '--no-compile-autoload-tsconfig', '--no-compile-autoload-package-json', source, '--outfile', core], { encoding: 'utf8', timeout: 60_000 }); expect(compiled.status).toBe(0); const digest = createHash('sha256').update(fs.readFileSync(core)).digest('hex'); buildStage = fs.mkdtempSync(path.join(ROOT, 'bin', '.gstack-cso-stage.windows-launcher-test.')); const stagedLauncher = path.join(buildStage, 'gstack-cso-launcher.exe'); const stagedPublisher = path.join(buildStage, 'gstack-cso-publish-lock.exe'); const native = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', path.join(ROOT, 'scripts', 'build-cso-windows.ps1'), '-RepoRoot', ROOT, '-OutputPath', stagedLauncher, '-LockOutputPath', stagedPublisher, '-CoreSha256', digest, '-GitExePath', Bun.which('git')!], { encoding: 'utf8', timeout: 60_000 }); if (native.status !== 0) throw new Error(`Fixture launcher compilation failed: ${native.stdout}${native.stderr}`); fs.copyFileSync(stagedLauncher, launcher); publisher = path.join(temporary, 'gstack-cso-publish-lock.exe'); fs.copyFileSync(stagedPublisher, publisher); fs.writeFileSync(path.join(temporary, '.gstack-cso-generation.lock'), ''); fs.writeFileSync(path.join(temporary, '.gstack-cso-generation'), `${digest}\n`); fs.rmSync(buildStage, { recursive: true, force: true }); buildStage = ''; }, 140_000); afterAll(() => { if (buildStage) fs.rmSync(buildStage, { recursive: true, force: true }); if (temporary) fs.rmSync(temporary, { recursive: true, force: true }); }); function launchEnvironment(extra: Record = {}) { return { ...process.env, HOME: temporary, GSTACK_HOME: path.join(temporary, 'state'), PATH: temporary, NODE_OPTIONS: '--require=hostile', RUBYOPT: '-rhostile', PYTHONPATH: temporary, GSTACK_CSO_SECRET_CANARY: 'must-not-cross-startup', ...extra }; } function launch(args: string[], extra: Record = {}, file = launcher) { return spawnSync(file, args, { cwd: invocationCwd, encoding: 'utf8', timeout: 30_000, env: launchEnvironment(extra), }); } async function waitForFile(file: string, timeout = 10_000) { const deadline = Date.now() + timeout; while (!fs.existsSync(file) && Date.now() < deadline) await Bun.sleep(10); expect(fs.existsSync(file)).toBe(true); } function publishProbe() { return spawnSync(publisher, [temporary, process.execPath, '--version'], { encoding: 'utf8', timeout: 10_000 }); } function pathIdentity(value: string) { const stat = fs.statSync(value, { bigint: true }); return { device: stat.dev, file: stat.ino }; } function expectSuccessfulProcess(result: ReturnType, label: string) { if (result.status === 0) return; const bounded = (value: unknown) => String(value ?? '').slice(0, 8192); throw new Error(`${label} failed: ${JSON.stringify({ status: result.status, signal: result.signal, error: result.error?.message, stdout: bounded(result.stdout), stderr: bounded(result.stderr), })}`); } function filesNamed(root: string, name: string): string[] { const found: string[] = []; const walk = (directory: string) => { let entries: fs.Dirent[]; try { entries = fs.readdirSync(directory, { withFileTypes: true }); } catch { return; } for (const entry of entries) { const candidate = path.join(directory, entry.name); if (entry.isSymbolicLink()) continue; if (entry.isDirectory()) walk(candidate); else if (entry.isFile() && entry.name === name) found.push(candidate); } }; walk(root); return found; } describe('CSO native Windows build contract', () => { test('Windows builds use MSVC with a static CRT and no Bun-hosted public launcher', () => { const build = fs.readFileSync(path.join(ROOT, 'scripts/build-cso.sh'), 'utf8'); const msvc = fs.readFileSync(path.join(ROOT, 'scripts/build-cso-windows.ps1'), 'utf8'); expect(build).toContain('powershell.exe -NoProfile -NonInteractive'); expect(build).toContain('build-cso-windows.ps1'); expect(build).toContain('-OutputPath "$(cygpath -w "$CSO_STAGE_LAUNCHER")"'); expect(build).toContain('-LockOutputPath "$(cygpath -w "$CSO_STAGE_LOCKER")"'); expect(build).toContain('-CoreSha256 "$CSO_CORE_SHA256"'); expect(build).toContain('-GitExePath "$(cygpath -aw "$CSO_WINDOWS_GIT")"'); expect(build).toContain('CSO_PUBLISH_SHELL="$(cygpath -aw /usr/bin/bash.exe)"'); expect(build).not.toContain('launcher-windows.ts'); expect(fs.existsSync(path.join(ROOT, 'lib/cso/launcher-windows.ts'))).toBe(false); expect(msvc).toContain('Launch-VsDevShell.ps1'); expect(msvc).toContain('[switch]$CheckOnly'); expect(msvc).toContain('Normal CSO Windows builds require staged outputs and a lowercase SHA-256 core binding.'); expect(msvc).toContain("[System.IO.FileAttributes]::ReparsePoint"); expect(msvc).not.toContain("Join-Path $RepoRoot 'bin\\gstack-cso-launcher.exe'"); expect(msvc).toContain("Set-Content -LiteralPath $source"); expect(msvc).toContain('-Arch amd64 -HostArch amd64 -SkipAutomaticLocation'); expect(msvc).toContain('StartsWith($installationPrefix'); expect(msvc).toContain('/MT'); expect(msvc).toContain('/W4 /WX'); expect(msvc).toContain('GSTACK_CSO_CORE_SHA256'); expect(msvc).toContain('GSTACK_CSO_GIT_PATH'); expect(msvc).toContain('/FI$binding'); expect(msvc).toContain('if ($LASTEXITCODE -ne 0)'); const processSource=fs.readFileSync(path.join(ROOT,'lib','cso','process.ts'),'utf8'); expect(processSource).toContain("includeNullPath=process.platform==='win32'?'/dev/null':nullPath"); const launcherSource = fs.readFileSync(path.join(ROOT, 'lib/cso/launcher-windows.c'), 'utf8'); expect(launcherSource).toContain('.gstack-cso-generation.lock'); expect(launcherSource).toContain('.gstack-cso-generation'); expect(launcherSource).toContain('GSTACK_CSO_CORE_SHA256'); expect(launcherSource).toContain('BCryptOpenAlgorithmProvider'); expect(launcherSource).toContain('MS_PRIMITIVE_PROVIDER'); expect(launcherSource).toContain('sha256_handle(pinned_core'); expect(launcherSource).toContain('#pragma comment(lib, "bcrypt.lib")'); expect(launcherSource).toContain('PROC_THREAD_ATTRIBUTE_HANDLE_LIST'); expect(launcherSource).toContain('joined_path'); const childWait = launcherSource.indexOf('WaitForSingleObject(child.hProcess, INFINITE)'); expect(childWait).toBeGreaterThan(0); expect(launcherSource.lastIndexOf('CloseHandle(pinned_core)')).toBeGreaterThan(childWait); expect(launcherSource.lastIndexOf('CloseHandle(generation_gate)')).toBeGreaterThan(childWait); const publisherSource = fs.readFileSync(path.join(ROOT, 'lib/cso/publish-lock.c'), 'utf8'); expect(publisherSource).toContain('joined_path'); expect(publisherSource).toContain('GENERIC_READ | GENERIC_WRITE, 0'); }); test('Windows CI runs the actual launcher tests rather than marking the platform supported from a source check', () => { const workflow = Bun.YAML.parse(fs.readFileSync(path.join(ROOT, '.github/workflows/free-tests.yml'), 'utf8')) as any; const job = workflow.jobs['cso-windows-launcher']; expect(job['runs-on']).toBe('windows-latest'); expect(job.steps.some((s: any) => s.run === 'bun run build:cso' && s.shell === 'bash')).toBe(true); const smoke = job.steps.find((s: any) => s.run === 'bun run test:cso:windows'); expect(smoke.env.GSTACK_CSO_WINDOWS_TESTS).toBe('1'); expect(smoke['continue-on-error']).not.toBe(true); }); // Each PowerShell invocation has its own deadline. A serial loop placed all // five cold starts under Bun's default five-second timeout. const pathEscapeCases = [ ['launcher outside stage', (stage: string, outside: string) => [path.join(outside, 'gstack-cso-launcher.exe'), path.join(stage, 'gstack-cso-publish-lock.exe')]], ['launcher in stage parent', (stage: string) => [path.join(stage, '..', 'gstack-cso-launcher.exe'), path.join(stage, 'gstack-cso-publish-lock.exe')]], ['wrong launcher name', (stage: string) => [path.join(stage, 'wrong.exe'), path.join(stage, 'gstack-cso-publish-lock.exe')]], ['lock outside stage', (stage: string, outside: string) => [path.join(stage, 'gstack-cso-launcher.exe'), path.join(outside, 'gstack-cso-publish-lock.exe')]], ['wrong lock name', (stage: string) => [path.join(stage, 'gstack-cso-launcher.exe'), path.join(stage, 'wrong-lock.exe')]], ] as const; test.skipIf(!windows).each(pathEscapeCases)('Windows build rejects %s before invoking MSVC',(_name, outputs)=>{ const script=path.join(ROOT,'scripts/build-cso-windows.ps1'),outside=fs.mkdtempSync(path.join(os.tmpdir(),'cso-bin-evil-')); const stage=fs.mkdtempSync(path.join(ROOT,'bin','.gstack-cso-stage.path-test.')); const [output,lock]=outputs(stage,outside),digest='a'.repeat(64); try{ const result=spawnSync('powershell.exe',['-NoProfile','-NonInteractive','-ExecutionPolicy','Bypass','-File',script,'-RepoRoot',ROOT,'-OutputPath',output,'-LockOutputPath',lock,'-CoreSha256',digest,'-GitExePath',Bun.which('git')!],{encoding:'utf8',timeout:30_000}); expect(result.error).toBeUndefined();expect(result.signal).toBeNull();expect(result.status).not.toBeNull(); expect(result.status).not.toBe(0);expect(`${result.stdout}${result.stderr}`).toContain('direct, non-reparse staging directory'); }finally{fs.rmSync(stage,{recursive:true,force:true});fs.rmSync(outside,{recursive:true,force:true});} },35_000); }); (windows ? describe : describe.skip)('CSO native Windows startup', () => { test('BUN_OPTIONS cannot execute a preload before the environment is scrubbed', () => { const result = launch(['--version'], { BUN_OPTIONS: `--preload=${preload}` }); expect(result.status).toBe(0); expect(fs.existsSync(marker)).toBe(false); const value = JSON.parse(result.stdout); expect(value.argv).toEqual(['--version']); expect(value.env.BUN_OPTIONS).toBeUndefined(); expect(value.env.GSTACK_CSO_SECRET_CANARY).toBeUndefined(); expect(value.env.NODE_OPTIONS).toBeUndefined(); expect(value.env.GSTACK_HOME).toBe(path.join(temporary, 'state')); expect(value.env.PATH).not.toBe(temporary); expect(value.env.SystemRoot.toLowerCase()).toBe(process.env.SystemRoot!.toLowerCase()); expect(pathIdentity(value.cwd)).toEqual(pathIdentity(temporary)); expect(pathIdentity(value.cwd)).not.toEqual(pathIdentity(invocationCwd)); }); test('BUN_BE_BUN cannot turn the public command into the Bun runtime', () => { const result = launch(['--version'], { BUN_BE_BUN: '1' }); expect(result.status).toBe(0); const value = JSON.parse(result.stdout); expect(value.argv).toEqual(['--version']); expect(value.env.BUN_BE_BUN).toBeUndefined(); }); test('preserves Unicode, empty, quoted, trailing-backslash and shell-looking arguments', () => { const args = ['', '空間', 'with spaces', 'a"b', 'C:\\directory with spaces\\', '\\"', '& whoami', '%PATH%', 'line\nbreak']; const result = launch(args); expect(result.status).toBe(0); expect(JSON.parse(result.stdout).argv).toEqual(args); }); test('forwards child exit status and fails closed on oversized inherited input', () => { expect(launch(['--exit-23']).status).toBe(23); const result = launch([], { GSTACK_HOME: 'x'.repeat(8193) }); expect(result.status).toBe(69); expect(result.stdout).toBe(''); expect(result.stderr).toContain('environment input is too large'); }); test('resolves launcher installation aliases before locating its sibling core', () => { const alias = path.join(temporary, 'alias'); fs.symlinkSync(temporary, alias, 'junction'); const result = launch(['--version'], {}, path.join(alias, 'gstack-cso-launcher.exe')); expect(result.status).toBe(0); expect(JSON.parse(result.stdout).argv).toEqual(['--version']); fs.unlinkSync(alias); }); test('rejects a launcher/manifest generation mismatch before executing the core', () => { const mismatched = path.join(temporary, 'mismatched generation'); fs.mkdirSync(mismatched); fs.copyFileSync(launcher, path.join(mismatched, 'gstack-cso-launcher.exe')); fs.copyFileSync(core, path.join(mismatched, 'gstack-cso-core.exe')); fs.writeFileSync(path.join(mismatched, '.gstack-cso-generation.lock'), ''); fs.writeFileSync(path.join(mismatched, '.gstack-cso-generation'), `${'0'.repeat(64)}\n`); const result = launch(['--version'], {}, path.join(mismatched, 'gstack-cso-launcher.exe')); expect(result.status).toBe(69); expect(result.stdout).toBe(''); expect(result.stderr).toContain('generations do not match'); }); test('rejects changed core bytes even when the generation manifest is unchanged', () => { const tampered = path.join(temporary, 'tampered core'); fs.mkdirSync(tampered); const tamperedLauncher = path.join(tampered, 'gstack-cso-launcher.exe'); const tamperedCore = path.join(tampered, 'gstack-cso-core.exe'); fs.copyFileSync(launcher, tamperedLauncher); fs.copyFileSync(core, tamperedCore); fs.appendFileSync(tamperedCore, Buffer.from([0])); fs.writeFileSync(path.join(tampered, '.gstack-cso-generation.lock'), ''); fs.copyFileSync(path.join(temporary, '.gstack-cso-generation'), path.join(tampered, '.gstack-cso-generation')); const result = launch(['--version'], {}, tamperedLauncher); expect(result.status).toBe(69); expect(result.stdout).toBe(''); expect(result.stderr).toContain('digest does not match'); }); test('the inherited generation gate survives launcher termination until the core exits', async () => { const ready = path.join(temporary, 'held-core.ready'), release = path.join(temporary, 'held-core.release'), exited = path.join(temporary, 'held-core.exited'); const running = spawn(launcher, ['--hold-until', ready, release, exited], { cwd: invocationCwd, env: launchEnvironment(), stdio: 'ignore' }); try { await waitForFile(ready); const launcherExited = new Promise(resolveExit => running.once('exit', () => resolveExit())); running.kill('SIGKILL'); await launcherExited; expect(publishProbe().status).toBe(73); fs.writeFileSync(release, 'release'); const deadline = Date.now() + 10_000; let result = publishProbe(); while (result.status === 73 && Date.now() < deadline) { await Bun.sleep(20); result = publishProbe(); } expect(result.status).toBe(0); } finally { fs.writeFileSync(release, 'release'); if (!running.killed) running.kill('SIGKILL'); const deadline = Date.now() + 5_000; while (!fs.existsSync(exited) && Date.now() < deadline) await Bun.sleep(10); } }, 30_000); test('a missing core never falls back to a PATH executable or Bun', () => { const missing = path.join(temporary, 'missing core'); fs.mkdirSync(missing); const copy = path.join(missing, 'gstack-cso-launcher.exe'); fs.copyFileSync(launcher, copy); fs.writeFileSync(path.join(missing, '.gstack-cso-generation.lock'), ''); fs.copyFileSync(path.join(temporary, '.gstack-cso-generation'), path.join(missing, '.gstack-cso-generation')); const result = launch(['--version'], {}, copy); expect(result.status).toBe(69); expect(result.stdout).toBe(''); expect(result.stderr).toContain('trusted compiled helper is missing'); }); test('the actual helper finds trusted Git and stores state under USERPROFILE without HOME', () => { const repository=path.join(temporary,'actual repository'),profile=path.join(temporary,'profile'); fs.mkdirSync(repository);fs.mkdirSync(profile); const git='C:\\Program Files\\Git\\cmd\\git.exe',gitEnv={...process.env,HOME:profile}; for(const args of [['init','-q'],['config','user.email','fixture@example.test'],['config','user.name','Fixture']] as string[][]){const result=spawnSync(git,args,{cwd:repository,encoding:'utf8',env:gitEnv,timeout:10_000});expect(result.status).toBe(0);} fs.writeFileSync(path.join(repository,'app.js'),'console.log("safe")\n'); for(const args of [['add','app.js'],['commit','-qm','fixture']] as string[][]){const result=spawnSync(git,args,{cwd:repository,encoding:'utf8',env:gitEnv,timeout:10_000});expect(result.status).toBe(0);} const actual=path.join(ROOT,'bin','gstack-cso-launcher.exe'),env={...process.env,HOME:'',GSTACK_HOME:'',CLAUDE_PLUGIN_ROOT:'',CLAUDE_PLUGIN_DATA:'',USERPROFILE:profile,PATH:temporary,NODE_OPTIONS:'--require=hostile'}; const doctor=spawnSync(actual,['doctor','--repo',repository],{cwd:repository,encoding:'utf8',env,timeout:30_000});expect(doctor.status).toBe(0);expect(JSON.parse(doctor.stdout).downloads).toBe(false); const started=spawnSync(actual,['start','--repo',repository,'--offline'],{cwd:repository,encoding:'utf8',env,timeout:30_000});expectSuccessfulProcess(started,'gstack-cso start');expect(JSON.parse(started.stdout).schemaVersion).toBe(3);expect(fs.existsSync(path.join(profile,'.gstack','security','cso'))).toBe(true); }, 120_000); test('NTFS high file IDs survive repeated native commands and ambiguous old decisions remain blocked', () => { const repository=path.join(temporary,'lease lifecycle repository'),profile=path.join(temporary,'lease lifecycle profile'); fs.mkdirSync(repository);fs.mkdirSync(profile); const git='C:\\Program Files\\Git\\cmd\\git.exe',gitEnv={...process.env,HOME:profile}; for(const args of [['init','-q'],['config','user.email','fixture@example.test'],['config','user.name','Fixture']] as string[][]){const result=spawnSync(git,args,{cwd:repository,encoding:'utf8',env:gitEnv,timeout:10_000});expect(result.status).toBe(0);} fs.writeFileSync(path.join(repository,'app.js'),'console.log("fixture")\n'); for(const args of [['add','app.js'],['commit','-qm','fixture']] as string[][]){const result=spawnSync(git,args,{cwd:repository,encoding:'utf8',env:gitEnv,timeout:10_000});expect(result.status).toBe(0);} const actual=path.join(ROOT,'bin','gstack-cso-launcher.exe'),env={...process.env,HOME:'',GSTACK_HOME:'',CLAUDE_PLUGIN_ROOT:'',CLAUDE_PLUGIN_DATA:'',USERPROFILE:profile,PATH:temporary}; const command=(args:string[])=>spawnSync(actual,args,{cwd:repository,encoding:'utf8',env,timeout:30_000}),submission=path.join(profile,'submission.json'); fs.writeFileSync(submission,'{}\n'); for(let i=0;i<3;i++){ const started=command(['start','--repo',repository,'--offline']);expectSuccessfulProcess(started,'gstack-cso start'); const run=JSON.parse(started.stdout),dir=path.join(profile,'.gstack','security','cso',run.repoId,run.runId),leases=path.join(dir,'.mutation-lock-leases'); const initialized=command(['resume',run.runId]);expectSuccessfulProcess(initialized,'gstack-cso initialize mutation lease'); expect(fs.realpathSync(leases).startsWith(fs.realpathSync(profile)+path.sep)).toBe(true); if(i===0){ const churn=path.join(leases,'churn');let inode=0n; for(let attempt=0;attempt<1024;attempt++){ fs.writeFileSync(churn,'x');inode=fs.lstatSync(churn,{bigint:true}).ino;fs.unlinkSync(churn); if(inode>BigInt(Number.MAX_SAFE_INTEGER))break; } expect(inode).toBeGreaterThan(BigInt(Number.MAX_SAFE_INTEGER)); } const inspected=command(['inspect',run.runId]);expectSuccessfulProcess(inspected,'gstack-cso inspect'); expect(JSON.parse(inspected.stdout).report.status).toBe('running'); const read=command(['read',run.runId,'app.js']);expectSuccessfulProcess(read,'gstack-cso read');expect(read.stdout).toContain('fixture'); const history=command(['history',run.runId]);expectSuccessfulProcess(history,'gstack-cso history'); const submitted=command(['submit',run.runId,submission]);expectSuccessfulProcess(submitted,'gstack-cso submit'); const resumed=command(['resume',run.runId]);expectSuccessfulProcess(resumed,'gstack-cso resume'); const finished=command(['finish',run.runId]);expectSuccessfulProcess(finished,'gstack-cso finish'); expect(JSON.parse(finished.stdout).completeness).not.toBe('complete'); const report=JSON.parse(fs.readFileSync(path.join(dir,'report.json'),'utf8')); expect(report.coverage.some((entry:any)=>entry.status==='not_assessed')).toBe(true); expect(fs.readdirSync(leases)).toEqual([]); if(i!==2)continue; const token='d'.repeat(32),candidate=path.join(leases,`${token}.json`),decision=path.join(leases,`${token}.decision`); for(const rounded of [false,true]){ let selected:string|undefined; for(let batch=0;batch<16&&!selected;batch++){ const paths:string[]=[]; for(let index=0;index<64;index++){ const file=path.join(leases,`fixture-${batch}-${index}`); fs.writeFileSync(file,JSON.stringify({pid:2147483647,token,createdAt:0})+'\n');paths.push(file); const inode=fs.lstatSync(file,{bigint:true}).ino; if(!selected&&inode>BigInt(Number.MAX_SAFE_INTEGER)&&String(Number(inode))!==String(inode))selected=file; } for(const file of paths){if(file===selected)fs.renameSync(file,candidate);else fs.unlinkSync(file);} } expect(selected).toBeDefined(); const stat=fs.lstatSync(candidate,{bigint:true}),record={schemaVersion:1,token,kind:'ticket',ticket:'0000000000000001',candidateDev:String(stat.dev),candidateIno:rounded?String(Number(stat.ino)):String(stat.ino),ownerPid:2147483647,ownerCreatedAt:0,publisherPid:2147483647,createdAt:0}; fs.writeFileSync(decision,JSON.stringify(record)+'\n'); const result=command(['resume',run.runId]);expect(result.status).not.toBe(0); if(rounded){ expect(record.candidateIno).not.toBe(String(stat.ino));expect(result.stderr).toContain('UNSAFE_PATH'); expect(fs.existsSync(candidate)).toBe(true);expect(fs.existsSync(decision)).toBe(true); fs.unlinkSync(decision);fs.unlinkSync(candidate); }else{ expect(result.stderr).toContain('INVALID_SCHEMA'); expect(fs.existsSync(candidate)).toBe(false);expect(fs.existsSync(decision)).toBe(false); } } const next=command(['start','--repo',repository,'--offline']);expectSuccessfulProcess(next,'gstack-cso start after legacy state'); expect(JSON.parse(next.stdout).runId).not.toBe(run.runId); } }, 180_000); test('the actual helper rejects source mutation during snapshot capture without certifying a report', async () => { const repository=path.join(temporary,'racing repository'),profile=path.join(temporary,'race profile'),padding=path.join(repository,'padding'),target=path.join(repository,'zzzz-race-target.js'); fs.mkdirSync(repository);fs.mkdirSync(profile);fs.mkdirSync(padding); const git='C:\\Program Files\\Git\\cmd\\git.exe',gitEnv={...process.env,HOME:profile}; for(const args of [['init','-q'],['config','user.email','fixture@example.test'],['config','user.name','Fixture']] as string[][]){const result=spawnSync(git,args,{cwd:repository,encoding:'utf8',env:gitEnv,timeout:10_000});expect(result.status).toBe(0);} const sourceBytes=128*1024,stable=Buffer.alloc(sourceBytes,0x61),changed=Buffer.alloc(sourceBytes,0x62); fs.writeFileSync(target,stable); for(let index=0;index<192;index++)fs.writeFileSync(path.join(padding,`${String(index).padStart(4,'0')}.js`),stable); for(const args of [['add',path.basename(target)],['commit','-qm','fixture']] as string[][]){const result=spawnSync(git,args,{cwd:repository,encoding:'utf8',env:gitEnv,timeout:30_000});expect(result.status).toBe(0);} const actual=path.join(ROOT,'bin','gstack-cso-launcher.exe'),env={...process.env,HOME:'',GSTACK_HOME:'',CLAUDE_PLUGIN_ROOT:'',CLAUDE_PLUGIN_DATA:'',USERPROFILE:profile,PATH:temporary},state=path.join(profile,'.gstack','security','cso'); const child=spawn(actual,['start','--repo',repository,'--offline'],{cwd:repository,env,stdio:['ignore','pipe','pipe']}); let stdout='',stderr='',closed=false; child.stdout.on('data',chunk=>{stdout=(stdout+String(chunk)).slice(-8192);}); child.stderr.on('data',chunk=>{stderr=(stderr+String(chunk)).slice(-8192);}); const terminal=new Promise<{code:number|null;error?:string}>(resolve=>{ child.once('error',error=>{closed=true;resolve({code:null,error:error.message});}); child.once('close',code=>{closed=true;resolve({code});}); }); const markerDeadline=Date.now()+30_000;let mutations=0,outcome:{code:number|null;error?:string}|undefined; try{ while(!closed&&!filesNamed(state,'history-status.json').length&&Date.now()