Skip to content

fix(test): gstack-config tests must win the state-dir precedence race - #2480

Open
tranthanhnhatkhoa wants to merge 1 commit into
garrytan:mainfrom
tranthanhnhatkhoa:fix/gstack-config-test-env-isolation
Open

fix(test): gstack-config tests must win the state-dir precedence race#2480
tranthanhnhatkhoa wants to merge 1 commit into
garrytan:mainfrom
tranthanhnhatkhoa:fix/gstack-config-test-env-isolation

Conversation

@tranthanhnhatkhoa

Copy link
Copy Markdown

The bug

browse/test/gstack-config.test.ts drives GSTACK_STATE_DIR — the lowest-priority of the four state-dir sources bin/gstack-config:17 reads:

GSTACK_STATE_ROOT > GSTACK_HOME > GSTACK_STATE_DIR > $HOME/.gstack

The helper spreads ...process.env into the spawn env, so if either higher-priority variable is set in the parent process, it silently outranks the temp dir and the script reads somewhere else. Every case asserting on fixture content then sees an empty config.

Not hypothetical — five suites assign GSTACK_HOME at module scope and never restore it:

browse/test/telemetry.test.ts:11
browse/test/cdp-e2e.test.ts:21
browse/test/domain-skills-storage.test.ts:7
browse/test/domain-skills-e2e.test.ts:20
test/helpers/budget-override.test.ts:18

bun shares one process across files, so whether these pass depends on file ordering:

result
bun test browse/test/gstack-config.test.ts 26 pass, 0 fail
same file inside bun run test 17 pass, 9 fail

The fix

In the harness, not the leaking suites. A test that spawns a subprocess should fully specify the env it depends on rather than inherit whatever ran first — that makes it immune to any leaker, including ones added later. Patching the five would fix today and regress the first time someone adds a sixth.

GSTACK_STATE_DIR stays the knob, so the legacy alias keeps its coverage, and the per-case extraEnv override at line 106 is unaffected.

Verified

clean env                    26 pass  0 fail
GSTACK_HOME poisoned         26 pass  0 fail   (was 17 pass, 9 fail)
GSTACK_STATE_ROOT poisoned   26 pass  0 fail
full suite                   32 fails -> 23    (all 9 gstack-config gone)

Environment: bun 1.3.14, Ubuntu 24.04.4 LTS, main @ 960c3a8d (v1.60.2.0).

Two things found alongside, not fixed here

The module-scope leaks are still there. This PR makes one harness immune; it doesn't stop the pollution. Anything reading GSTACK_HOME in-process (not via a spawned CLI) is still exposed. Worth a separate pass moving those five into beforeAll/afterAll with restore.

The remaining 23 failures are unrelated to this. 15 of them (gstack-team-init, gstack-session-update) are environmental: those cases git init and commit into temp repos, and fail with Author identity unknown on a machine with no global user.name/user.email. Supplying GIT_AUTHOR_* takes test/team-mode.test.ts from 9 pass / 15 fail to 24 pass / 0 fail. That may be worth a fixture-level identity so the suite doesn't depend on the developer's global git config — happy to send that separately if you want it.

I also hit #2435 while doing this (suite exits 0 with failures) and left a repro there.

browse/test/gstack-config.test.ts drives GSTACK_STATE_DIR, which is the
LOWEST-priority of the four state-dir sources bin/gstack-config reads:

  GSTACK_STATE_ROOT > GSTACK_HOME > GSTACK_STATE_DIR > $HOME/.gstack

The helper spreads ...process.env into the spawn env, so if either
higher-priority variable is set in the parent process it silently
outranks the temp dir and the script reads somewhere else. Every case
that asserts on fixture content then sees an empty config.

That is not hypothetical. Five suites assign GSTACK_HOME at MODULE
scope and never restore it:

  browse/test/telemetry.test.ts:11
  browse/test/cdp-e2e.test.ts:21
  browse/test/domain-skills-storage.test.ts:7
  browse/test/domain-skills-e2e.test.ts:20
  test/helpers/budget-override.test.ts:18

bun shares one process across files, so whether these pass depends on
file ordering. Alone: 26 pass. In the suite: 17 pass, 9 fail.

Fix is in the harness rather than the leaking suites: a test that spawns
a subprocess should fully specify the env it depends on instead of
inheriting whatever ran first. Dropping the two higher-priority names
makes the cases immune to any leaker, including ones added later.

GSTACK_STATE_DIR stays the knob so the legacy alias keeps its coverage,
and the per-case extraEnv override at line 106 is unaffected.

Verified:
  clean env                26 pass  0 fail
  GSTACK_HOME poisoned     26 pass  0 fail   (was 17 pass, 9 fail)
  GSTACK_STATE_ROOT poison 26 pass  0 fail
  full suite               32 fails -> 23    (all 9 gstack-config gone)
@trunk-io

trunk-io Bot commented Aug 8, 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

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.

1 participant