Skip to content

[finding] serve-node-env-production-default.e2e.test.ts roots its fixture inside the tracked packages/cli/test/ tree, and tmp-node-env-default-* is not gitignored — a failing run leaves it behind for the next git add -A #12583

Description

@os-litant

Filed unassigned and ungraded by the #12539 dev, session session_01UjujZN219uFzBhSYfMykCd. Met while measuring #12539's failing set. ⛔ Not graded, not routed. The file is currently fenced by PR #12569, so nothing was touched.

Measured

packages/cli/test/serve-node-env-production-default.e2e.test.ts:388 creates its fixture inside the tracked test tree, not the system tmpdir:

constFIXTURES_ROOT=HERE;// = packages/cli/test/dir=mkdtempSync(join(FIXTURES_ROOT,'tmp-node-env-default-'));

That location is correct and deliberate — the file's own docblock gives the measured reason: the fixture config does a static import { AuthPlugin } from '@objectstack/plugin-auth', which resolves only because packages/cli/node_modules/ is reachable by Node's upward walk from wherever the config lives. A fixture in os.tmpdir() has no such ancestor. ⛔ This is not a request to move it.

The defect is the other half: nothing keeps the directory out of git, and cleanup does not survive a failure.

  • .gitignore carries *.tmp and tmp/. Neither matches tmp-node-env-default-* — verified: git check-ignore -v packages/cli/test/tmp-node-env-default-XXXX reports it is NOT ignored.
  • afterAll (line 397) awaits stop(child) for every child beforermSync(dir, …), so any throw or timeout in the child-teardown loop skips the removal entirely.

Observed on 09b4f4e4e with the dependency closure built and packages/cli/dist absent — i.e. the fresh-worktree state #12539 is about, where this file's it fails. After that run:

packages/cli/test/tmp-node-env-default-zVfZgc/objectstack.config.ts
packages/cli/test/tmp-node-env-default-zVfZgc/package.json

were still on disk, untracked. After a run where the same file passes, they are gone — so the leak is specifically on the failing path, which is the path a developer is most likely to be on when they reach for git add -A.

⚠️ Why it is worth a card

Three costs, in ascending order:

  1. git status is no longer a clean signal in the worktree, which is what a parallel-agent container leans on.
  2. A stray package.json changes what tooling derives.node scripts/pm/dispatch-gates.mjs reads the working tree including untracked files; with the leftover present it derived three extra gate families for an unrelated change set — check:override-consistency, check-changeset-fixed.mjs and check-osv-exemptions.mjs — matched solely via packages/cli/test/tmp-node-env-default-zVfZgc/package.json through validate-deps.yml's **/package.json trigger. It exits 0 and the list looks ordinary.
  3. git add -A commits a test fixture into packages/cli/test/.

Cost 3 is the one this repo has already paid once, from a different producer: #8218"check:type-check-debt writes tsconfig.debt-remeasure.json into tracked package dirs and it is not gitignored — a concurrent git add -A commits it" (closed). Same class, same remedy shape.

This is the only file in the repo that roots a fixture this way — git grep -n "mkdtempSync(join(HERE\|mkdtempSync(join(FIXTURES_ROOT" -- packages returns exactly one hit — so the fix is bounded and there is no family to sweep.

Two candidate remedies, not judged here

  • Add packages/cli/test/tmp-node-env-default-*/ to .gitignore (or a packages/cli/test/.gitignore). Cheapest; leaves the disk litter.
  • Move rmSync(dir, …) into a finally around the child-teardown loop, so the removal runs whatever stop() does. Fixes the leak rather than hiding it. ⭐ Both, probably — the ignore is the guard for the next producer, the finally is the fix for this one.

Re-check

sed -n '380,400p' packages/cli/test/serve-node-env-production-default.e2e.test.ts
git check-ignore -v packages/cli/test/tmp-node-env-default-XXXX ; echo "exit=$?" # 1 = NOT ignored
grep -n "tmp" .gitignore

⛔ Reproducing the leak needs the failing path: build only the dependency closure (pnpm --filter '@objectstack/cli^...' build, note ^...), leave packages/cli/dist absent, then run this one file and look at git status --short afterwards.

Severity not judged; S, mechanical.


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions