fix(security): close cross-model (Codex) adversarial findings

Codex adversarial review found a HIGH the Claude pass missed plus 3 mediums:
- C1 (HIGH): gstack-decision-search --all returned every decide and IGNORED redact
  events, so a redacted secret still resurfaced via --all until compact ran. --all
  now excludes redacted (redact = expunge from every read path), still showing
  superseded history.
- C-med: semantic (external gbrain) slug/snippet were printed raw — datamark them too
  so a gbrain hit can't spoof role markers / fences into agent context.
- C4: semanticRecall fell back to an UNSCOPED gbrain search when no curated-memory
  source resolved, pulling code/doc corpora mislabeled as 'related decisions'. Now
  returns null (degrade) when there's no worktree-backed memory source.
- C5: validateDecide scanned only decision/rationale/alternatives; branch and issue
  are stored + surfaced (raw via --json), so include them in the injection+secret scan.

C2 (snapshot staleness) / C3 (compact TOCTOU residual): accepted for a single-user
store — atomic appends never lose the event, rebuilds self-heal, and the compact
size-recheck leaves only a sub-ms window; full append-locking would break the
lock-free append design.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-06-07 19:34:10 -07:00
parent 7fdd5a377d
commit e938fa7211
5 changed files with 48 additions and 12 deletions
+3 -4
View File
@@ -113,7 +113,7 @@ exit 1
expect(hits![0].slug).toBe("decisions/foo"); // proves --source default was forwarded
});
test("searches unscoped when no worktree source is registered", () => {
test("degrades to null when no curated-memory source (no unscoped fallback)", () => {
writeShim(
`#!/usr/bin/env bash
if [ "$1" = "sources" ]; then echo '{"sources":[{"id":"code","local_path":"/repo"}]}'; exit 0; fi
@@ -122,9 +122,8 @@ exit 1
`,
);
expect(resolveMemorySourceId(env())).toBeNull();
const hits = semanticRecall("anything", env());
expect(hits).not.toBeNull();
expect(hits![0].slug).toBe("code/x");
// no worktree-backed source → null, NOT an unscoped search that would pull code/doc hits
expect(semanticRecall("anything", env())).toBeNull();
});
test("degrades to null when gbrain search exits non-zero", () => {