Files
gstack/test/gstack-home-module-scope.test.ts
T
SinaandClaude Fable 5.1 886217894f test: registries, budgets and suite reconciled for Aside-first with the $B fallback
Touchfiles + E2E tiers gain the Aside keys, coverage matrix and eval baselines updated, size budget re-baselined to parity-baseline-v1.80.0.0.json (the contract plus fallback ride in every browsing skill), parity ceilings ratcheted with measured values, LLM-judge prompts and the E2E fixtures speak Aside-first, browse-fallback.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 16:48:38 -04:00

55 lines
2.3 KiB
TypeScript

/**
* No module-scope GSTACK_HOME assignment in any test file.
*
* Shard processes evaluate many test-file modules in one bun process, and a
* module can be loaded before its tests run — so a module-scope
* `process.env.GSTACK_HOME = ...` leaks into every sibling file in the
* shard. The damage was real before the 2026-08 sweep: relink.test.ts:28
* documents a "fresh install" test seeing a neighbor's skill_prefix, and
* cdp-e2e once baked a sibling's temp dir into artifacts that outlived it
* (dangling symlinks into a deleted render dir).
*
* The pattern is: save the original, assign in beforeAll, restore in
* afterAll — confining the value to the file's execution window.
*
* Heuristic: repo test files write module-scope statements unindented, so a
* column-0 assignment is module scope; indented assignments (inside hooks,
* tests, or helpers) are fine.
*/
import { describe, expect, test } from 'bun:test';
import { spawnSync } from 'node:child_process';
import * as fs from 'node:fs';
import * as path from 'node:path';
const ROOT = path.resolve(__dirname, '..');
function trackedTestFiles(): string[] {
const out = spawnSync('git', ['ls-files', '*.test.ts'], {
cwd: ROOT, encoding: 'utf-8', timeout: 30_000,
});
if (out.status !== 0) throw new Error(`git ls-files failed: ${out.stderr}`);
// The index can still list a file deleted from the working tree (a pending
// `git rm`); scan only what exists on disk.
return out.stdout.split('\n').filter(Boolean).filter((rel) => fs.existsSync(path.join(ROOT, rel)));
}
describe('GSTACK_HOME module-scope tripwire', () => {
test('no test file assigns process.env.GSTACK_HOME at module scope', () => {
const files = trackedTestFiles();
expect(files.length).toBeGreaterThan(100); // scan-rot guard
const offenders: string[] = [];
for (const rel of files) {
const lines = fs.readFileSync(path.join(ROOT, rel), 'utf-8').split('\n');
lines.forEach((line, i) => {
if (/^(?:process\.env\.GSTACK_HOME|process\.env\.GSTACK_STATE_ROOT)\s*=[^=]/.test(line)) {
offenders.push(`${rel}:${i + 1}${line.trim()}`);
}
});
}
expect(offenders,
`module-scope env assignment leaks across shard siblings — move into beforeAll + restore in afterAll:\n${offenders.join('\n')}`,
).toEqual([]);
});
});