Skip to content

fix(test): prepush hook test builds PATH with a POSIX-only separator - #2544

Closed
luckywenapere wants to merge 1 commit into
garrytan:mainfrom
luckywenapere:fix/prepush-test-path-separator
Closed

fix(test): prepush hook test builds PATH with a POSIX-only separator#2544
luckywenapere wants to merge 1 commit into
garrytan:mainfrom
luckywenapere:fix/prepush-test-path-separator

Conversation

@luckywenapere

Copy link
Copy Markdown
Contributor

The follow-up I offered in #2543. Independent of that PR — touches one test file
and no shipping code, so it can land in either order.

The bug

test/redact-prepush-hook.test.ts shadows git with a stub by prepending a temp
dir to PATH, built as:

PATH: `${stubDir}:${process.env.PATH}`

On Windows the separator is ;, so : produces a single unparseable entry, the
stub is never found, and the real git runs. The diff then succeeds,
gitStrict never throws, and the hook exits 0 where the test expects 1.

It surfaces as a wrong assertion (Expected: 1, Received: 0) rather than as a
portability problem, which is what made it hard to place — I initially assumed it
was a regression from my own changes in #2543 and only found the real cause after
reproducing it against a pristine checkout.

The fix

A prependPath helper mirroring the one already in
test/gstack-brain-context-load.test.ts, which handles both platform details:

  • path.delimiter rather than a hardcoded :
  • a case-insensitive lookup of the existing env key — Windows commonly spells it
    Path, and adding a second PATH alongside an inherited Path leaves which
    one wins up to the spawn implementation

On POSIX the helper resolves to { PATH: binDir + ":" + process.env.PATH }
byte-identical to the expression it replaces, so behaviour there is
unchanged
.

Why the test is also gated to POSIX

Fixing the separator alone does not make it pass on Windows, and it can't:

  • The premise is that a signal-killed child yields spawnSync status === null.
    Windows has no equivalent — a force-killed process reports a non-zero exit
    code — so the branch the test names is unreachable there.
  • The stub is a #!/bin/sh file named git, which Windows will not execute at
    all: process creation resolves commands through PATHEXT (.exe/.cmd/.bat) and
    ignores the shebang.

A Windows variant would have to assert the non-zero-exit path instead — a
different branch than the test name claims — so it's gated with
test.skipIf(process.platform === "win32"), matching
test/session-runner-timeout.test.ts and test/setup-emoji-font.test.ts.

The separator fix is still worth landing on its own: it's a latent trap for the
next test that copies this idiom, and the current form fails silently by
running the real binary rather than loudly.

Verification

Windows, bun test test/redact-prepush-hook.test.ts:

before after
pass 14 14
skip 0 1
fail 1 0

Three consecutive clean runs after the change.

Two caveats, since I can only verify one platform here:

  • POSIX is unverified by me. The test should still run and pass there, by the
    byte-identical argument above, but it's worth a CI run.
  • I saw the neighbouring new branch (zero remote sha) test fail once at
    ~6.8s under heavy parallel load, then pass 3/3 afterwards, and it also passes
    on a pristine checkout. I believe it's load-related flakiness unrelated to this
    change, but flagging it rather than leaving it unmentioned in case you've seen
    it in CI too.

🤖 Generated with Claude Code

Disclosing the tooling, as in #2543. The before/after numbers above were measured
by running the suite, not inferred, including against a pristine checkout to
confirm the failure pre-dated my changes.

`test/redact-prepush-hook.test.ts` shadows `git` with a stub by prepending a
temp dir to PATH, built as `${stubDir}:${process.env.PATH}`. On Windows the
separator is `;`, so that produces one unparseable entry, the stub is never
found, and the REAL git runs — the diff succeeds, `gitStrict` never throws, and
the hook exits 0 where the test expects 1. It fails as a wrong assertion rather
than as a portability problem, which is what made it hard to place.

Replace it with a `prependPath` helper mirroring the one already in
test/gstack-brain-context-load.test.ts, which handles both platform details:
`path.delimiter`, and a case-insensitive lookup of the existing env key —
Windows commonly spells it `Path`, and adding a second `PATH` alongside an
inherited `Path` leaves the winner up to the spawn implementation.

On POSIX the helper resolves to `{ PATH: binDir + ":" + process.env.PATH }`,
byte-identical to the expression it replaces, so behaviour there is unchanged.

Fixing the separator alone does not make the test pass on Windows, and it
cannot: the premise is that a signal-killed child yields `spawnSync`
status === null, and Windows has no equivalent (a force-killed process reports
a non-zero exit code). The stub is also a `#!/bin/sh` file named `git`, which
Windows will not execute, since process creation resolves through PATHEXT and
ignores the shebang. A Windows variant would assert the non-zero-exit branch
instead — a different branch than the test name claims — so the test is gated
with test.skipIf(process.platform === "win32"), matching
test/session-runner-timeout.test.ts and test/setup-emoji-font.test.ts.

Windows before: 14 pass, 1 fail. After: 14 pass, 1 skip, 0 fail (3 consecutive
runs). Unchanged on POSIX, where it should still run and pass — worth
confirming in CI, since I can only verify the Windows half here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Aug 13, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@garrytan

Copy link
Copy Markdown
Owner

Thank you — this was absorbed on main (credited in the v1.6x CHANGELOG entries; roster in PR #2604). Closing.

@garrytan garrytan closed this Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants