Skip to content

mcp/snapshot: secret-filter drift guard + per-session edit locks (#528 audit)#530

Merged
justrach merged 2 commits into
release/0.2.5824from
fix/audit-bugs-528
Jun 4, 2026
Merged

mcp/snapshot: secret-filter drift guard + per-session edit locks (#528 audit)#530
justrach merged 2 commits into
release/0.2.5824from
fix/audit-bugs-528

Conversation

@justrach

@justrach justrach commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Two correctness/security items surfaced by the #528 capability audit. Both were verified against the actual code — and notably, both turned out to be latent rather than live, which the fixes reflect honestly.

1. isSensitivePath secret-filter — drift guard (not a live bug)

snapshot.zig and watcher.zig keep duplicate copies of the secret/credential exclusion filter (snapshot persistence vs live indexing). The audit flagged "divergent logic causing coverage gaps" — but tracing every input class shows they're functionally equivalent today (watcher's first-char fast-path gate {'.','c','s','i'} covers every sensitive name; both have the .env boundary check from issue-409).

So there's no live coverage gap — but it is a real future-leak hazard in security code (edit one copy, not the other → a secret silently slips into one path). Fix: make snapshot.isSensitivePath pub and add a parity test over a ~40-path battery (.env, id_rsa, .ssh/known_hosts, keystore.jks, … and the non-secret .envoy.json/.environment edge cases) that fails CI on any drift. No runtime behavior change.

2. codedb_edit agent_id = 1 — per-session edit-lock owner (forward-looking)

handleEdit hardcoded EditRequest.agent_id = 1 (the startup __filesystem__ agent). The advisory lock is re-entrant per agent id, so multiple MCP connections sharing one process would both "win" the same file's lock and miss a concurrent edit.

On inspection this is latent, not live: stdio MCP is one connection per process, and server.zig (HTTP serve) already takes a per-client agent id from the request. So it'd only bite if a multi-connection MCP transport is added. The fix threads a distinct per-session id (Session.edit_agent_id, registered at session start) through handleCall → dispatch → handleEdit (+ the bundle recursion), removing the documented TODO. Behavior-preserving for today's single-connection path (the single client just owns a distinct registered id instead of the shared 1).

Tests / validation

  • test_snapshot.zig: isSensitivePath parity battery (snapshot ≡ watcher) + explicit secret/non-secret anchors.
  • test_core.zig: distinct session ids register non-1 and mutually exclude on a path (the registry's contention semantics were already covered).
  • zig build and zig build test are green.

This came out of a multi-agent capability audit of codedb; the larger roadmap (callpath+PageRank from the already-computed edges, token-budget context packing, format=json, prefix/kind symbol search, git-churn ranking) is tracked separately.

🤖 Generated with Claude Code

…audit)

Two correctness/security items surfaced by the #528 capability audit.

- isSensitivePath drift guard: snapshot.zig and watcher.zig keep duplicate
  copies of the secret/credential exclusion filter. They are equivalent today
  (verified by tracing every input class), but a future edit to one copy and
  not the other would silently leak a secret into either the snapshot or the
  live index. Make snapshot's copy `pub` and add a parity test over a ~40-path
  battery (incl. the .env-prefix edge cases and .ssh//.aws/ dirs) so any drift
  fails CI. No runtime behavior change.

- Per-session edit-lock owner: codedb_edit hardcoded EditRequest.agent_id = 1
  (the startup __filesystem__ agent). The advisory lock is re-entrant per agent
  id, so multiple MCP connections sharing one process would both "win" the same
  file's lock and fail to detect concurrent edits. Thread a distinct per-session
  agent id (Session.edit_agent_id, registered at session start) through
  handleCall -> dispatch -> handleEdit (and the bundle recursion). Today's stdio
  MCP is single-connection and the HTTP server already takes a per-client agent
  id, so this is forward-looking hardening + removes the TODO; behavior-
  preserving for the current single-connection path.

Validated by zig build test. Registry lock semantics were already covered in
test_core.zig; added a test tying distinct session ids to mutual exclusion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

Benchmark Regression Report

Thresholds: 10.00% and 50,000 ns absolute delta

NOISE means the percentage threshold was exceeded, but the absolute delta was too small to fail CI.

Tool Base (ns) Head (ns) Delta Abs Delta (ns) Status
codedb_bundle 112592 106366 -5.53% -6226 OK
codedb_changes 12326 11192 -9.20% -1134 OK
codedb_context 1156334 1142004 -1.24% -14330 OK
codedb_deps 243 239 -1.65% -4 OK
codedb_edit 51158 50236 -1.80% -922 OK
codedb_find 11669 11811 +1.22% +142 OK
codedb_hot 26733 26421 -1.17% -312 OK
codedb_outline 38022 38835 +2.14% +813 OK
codedb_read 16857 16940 +0.49% +83 OK
codedb_search 26454 28230 +6.71% +1776 OK
codedb_snapshot 70062 70611 +0.78% +549 OK
codedb_status 13927 10120 -27.34% -3807 OK
codedb_symbol 20839 19567 -6.10% -1272 OK
codedb_tree 45014 46127 +2.47% +1113 OK
codedb_word 12827 13217 +3.04% +390 OK

Positive runtime evidence for the per-session edit-lock fix: an edit through a
session agent registered AFTER __filesystem__ (so id != 1, mirroring the real
server's Session.edit_agent_id) successfully acquires the advisory lock and
writes the file, and a second agent can edit once the lock is released.
applyEdit returns error.FileLocked if the id were not a live registered agent,
so this guards against a wiring regression that compilation can't catch.

test-snapshot 29/29; full zig build test green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

Benchmark Regression Report

Thresholds: 10.00% and 50,000 ns absolute delta

NOISE means the percentage threshold was exceeded, but the absolute delta was too small to fail CI.

Tool Base (ns) Head (ns) Delta Abs Delta (ns) Status
codedb_bundle 109063 109893 +0.76% +830 OK
codedb_changes 11688 11025 -5.67% -663 OK
codedb_context 1139404 1137346 -0.18% -2058 OK
codedb_deps 321 263 -18.07% -58 OK
codedb_edit 51567 54675 +6.03% +3108 OK
codedb_find 10645 10740 +0.89% +95 OK
codedb_hot 27234 27320 +0.32% +86 OK
codedb_outline 37966 35181 -7.34% -2785 OK
codedb_read 17162 19282 +12.35% +2120 NOISE
codedb_search 25857 25996 +0.54% +139 OK
codedb_snapshot 70099 80925 +15.44% +10826 NOISE
codedb_status 10200 9863 -3.30% -337 OK
codedb_symbol 20813 19730 -5.20% -1083 OK
codedb_tree 44483 46068 +3.56% +1585 OK
codedb_word 12673 12407 -2.10% -266 OK

@justrach justrach merged commit 9648c9f into release/0.2.5824 Jun 4, 2026
1 check passed
@justrach justrach deleted the fix/audit-bugs-528 branch June 4, 2026 06:23
justrach added a commit that referenced this pull request Jun 4, 2026
…, CLI hardening, ReScript

- release_info.semver 0.2.5823 -> 0.2.5824 (the version codedb reports and
  update.zig compares against; build.zig.zon was already 0.2.5824).
- CHANGELOG: document the warm CLI daemon (#525), faster fuzzy find (#526),
  CLI hardening (#529), ReScript .res/.resi (#532), and audit fixes (#530)
  alongside the existing code-graph / snapshot-load sections.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant