From 8b3de601e171c7b2c600ee5d28fc40c6c75aefd7 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 31 Oct 2026 18:52:58 +0000 Subject: [PATCH 1/2] test(cso): fixtureGit throws when git is killed or cannot start (#3476) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- changelog.d/gsta-217-fixturegit-status.md | 4 ++++ test/cso-git-hardening.test.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changelog.d/gsta-217-fixturegit-status.md diff --git a/changelog.d/gsta-217-fixturegit-status.md b/changelog.d/gsta-217-fixturegit-status.md new file mode 100644 index 000000000..bb1bc02d1 --- /dev/null +++ b/changelog.d/gsta-217-fixturegit-status.md @@ -0,0 +1,4 @@ +**A CSO hardening test now fails at the Git step that broke instead of passing without testing anything.** `fixtureGit` in `test/cso-git-hardening.test.ts` threw only on a non-zero exit status. When Git was killed by its 30-second timeout or could not start, `spawnSync` returned a `null` status, and the helper treated that as success. If that happened to the `git replace` step, the test that checks a security snapshot ignores replaced history would pass without a replacement in place. The helper now throws on a spawn error or any status other than 0, and the message names the Git arguments, the status and the signal. + +### Tests +- `test/cso-git-hardening.test.ts`: `fixtureGit` throws on `result.error` or `status !== 0` (#3476). diff --git a/test/cso-git-hardening.test.ts b/test/cso-git-hardening.test.ts index 7c6d3eb96..5bf3f1657 100644 --- a/test/cso-git-hardening.test.ts +++ b/test/cso-git-hardening.test.ts @@ -9,7 +9,7 @@ import { childEnvironment, executable, git as readGitMetadata, runProcess } from const roots:string[]=[]; afterEach(()=>{for(const root of roots.splice(0))fs.rmSync(root,{recursive:true,force:true});}); -const fixtureGit=(repo:string,home:string)=>(...args:string[])=>{const result=spawnSync('/usr/bin/git',['-C',repo,...args],{encoding:'utf8',env:{HOME:home,PATH:'/usr/bin:/bin'},timeout:30_000});if(result.status)throw new Error(result.stderr);return result.stdout;}; +const fixtureGit=(repo:string,home:string)=>(...args:string[])=>{const result=spawnSync('/usr/bin/git',['-C',repo,...args],{encoding:'utf8',env:{HOME:home,PATH:'/usr/bin:/bin'},timeout:30_000});if(result.error||result.status!==0)throw new Error(`fixture git ${args.join(' ')} failed (status ${result.status}, signal ${result.signal}): ${result.error?.message??result.stderr}`);return result.stdout;}; // Each fixture builds its own repository from Git; nothing is copied from a shared // template (Free Tests 40288142343 shard 17: fs.cpSync of the template threw inside // its directory walk once and passed on the serial retry). Auto-maintenance is off From a3e3228b4ddc58b8559d285fd83d7396e090677a Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 31 Oct 2026 20:55:48 +0000 Subject: [PATCH 2/2] test(cso): skip the git warm-up on Windows, where every test in the file already skips Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- changelog.d/gsta-217-fixturegit-status.md | 4 ++-- test/cso-git-hardening.test.ts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/changelog.d/gsta-217-fixturegit-status.md b/changelog.d/gsta-217-fixturegit-status.md index bb1bc02d1..5670ac788 100644 --- a/changelog.d/gsta-217-fixturegit-status.md +++ b/changelog.d/gsta-217-fixturegit-status.md @@ -1,4 +1,4 @@ -**A CSO hardening test now fails at the Git step that broke instead of passing without testing anything.** `fixtureGit` in `test/cso-git-hardening.test.ts` threw only on a non-zero exit status. When Git was killed by its 30-second timeout or could not start, `spawnSync` returned a `null` status, and the helper treated that as success. If that happened to the `git replace` step, the test that checks a security snapshot ignores replaced history would pass without a replacement in place. The helper now throws on a spawn error or any status other than 0, and the message names the Git arguments, the status and the signal. +**A CSO hardening test now fails at the Git step that broke instead of passing without testing anything.** `fixtureGit` in `test/cso-git-hardening.test.ts` threw only on a non-zero exit status. When Git was killed by its 30-second timeout or could not start, `spawnSync` returned a `null` status, and the helper treated that as success. If that happened to the `git replace` step, the test that checks a security snapshot ignores replaced history would pass without a replacement in place. The helper now throws on a spawn error or any status other than 0, and the message names the Git arguments, the status and the signal. The stricter helper showed that the file's warm-up step had been calling `/usr/bin/git` on Windows, where it doesn't exist, on every run. It was passing only because the error was swallowed. Every test in the file already skips on Windows, so the warm-up now skips there too. ### Tests -- `test/cso-git-hardening.test.ts`: `fixtureGit` throws on `result.error` or `status !== 0` (#3476). +- `test/cso-git-hardening.test.ts`: `fixtureGit` throws on `result.error` or `status !== 0` (#3476), and the `beforeAll` warm-up returns early on Windows (Windows Free Tests run 41236157469 failed in it with `ENOENT … uv_spawn '/usr/bin/git'` once the error stopped being swallowed). diff --git a/test/cso-git-hardening.test.ts b/test/cso-git-hardening.test.ts index 5bf3f1657..99021e7d4 100644 --- a/test/cso-git-hardening.test.ts +++ b/test/cso-git-hardening.test.ts @@ -25,7 +25,9 @@ function seedRepo(repo:string,home:string){ return git; } // The first /usr/bin/git spawns on a cold macOS runner can eat a test's whole 5 s budget before the code under test runs; pay them once here. +// Every test below skips on Windows, which has no /usr/bin/git, so the warm-up does too. beforeAll(()=>{ + if(process.platform==='win32')return; const warm=fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(),'cso-git-hardening-warm-'))); try{seedRepo(path.join(warm,'repo'),warm);}finally{fs.rmSync(warm,{recursive:true,force:true});} },{timeout:30_000});