mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
* security: isolate every gstack Bun entry point from the audited checkout's .env and bunfig.toml Bun auto-loads .env, .env.local and .env.<NODE_ENV> from its cwd and runs a cwd bunfig.toml preload before the program starts. gstack runs inside the repo it audits, so a committed .env could steer state roots, the claude binary or spend caps, and a bunfig preload ran arbitrary code in every bin and hook. Every bun shebang, shell and skill caller, TypeScript spawn and compiled build now disables both (--no-env-file --config=/dev/null, bunIsolationArgs(), --no-compile-autoload-dotenv/bunfig), with a ratchet and hostile-fixture regressions. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: name the directly executed scripts in the isolation ratchet Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: follow the isolation flags in touchfiles, copy lists, recipe assertions and the harness pin Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: keep browse/src/bun-child-config.ts unchanged so the native cookie qualification still binds Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(windows): the empty bunfig outlives its process so the timeline hook's detached repair child can read it Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * v1.91.159.0 security: gstack's Bun entry points ignore the audited repo's .env and bunfig.toml (S1) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: plan-mode render pattern accepts the isolation flags Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
50 lines
2.9 KiB
TypeScript
50 lines
2.9 KiB
TypeScript
#!/usr/bin/env -S bun --no-env-file --config=/dev/null
|
|
/**
|
|
* One-release stubs for retired package scripts. Each retired name in
|
|
* package.json runs `bun run scripts/retired-command.ts <name>`, which prints
|
|
* the replacement and exits 1, so an old command in an agent's memory or a
|
|
* stale doc fails loudly instead of running zero cases or the wrong lane.
|
|
*
|
|
* CONTRIBUTING.md "Retired commands" carries the same table. TODOS.md
|
|
* "Remove one-release command stubs" deletes this file and the stub entries
|
|
* in the next release.
|
|
*/
|
|
|
|
export interface RetiredCommand {
|
|
replacement: string;
|
|
reason: string;
|
|
}
|
|
|
|
export const RETIRED_COMMANDS: Record<string, RetiredCommand> = {
|
|
'test:evals': { replacement: 'bun run eval:bg:pr', reason: 'tierless run skipped every tier-gated paid file' },
|
|
'test:evals:all': { replacement: 'bun run eval:bg:release', reason: 'tierless run skipped every tier-gated paid file' },
|
|
'test:e2e': { replacement: 'bun run eval:bg:pr', reason: 'tierless run skipped every tier-gated paid file' },
|
|
'test:e2e:all': { replacement: 'bun run eval:bg:release', reason: 'tierless run skipped every tier-gated paid file' },
|
|
'test:gate': { replacement: 'bun run test:gate:sharded', reason: 'the single-process fan-out never completed a run' },
|
|
'test:periodic': { replacement: 'bun run test:periodic:sharded', reason: 'the single-process fan-out never completed a run' },
|
|
'test:codex': { replacement: 'bun run test:periodic:sharded', reason: 'it set no EVALS_TIER, so both periodic-tier Codex files ran zero cases' },
|
|
'test:codex:all': { replacement: 'bun run test:periodic:sharded', reason: 'it set no EVALS_TIER, so both periodic-tier Codex files ran zero cases' },
|
|
'eval:bg': { replacement: 'bun run eval:bg:pr', reason: 'it detached the retired tierless test:evals' },
|
|
'eval:bg:all': { replacement: 'bun run eval:bg:release', reason: 'it detached the retired tierless test:evals:all' },
|
|
'eval:flake-rank': { replacement: 'bun run eval:pass-rates', reason: 'it was a second name for the same script' },
|
|
'eval:watch': { replacement: 'tail the gstack-detach log under ~/.gstack-dev/eval-runs/, or `gh run watch <run-id>` for a CI run', reason: 'it read a file only the unsharded runner wrote, so it showed nothing for sharded runs' },
|
|
'test:audit': { replacement: 'bun run test', reason: 'test/audit-compliance.test.ts already runs in the free suite' },
|
|
};
|
|
|
|
export function retiredMessage(name: string): string | null {
|
|
const entry = RETIRED_COMMANDS[name];
|
|
if (!entry) return null;
|
|
return `\`bun run ${name}\` is retired (${entry.reason}).\nUse instead: ${entry.replacement}\nSee CONTRIBUTING.md "Retired commands" for the full table.`;
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
const name = process.argv[2] ?? '';
|
|
const message = retiredMessage(name);
|
|
if (!message) {
|
|
console.error(`retired-command: unknown name "${name}". Known: ${Object.keys(RETIRED_COMMANDS).join(', ')}`);
|
|
process.exit(2);
|
|
}
|
|
console.error(message);
|
|
process.exit(1);
|
|
}
|