Skip to content

Harden local Guardian findings integration - #3

Merged
gagan114662 merged 2 commits into
mainfrom
feat/numbat-sidecar
Jul 31, 2026
Merged

gagan114662 merged 2 commits into
mainfrom
feat/numbat-sidecar

Conversation

@gagan114662

Copy link
Copy Markdown
Owner

Summary

  • attach Perplexity Numbat monitoring hooks to supported managed agent runtimes
  • project bounded, privacy-minimized local Guardian findings into the agent session panel
  • require exact recorded session, channel, and turn provenance instead of relabeling records with viewer context
  • remove unsafe finding-driven turn cancellation until Buzz has atomic expected-session/turn cancellation and Numbat exposes trustworthy agent identity
  • report hook installation as configured/unverified, clear stale health on scope changes and polling failures, and protect/rotate local evidence storage

Safety boundaries

  • monitor-only; this does not enable Numbat blocking
  • raw commands, paths, endpoints, hashes, and cited evidence never cross the Tauri projection
  • incomplete or mismatched provenance is not displayed
  • no finding can cancel a managed run
  • true per-agent evidence binding remains future work and requires an upstream record identity that Buzz can verify

Verification

  • cargo fmt --all -- --check
  • cargo fmt --manifest-path desktop/src-tauri/Cargo.toml -- --check
  • Biome check on all changed TypeScript files
  • pnpm typecheck
  • desktop unit tests: 3,751 passed
  • full Tauri Rust suite, serialized: 1,858 passed, 0 failed (14 keychain/real-relay tests ignored)
  • E2E production build passed
  • Playwright smoke: 771 passed, 1 skipped; 6 unrelated existing UI scenarios failed (composer caret formatting, own-avatar rendering, and video speed-menu stability)

Follow-up

Agent-bound display and safe cancellation should only be added after Numbat records carry a Buzz-verifiable managed-agent identity and the cancellation API accepts an atomic expected session + turn.

Co-authored-by: gagan114662 <[email protected]>
Signed-off-by: gagan114662 <[email protected]>
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@xhawk-ai xhawk-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Review Summary

I reviewed the Numbat/Guardian integration that installs monitor-only hooks, stores local findings, and projects session-scoped findings into the agent panel. The direction matches the safety boundaries, but two reliability issues should be addressed: the hook installer can indefinitely block managed-agent startup, and the UI filters by the currently active turn so valid findings disappear or never appear once a turn completes.

🔍 Findings

🟠 High 1 · 🟡 Medium 1

Comment on lines +366 to +379
let output = Command::new(binary)
.args([
"hook",
"install",
"--agent",
runtime,
"--emit",
"findings",
"--output",
"file",
"--output-file",
])
.arg(&findings)
.output()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High

This subprocess runs synchronously in the managed-agent spawn path, and Command::output() has no timeout. A broken or hanging numbat hook install will block agent start/restore indefinitely even though monitoring is best-effort, and the manual start path holds the managed-agent store/runtime locks while this executes. Run this off the critical path or enforce a short timeout and record disconnected on timeout.

agent.pubkey,
sessionChannelId,
activeSessionId,
activeTurnId,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium

Using activeTurnId as the required projection scope drops valid findings as soon as isWorking becomes false. Guardian records can be flushed at or just after turn completion with exact session/channel/turn provenance, but the hook then passes null for turnId, causing the Rust projection to return no findings and the panel to clear them. Scope to the latest/displayed turn id rather than only the currently working turn so completed-turn findings remain visible.

@gagan114662 gagan114662 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking review — do not merge yet.

  1. Agent isolation is still not enforced. numbat_findings_path validates the requested pubkey but returns the same global live.ndjson for every agent (numbat_findings.rs:82-85). project_finding requires session/channel/turn but never compares record.source_agent with the requested managed agent (:131-170), and the Tauri command accepts any syntactically valid pubkey (:405-424). Therefore the API has no structural proof that a displayed record belongs to the viewed agent. Exact context matching prevents relabeling, but it does not establish agent ownership. Require a trustworthy record identity bound to the managed agent, or keep agent-scoped findings hidden until that identity exists. Add a negative cross-agent test.

  2. Private storage fails open on non-Unix platforms. set_private_permissions returns Ok(()) without applying any protection under cfg(not(unix)) (:312-315), while the code proceeds to create/write the raw evidence and health files (:336-364). Raw Numbat evidence can contain commands, paths, endpoint data, hashes, and event IDs. Implement a Windows ACL/private-file path or explicitly disable the sink where owner-only storage cannot be guaranteed; add platform coverage.

  3. Agent startup can hang on Numbat configuration. Every supported managed-agent spawn synchronously calls prepare_numbat_monitoring (runtime.rs:614-621), which runs numbat hook install via blocking .output() with no timeout (numbat_findings.rs:366-380). A stuck or slow external binary now blocks the normal spawn critical path. Reconcile configuration outside that path, or use a bounded child process and make Guardian failure non-blocking.

The provenance rewrite and wrong-turn Cancel vulnerabilities are fixed, the health wording is more honest, and the privacy projection is appropriately narrow. Those improvements are not enough to merge while the ownership, storage, and startup boundaries above remain open.

Verification context: PR head caca6401c85c567bdee13525bc472173ae3e21a5, base 9bee25bef600f8e13b0f75e3a438a0995a1606a1; GitHub reports mergeable/clean but no CI checks are configured.

Co-authored-by: gagan114662 <[email protected]>
Signed-off-by: gagan114662 <[email protected]>
@gagan114662

Copy link
Copy Markdown
Owner Author

Re-review at head a26727ba06c18f5a01dc21a2d5514eb7a031c5d7: the four blocking findings are resolved. Finding projection now requires exact managed-agent identity and therefore fails closed with current runtime-only Numbat records; non-Unix storage fails before opening evidence; hook installation is off the spawn path, serialized, and bounded to 10 seconds; and the panel retains the latest completed turn for late findings.

Verification at this exact local head: TypeScript passed; 3,752/3,752 desktop tests passed; full unrestricted serialized Rust suite passed (1,855 library + 3 diagnostics, 14 ignored); E2E production build passed. pnpm check still reports the pre-existing runtime.rs file-size baseline mismatch present unchanged at the prior PR head.

@gagan114662
gagan114662 merged commit 6130a38 into main Jul 31, 2026
@gagan114662
gagan114662 deleted the feat/numbat-sidecar branch July 31, 2026 14:39
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