mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-09 14:38:59 +02:00
fix(slug): env-override runs never persist to the cwd cache; cache is GSTACK_HOME-aware
Found while closing the wave's eval gate: a test exporting GSTACK_PROJECT_SLUG from the repo root persisted the override into the cwd slug cache, silently rebinding the ENTIRE repo's session state (evals, decisions, timelines) to the test's slug for every later env-less run. The escape hatch is per-invocation by contract — it no longer writes the cache. The cache dir also hardcoded $HOME while lib/bin-context.ts's native port (#2561) reads it GSTACK_HOME-aware, so temp-home test runs littered the real ~/.gstack (observed: 2,528 stale temp-cwd entries, swept). Writer and reader now key the same GSTACK_HOME-aware cache; regression tests pin both behaviors. Also raises the cso --diff eval budget (240s/25t → 360s/40t): transcript-verified, the wave's legitimately-grown audit session completes the report and dies in closing telemetry at ~215s under the old budget; the full-audit sibling already runs at 300s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
54ca64b11f
commit
5af4a03b13
+12
-2
@@ -27,7 +27,11 @@
|
||||
# injection when consumed via source or eval.
|
||||
set -euo pipefail
|
||||
|
||||
CACHE_DIR="$HOME/.gstack/slug-cache"
|
||||
# GSTACK_HOME-aware, matching lib/bin-context.ts's native port (#2561): the
|
||||
# bash writer and the TS reader must key the SAME cache, and a test running
|
||||
# with GSTACK_HOME=<temp> must write its cache junk there, not into the real
|
||||
# home (observed: 2,528 stale temp-cwd entries accumulated in ~/.gstack).
|
||||
CACHE_DIR="${GSTACK_HOME:-$HOME/.gstack}/slug-cache"
|
||||
PROJECT_DIR="$(pwd)"
|
||||
# Encode absolute path as cache key: /Users/j/foo → _Users_j_foo
|
||||
CACHE_KEY=$(printf '%s' "$PROJECT_DIR" | tr '/' '_')
|
||||
@@ -37,8 +41,14 @@ SLUG=""
|
||||
|
||||
# 0. Explicit env override — wins over everything. Escape hatch for vendored
|
||||
# sub-repos and other genuine "subdir IS its own project" edge cases.
|
||||
SLUG_FROM_ENV=0
|
||||
if [[ -n "${GSTACK_PROJECT_SLUG:-}" ]]; then
|
||||
SLUG=$(printf '%s' "$GSTACK_PROJECT_SLUG" | tr -cd 'a-zA-Z0-9._-')
|
||||
# Per-invocation escape hatch, never a durable identity: persisting it
|
||||
# would rebind THIS cwd's slug for every later env-less run (observed: a
|
||||
# test exporting GSTACK_PROJECT_SLUG from the repo root rebound the whole
|
||||
# repo's session state to the test's slug).
|
||||
SLUG_FROM_ENV=1
|
||||
fi
|
||||
|
||||
# 1. Walk up from pwd, tracking the OUTERMOST ancestor with a canonical
|
||||
@@ -160,7 +170,7 @@ SLUG="${SLUG:-$(basename "$PROJECT_DIR" | tr -cd 'a-zA-Z0-9._-')}"
|
||||
# injection, but the invariant should not depend on that reasoning).
|
||||
SLUG=$(printf '%s' "$SLUG" | tr -cd 'a-zA-Z0-9._-')
|
||||
|
||||
if [[ -n "$SLUG" ]]; then
|
||||
if [[ -n "$SLUG" && "$SLUG_FROM_ENV" -eq 0 ]]; then
|
||||
CURRENT_CACHE=""
|
||||
if [[ -f "$CACHE_FILE" ]]; then
|
||||
CURRENT_CACHE=$(cat "$CACHE_FILE" 2>/dev/null || true)
|
||||
|
||||
@@ -63,3 +63,40 @@ describe('gstack-slug cache-read sanitization', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// The GSTACK_PROJECT_SLUG escape hatch is per-invocation, never durable: a
|
||||
// test exporting it from the repo root once rebound the ENTIRE repo's session
|
||||
// state (evals, decisions, timelines) to the test's slug via the cwd cache.
|
||||
// The cache is also GSTACK_HOME-aware now, matching lib/bin-context.ts's
|
||||
// native port — temp-home runs must not litter the real ~/.gstack (observed:
|
||||
// 2,528 stale temp-cwd entries).
|
||||
describe('slug cache hygiene', () => {
|
||||
test('an env-override run never writes the cwd cache', () => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'slug-env-'));
|
||||
try {
|
||||
const r = spawnSync(['bash', SLUG_BIN], {
|
||||
cwd: os.tmpdir(),
|
||||
env: { ...process.env, GSTACK_HOME: home, GSTACK_PROJECT_SLUG: 'override-slug' },
|
||||
});
|
||||
expect(r.stdout.toString()).toContain('SLUG=override-slug');
|
||||
expect(fs.existsSync(path.join(home, 'slug-cache'))).toBe(false);
|
||||
} finally {
|
||||
fs.rmSync(home, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('an env-less run caches under GSTACK_HOME, not $HOME', () => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'slug-home-'));
|
||||
try {
|
||||
const r = spawnSync(['bash', SLUG_BIN], {
|
||||
cwd: os.tmpdir(),
|
||||
env: { ...process.env, GSTACK_HOME: home },
|
||||
});
|
||||
expect(r.exitCode).toBe(0);
|
||||
const entries = fs.readdirSync(path.join(home, 'slug-cache'));
|
||||
expect(entries.length).toBe(1);
|
||||
} finally {
|
||||
fs.rmSync(home, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -161,9 +161,14 @@ IMPORTANT:
|
||||
- Focus on changes in the current branch vs main.
|
||||
- The webhook.ts file was added on this branch — it should be analyzed.`,
|
||||
workingDirectory: csoDiffDir,
|
||||
maxTurns: 25,
|
||||
maxTurns: 40,
|
||||
allowedTools: ['Bash', 'Read', 'Write', 'Edit', 'Grep', 'Glob', 'Agent'],
|
||||
timeout: 240_000,
|
||||
// 360s/40 turns: the v1.67 wave grew the audit session legitimately —
|
||||
// transcript-verified, the agent finds the webhook vuln, spawns the
|
||||
// verification subagent, and writes the report, then gets killed at
|
||||
// ~215s in its CLOSING telemetry under the old 240s/25-turn budget.
|
||||
// The full-audit sibling already runs at 300s.
|
||||
timeout: 360_000,
|
||||
});
|
||||
|
||||
logCost('cso', result);
|
||||
@@ -176,7 +181,7 @@ IMPORTANT:
|
||||
).toBe(true);
|
||||
|
||||
recordE2E(evalCollector, 'cso-diff-mode', 'e2e-cso', result);
|
||||
}, 240_000);
|
||||
}, 400_000);
|
||||
});
|
||||
|
||||
describeIfSelected('CSO v2 — infra scope', ['cso-infra-scope'], () => {
|
||||
|
||||
Reference in New Issue
Block a user