fix: session-scoped state to prevent cross-session race

Addresses reviewer feedback from @affaan-m:

1. State keyed by CLAUDE_SESSION_ID / ECC_SESSION_ID
   - Falls back to pid-based isolation when env vars absent
   - State file: state-{sessionId}.json (was .session_state.json)

2. Atomic write+rename semantics
   - Write to temp file, then fs.renameSync to final path
   - Prevents partial reads from concurrent hooks

3. Bounded checked list (MAX_CHECKED_ENTRIES = 500)
   - Prunes to last 500 entries when cap exceeded
   - Stale session files auto-deleted after 1 hour

9/9 tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
seto
2026-04-13 15:30:34 +09:00
parent 9a64e0d271
commit 45823fcede
2 changed files with 37 additions and 8 deletions

View File

@@ -9,7 +9,9 @@ const { spawnSync } = require('child_process');
const runner = path.join(__dirname, '..', '..', 'scripts', 'hooks', 'run-with-flags.js');
const stateDir = process.env.GATEGUARD_STATE_DIR || path.join(process.env.HOME || process.env.USERPROFILE || '/tmp', '.gateguard-test-' + process.pid);
const stateFile = path.join(stateDir, '.session_state.json');
// State files are per-session. In tests, falls back to pid-based name.
const sessionId = process.env.CLAUDE_SESSION_ID || process.env.ECC_SESSION_ID || `pid-${process.ppid || process.pid}`;
const stateFile = path.join(stateDir, `state-${sessionId.replace(/[^a-zA-Z0-9_-]/g, '_')}.json`);
function test(name, fn) {
try {