feat(peek): verify_audit_log MCP tool + peek audit bundle evidence archive#137
Conversation
…n module Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
…(review) Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
Adds `peek audit bundle [--dir <path>] [--out <file>]` to package the audit log + head into a portable *.peekaudit evidence archive with a SHA-256 integrity manifest. Wires dispatch in audit.ts and extends printUsage(). Covered by two new tests in audit.test.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
…e archive Adds `--bundle <file>` to `peek audit verify`: unpacks a *.peekaudit archive, checks SHA-256 integrity (exit 2 on failure), then runs the full hash-chain verification on the extracted log + head. Mutually exclusive with --dir; --bundle wins. Usage block updated. Covered by two new tests (good bundle exits 0 + /archive integrity ok/ + /intact/; tampered bundle exits 2 + /integrity FAILED/). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
- peek-skill.md: bump 16→17 tools in frontmatter description, body prose, section heading, and safety-floor note; add verify_audit_log tool entry (audit tier, read-only, no permission level required) - plugins/peek/skills/peek/SKILL.md: byte-identical copy of peek-skill.md - peek-mcp README: add verify_audit_log to tool table; bump (16→17 tools) - peek-cli README: bump 16→17 + mention audit-log chain verification - set-up-peek-with-claude-code.md + using-peek-with-your-agent.md: bump 16→17 - new recipe: verify-and-share-a-tamper-evident-audit-trail.md - changesets: peek-verify-audit-log.md (@peekdev/mcp minor) + peek-audit-bundle.md (@peekdev/cli minor) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
Warning Review limit reached
Next review available in: 55 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
📝 WalkthroughWalkthroughAdds a hash-chain audit-log verification library ( ChangesAudit verification and bundling
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant CLI
participant AuditBundleLib
participant FileSystem
User->>CLI: peek audit bundle --dir --out
CLI->>FileSystem: read audit.log / audit.head.json
CLI->>AuditBundleLib: packAuditBundle(outPath, input)
AuditBundleLib-->>CLI: .peekaudit archive written
User->>CLI: peek audit verify --bundle file
CLI->>AuditBundleLib: unpackAuditBundle(bundlePath)
AuditBundleLib-->>CLI: logBuf, headBuf
CLI->>AuditBundleLib: verifyAuditBundleIntegrity
CLI->>CLI: verifyAuditChain(logBuf, head)
CLI-->>User: verification result
sequenceDiagram
participant Client
participant MCPServer
participant FileSystem
participant AuditChain
Client->>MCPServer: call verify_audit_log
MCPServer->>FileSystem: check audit.log exists
FileSystem-->>MCPServer: logPresent status
MCPServer->>FileSystem: read audit.log and head
MCPServer->>AuditChain: verifyAuditChain(logBuf, head)
AuditChain-->>MCPServer: VerifyResult
MCPServer-->>Client: JSON result + summary
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@apps/peek-docs/src/content/recipes/verify-and-share-a-tamper-evident-audit-trail.md`:
- Around line 77-80: The fenced block in the recipe content is missing a
language identifier, which causes markdownlint to fail. Update the markdown
fence around the audit trail output so it uses a valid language such as text or
console, keeping the existing content unchanged. Locate the fenced snippet in
the verify-and-share-a-tamper-evident-audit-trail.md recipe and adjust the fence
syntax only.
- Around line 75-80: The sample output in the audit verification recipe does not
match the actual CLI output from `peek audit verify --bundle`, so update this
block to use the literal wording emitted by the verifier or clearly mark it as
schematic. Locate the documentation snippet under the audit trail recipe and
adjust the displayed result to match the current human summary text produced by
the verification command.
In `@packages/peek-cli/skills/peek-skill.md`:
- Around line 84-88: The audit tool guidance in the peek skill incorrectly
suggests using verify_audit_log after receiving a bundle, but that tool only
checks the local audit log and cannot validate a .peekaudit file. Update the
wording around verify_audit_log in the skill docs so it is only described for
~/.peek/audit.log, and route bundle verification to the CLI flow via peek audit
verify --bundle <file> instead of the current “or after receiving one” phrasing.
In `@packages/peek-cli/src/commands/audit-verify.ts`:
- Around line 106-108: The bundled audit head parsing in audit-verify.ts can
throw before the integrity check handles failures. Update the head parsing
around unpacked.headBuf/JSON.parse in the verify flow so malformed bundled
audit.head.json is caught and converted into the same deterministic verify
failure behavior used by the --dir path. Keep the change scoped to the bundle
verification path and preserve the existing AuditHead handling.
- Around line 96-113: The `audit-verify` bundle path is mixing human text with
JSON output, breaking the `--bundle --json` contract. Update the
`verifyAuditBundle` flow in `audit-verify.ts` so `write('archive integrity
ok...')` and the `archive integrity FAILED...` message are only emitted for
non-JSON mode, and make the `verifyAuditBundleIntegrity`/`verifyAuditChain`
result path produce a single JSON document when `values.json` is set. Keep the
behavior consistent across the `values.bundle`, `values.json`,
`unpackAuditBundle`, and `verifyAuditChain` branches.
In `@packages/peek-cli/src/lib/audit-bundle.ts`:
- Around line 14-19: The current AUDIT_CAVEAT overstates the security guarantees
of the archive because the SHA-256 manifest is stored inside the same unsigned
bundle it verifies. Update AUDIT_CAVEAT in audit-bundle.ts to describe this as
internal corruption detection only, not tamper-evidence or proof of
authorship/time, and align any related messaging in verifyAuditBundleIntegrity
and audit bundle documentation/comments to reflect that a true integrity root
must come from outside the archive.
In `@packages/peek-cli/test/audit-verify.test.ts`:
- Around line 261-295: Add a regression test in audit-verify.test.ts that
exercises runAuditVerify with both --bundle and --json, so the bundle-specific
JSON output path is covered alongside the existing human-readable cases. Use the
existing helpers like chainLog, packAuditBundle, and runAuditVerify, then assert
the emitted JSON contains the expected archive/integrity status for a good
bundle and/or tampered bundle. Keep the new case near the current bundle tests
so the separate JSON branch in the audit verify command stays protected.
In `@packages/peek-mcp/src/mcp/server.ts`:
- Around line 999-1010: The audit status handler in mcp/server.ts is
short-circuiting on a missing log file before checking the head file. Update the
callback in the audit lookup path so it always reads audit.head.json and invokes
verifyAuditChain when audit.head.json exists, even if audit.log is missing. Use
the existing symbols defaultAuditLogPath, auditHeadPath, readHead, and
verifyAuditChain to return a tamper-detected result instead of the benign “no
audit log yet” response.
In `@packages/peek-mcp/test/audit-chain.test.ts`:
- Around line 61-119: Extend the verifyAuditChain coverage in
audit-chain.test.ts to hit the remaining branches: add a case that builds a
chain with a genuine gap so verifyAuditChain returns the gaps status, and add a
benign lagging-head case where the log has valid extra entries beyond the
supplied AuditHead and should still be reported as intact. Use the existing
chainLog and verifyAuditChain helpers to keep the tests aligned with the current
verifier behavior and assert the relevant status/metadata fields.
In `@packages/peek-mcp/test/server.test.ts`:
- Line 155: Update the test description in server.test.ts for the suite around
the documented tool surface so it matches the actual asserted count. The current
title on the it(...) block omits get_page_view and get_element_detail, so revise
the breakdown string to include those two read tools and reflect 17 total tools,
keeping the assertion and the named tool surface in sync.
In `@plugins/peek/skills/peek/SKILL.md`:
- Around line 84-88: The audit tool guidance in the Peek skill incorrectly tells
users to call verify_audit_log after receiving a bundle, but that tool only
checks the local audit log and cannot validate a .peekaudit file. Update the
text near the verify_audit_log entry in SKILL.md to remove the “or after
receiving one” wording and instead direct bundle checks to the CLI flow via peek
audit verify --bundle <file>, keeping the tool description accurate to its
scope.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b15a5ffa-2fb2-476f-9f5a-fc1edb3e1826
📒 Files selected for processing (23)
.changeset/peek-audit-bundle.md.changeset/peek-verify-audit-log.mdapps/peek-docs/src/content/recipes/set-up-peek-with-claude-code.mdapps/peek-docs/src/content/recipes/using-peek-with-your-agent.mdapps/peek-docs/src/content/recipes/verify-and-share-a-tamper-evident-audit-trail.mdpackages/peek-cli/README.mdpackages/peek-cli/skills/peek-skill.mdpackages/peek-cli/src/commands/audit-bundle.tspackages/peek-cli/src/commands/audit-verify.tspackages/peek-cli/src/commands/audit.tspackages/peek-cli/src/lib/audit-bundle.tspackages/peek-cli/test/audit-bundle.test.tspackages/peek-cli/test/audit-verify.test.tspackages/peek-cli/test/audit.test.tspackages/peek-mcp/README.mdpackages/peek-mcp/src/mcp/server.tspackages/peek-mcp/src/native-host/audit-chain.tspackages/peek-mcp/test/audit-chain.test.tspackages/peek-mcp/test/server.test.tspackages/peek-mcp/test/stdio-smoke.test.tspackages/peek-mcp/test/verify-audit-log.test.tsplugins/peek/README.mdplugins/peek/skills/peek/SKILL.md
…ier test coverage (CodeRabbit) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
…nest bundle caveat (CodeRabbit) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
…er wording (CodeRabbit) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
…real action schema Optional polish from the community-marketplace pre-approval review (0 blockers). Rebased onto #137 (verify_audit_log / 17 tools); these edits are independent of it. - plugin.json / marketplace.json: the listing one-liners omitted peek's consent-gated live-browser act capability (execute_action et al.). Add a short "with per-origin consent, act in the live page" clause so the shortest listing text matches the tool surface a screener enumerates. - SKILL.md consent-flow example used a flat, invalid shape (action: 'click', selector, no sessionId) that returns MCP -32602. Fix it to the real schema (request_authorization / execute_action take { sessionId, action: { type, ref } }), bind the returned confirmToken explicitly, and prefer a get_page_view ref per the skill's own guidance. - SKILL.md "runs entirely on the user's machine" now carries the READMEs' honest caveat (peek uploads nothing; what your MCP client does with returned session data is up to you). Both skill copies kept byte-identical (verify:plugin green). Verified: claude plugin validate (plugin + marketplace) passes, biome clean, and the corrected example shape passes live input validation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
…real action schema (#138) Optional polish from the community-marketplace pre-approval review (0 blockers). Rebased onto #137 (verify_audit_log / 17 tools); these edits are independent of it. - plugin.json / marketplace.json: the listing one-liners omitted peek's consent-gated live-browser act capability (execute_action et al.). Add a short "with per-origin consent, act in the live page" clause so the shortest listing text matches the tool surface a screener enumerates. - SKILL.md consent-flow example used a flat, invalid shape (action: 'click', selector, no sessionId) that returns MCP -32602. Fix it to the real schema (request_authorization / execute_action take { sessionId, action: { type, ref } }), bind the returned confirmToken explicitly, and prefer a get_page_view ref per the skill's own guidance. - SKILL.md "runs entirely on the user's machine" now carries the READMEs' honest caveat (peek uploads nothing; what your MCP client does with returned session data is up to you). Both skill copies kept byte-identical (verify:plugin green). Verified: claude plugin validate (plugin + marketplace) passes, biome clean, and the corrected example shape passes live input validation. Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com> Co-authored-by: harry-harish <22562634+harry-harish@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Makes peek's hash-chained action audit log verifiable in-loop by the agent and shareable as a portable evidence archive — extending the shipped audit log (#113).
verify_audit_log(new, 17th MCP tool, read-only, no params): verifies~/.peek/audit.log's hash chain and returns{ logPresent, status, entriesVerified, …, summary }—status∈ intact / broken / truncated / tail-tampered / prefix-tampered / incomplete-final / gaps / head-missing.verifyAuditChainwas ported verbatim from@peekdev/cliinto@peekdev/mcp's deliberately-duplicatednative-host/audit-chain.ts(importingAuditHead, not re-declaring); the pinned known-answer vector test guards drift.peek audit bundle(new CLI): packagesaudit.log+audit.head.jsoninto a portable*.peekauditgzipped-tar archive with a SHA-256 integrity manifest + chain head.peek audit verify --bundle <file>: a receiver verifies archive integrity + the chain in one step.Honesty / guardrails
Read-only, 100% local, no new egress/telemetry. Integrity is a SHA-256 manifest, not a signature, and there's no external timestamp anchor — messaging says "append-only, tamper-evident, not tamper-proof" everywhere. The audit log is value-free by design (verbs/selectors/prompts/timestamps, never values); the archive caveat says exactly what it does/doesn't contain.
Docs ripple (17th tool)
Skill
16→17+verify_audit_logentry, re-copied to the plugin (byte-identical;check-pluginenforces), peek-mcp/peek-cli READMEs + recipe count sweep, and a new recipeverify-and-share-a-tamper-evident-audit-trail.Test plan
pnpm test+build+lint+typecheckgreenverify-recipes(STRICT) +verify:plugin+claude plugin validate ./plugins/peekpassverifyAuditChaindiff'd byte-identical vs the CLI; plugin SKILL.md byte-identicalChangesets:
@peekdev/mcpminor +@peekdev/climinor.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation