feat: add signed-audit-trails teaching plugin (third governance-category skill)#496
Conversation
Companion to the existing protect-mcp and review-agent-governance plugins
in the governance category. This one is a teaching skill, not a runtime
hook: a cookbook-style walkthrough for explaining, evaluating, or
demonstrating the signed-audit-trails pattern before committing to the
protect-mcp infrastructure.
Contents
────────
- plugin.json, README.md (explains this is a teaching skill, not runtime)
- skills/signed-audit-trails-recipe/SKILL.md (~1600 words) walking through:
1. Hook configuration in .claude/settings.json
2. Cedar policy authoring (four permit/forbid rules)
3. Using Claude Code normally with hooks active
4. Inspecting a produced receipt
5. Verifying the chain with @veritasacta/verify
6. Demonstrating tamper detection live
Plus: three-invariant cryptographic model (JCS + Ed25519 + hash chain),
cross-implementation interop table (4 implementations), CI/CD YAML
snippet, SLSA composition via ResourceDescriptor byproduct, common
pitfalls, references.
Marketplace entry
─────────────────
Added under category: "governance" immediately after protect-mcp. Keywords
emphasize the tutorial/cookbook nature ("tutorial", "skill", "recipe") to
distinguish from the runtime plugins.
Why this is useful alongside the two existing plugins
─────────────────────────────────────────────────────
protect-mcp is runtime. review-agent-governance is runtime (with human-
approval pattern). signed-audit-trails is education. A user evaluating
whether to adopt receipts can invoke the skill to get the concept and a
reproducible demo in-session, then install the runtime plugin if they
decide to proceed. Pairs naturally with /audit-chain and /verify-receipt
slash commands shipped in protect-mcp.
No new dependencies. Same IETF draft + @veritasacta/verify references as
the other governance plugins.
wshobson
left a comment
There was a problem hiding this comment.
Thanks @tomjwxf — the SKILL reads well and the three-invariants explanation (JCS + Ed25519 + hash chain) plus the cross-implementation interop table are good teaching content. One blocker before merge:
marketplace.json unicode regression (blocking). Same issue as #495: the diff rewrites literal UTF-8 characters on other, unrelated plugin entries as ASCII escapes (\u2014, \u2192, \u00e1). Please only append the new signed-audit-trails entry and leave the surrounding descriptions byte-for-byte intact. Likely a json.dump round-trip without ensure_ascii=False.
Also: this PR and #495 both modify the same section of marketplace.json and will conflict. Once the unicode issue is fixed on both, one will need to rebase on the other.
Non-blocking thoughts:
- The
refs.arewm.com/agent-commit/v0.2link should probably be verified before merge. - Worth deciding with the maintainer whether a teaching plugin with no agents/commands/hooks — just one SKILL — is better as a standalone plugin or as an additional skill under
plugins/protect-mcp/skills/. Both are defensible; the current decoupling has the advantage that a user evaluating receipts before committing to infrastructure can install this one alone. Your call to propose, maintainer's call to decide. - The walkthrough shows
--fail-on-missing-policy falseand then warns against it for production — good. Showing the strict form end-to-end as a second example would tighten the "production-ready" pathway.
Happy to re-review once the marketplace.json diff is clean.
Three blocking items + one non-blocking clarification from the review: 1. marketplace.json unicode regression FIXED. Reset the file to upstream HEAD, then inserted ONLY the review-agent-governance entry with a string-based append that preserves every existing UTF-8 character byte-for-byte. No entries other than the new one are modified. `grep -c '\\u' marketplace.json` returns 0 escape sequences. 2. approve-review.md $1 → $ARGUMENTS. The marketplace slash-command convention (per plugins/codebase-cleanup/commands/deps-audit.md from PR wshobson#490) is $ARGUMENTS, which captures the full argument including spaces. $1 only captured the first word. Also JSON-escape the reason before embedding in the approval record (via python3 json.dumps) so quotes, backslashes, and newlines do not break the JSON body. This resolves the non-blocking JSON-escape note too. 3. README honesty on the approval log. Previously claimed the chain "records exactly which actions were human-gated and when," which was overstating: approval log entries under ./review-receipts/approvals/ are plain JSON, not signed. Rewrote that paragraph to explicitly separate the signed PostToolUse chain (covered by @veritasacta/verify) from the operator-trust approval log. Points users at protect-mcp sign directly if they need signed approval records for regulated environments. 4. Added an explicit note on what the signed chain covers when the approval flag is present: PreToolUse short-circuits without calling Cedar, so the downstream PostToolUse receipt has decision:allow but no policy_digest. Auditors walking the chain should expect this. Resolves the "document the short-circuit" non-blocking item. Not addressed (pending Seth's follow-up): - marketplace.json conflict with wshobson#496 will be resolved by rebase order (whichever merges first; the other rebases) Tests: - python3 -m json.tool validates marketplace.json, plugin.json, hooks.json - grep -c '\\u' on marketplace.json = 0
1. marketplace.json unicode regression FIXED. Same fix as wshobson#495: reset the file to upstream HEAD and did a string-based append of only the new signed-audit-trails entry. No other entries are touched. Verified with grep on \\u escape sequences returning 0. 2. refs.arewm.com/agent-commit/v0.2 link verified. curl -sIL returns HTTP 200; the page is live and correct. Non-blocking thought (standalone plugin vs skill under protect-mcp) acknowledged; keeping as standalone for v0.1 since the user-evaluation path ('read before commit to infrastructure') works better without requiring protect-mcp install first. Happy to restructure if the maintainer prefers the nested-skill shape. Strict-form --fail-on-missing-policy true production example deferred to a follow-up SKILL revision. Not in this fix since it would be new content rather than a bug fix.
|
Thanks @wshobson, pushed 34b0c54 addressing the blocker plus the non-blocking notes: 1. marketplace.json unicode regression — fixed. Same fix as #495: reset the file to upstream HEAD and did a string-based append of only the new 2. refs.arewm.com/agent-commit/v0.2 — verified live. 3. On the standalone-plugin vs nested-skill question — your call, but here is my read. The user I had in mind for this plugin is someone evaluating the receipt pattern BEFORE they install 4. Strict-form On the #495 conflict: whichever you want to land first is fine. The string-based insertion approach in both PRs means the rebase of whichever-is-second is mechanical (just re-insert after the new first entry). Re-requesting review. |
Closes the version-pinning suggestion from @wshobson on wshobson#494. The tamper-detection test in plugins/protect-mcp/test/run-tests.sh previously called `npx protect-mcp@latest` and `npx @veritasacta/verify` with no version constraint, meaning an upstream npm publish could flip the test green or red without any repo-side signal. Pinning eliminates that. Changes ─────── - plugins/protect-mcp/hooks/hooks.json: 2 x protect-mcp@latest -> protect-mcp@0.5.5 (PreToolUse evaluate + PostToolUse sign) - plugins/protect-mcp/test/run-tests.sh: 6 x protect-mcp@latest -> protect-mcp@0.5.5 3 x @veritasacta/verify -> @veritasacta/verify@0.3.0 (the four PreToolUse test invocations, keygen, sign, plus the two verify calls in tests 7 and 8) - Header comment at the top of run-tests.sh now mentions the pinned @veritasacta/verify version for clarity. What is NOT pinned ────────────────── README.md and SKILL.md references remain as `npx protect-mcp@latest` and `npx @veritasacta/verify`. Those are documentation of the pattern a user should use in their own project, and "latest" is the right advice for that audience. The test infrastructure is the only executed path where pinning matters for reproducibility. How to bump ─────────── When you want to update (e.g., protect-mcp publishes 0.6.0 with a breaking change to --input handling), update both files together: perl -i -pe 's/protect-mcp\@0\.5\.5/protect-mcp\@0.6.0/g' \ plugins/protect-mcp/hooks/hooks.json \ plugins/protect-mcp/test/run-tests.sh Then re-run ./plugins/protect-mcp/test/run-tests.sh to confirm the tamper-detection guard still passes before merging. This PR does NOT touch review-agent-governance or signed-audit-trails because those plugins are still in review (wshobson#495, wshobson#496). Once they land, a follow-up PR will pin them too. Tests ───── - python3 -m json.tool hooks.json passes - bash -n run-tests.sh passes - No other files touched; no marketplace.json changes (avoids conflict with wshobson#495 and wshobson#496)
Three blocking items + one non-blocking clarification from the review: 1. marketplace.json unicode regression FIXED. Reset the file to upstream HEAD, then inserted ONLY the review-agent-governance entry with a string-based append that preserves every existing UTF-8 character byte-for-byte. No entries other than the new one are modified. `grep -c '\\u' marketplace.json` returns 0 escape sequences. 2. approve-review.md $1 → $ARGUMENTS. The marketplace slash-command convention (per plugins/codebase-cleanup/commands/deps-audit.md from PR wshobson#490) is $ARGUMENTS, which captures the full argument including spaces. $1 only captured the first word. Also JSON-escape the reason before embedding in the approval record (via python3 json.dumps) so quotes, backslashes, and newlines do not break the JSON body. This resolves the non-blocking JSON-escape note too. 3. README honesty on the approval log. Previously claimed the chain "records exactly which actions were human-gated and when," which was overstating: approval log entries under ./review-receipts/approvals/ are plain JSON, not signed. Rewrote that paragraph to explicitly separate the signed PostToolUse chain (covered by @veritasacta/verify) from the operator-trust approval log. Points users at protect-mcp sign directly if they need signed approval records for regulated environments. 4. Added an explicit note on what the signed chain covers when the approval flag is present: PreToolUse short-circuits without calling Cedar, so the downstream PostToolUse receipt has decision:allow but no policy_digest. Auditors walking the chain should expect this. Resolves the "document the short-circuit" non-blocking item. Not addressed (pending Seth's follow-up): - marketplace.json conflict with wshobson#496 will be resolved by rebase order (whichever merges first; the other rebases) Tests: - python3 -m json.tool validates marketplace.json, plugin.json, hooks.json - grep -c '\\u' on marketplace.json = 0
Three blocking items + one non-blocking clarification from the review: 1. marketplace.json unicode regression FIXED. Reset the file to upstream HEAD, then inserted ONLY the review-agent-governance entry with a string-based append that preserves every existing UTF-8 character byte-for-byte. No entries other than the new one are modified. `grep -c '\\u' marketplace.json` returns 0 escape sequences. 2. approve-review.md $1 → $ARGUMENTS. The marketplace slash-command convention (per plugins/codebase-cleanup/commands/deps-audit.md from PR wshobson#490) is $ARGUMENTS, which captures the full argument including spaces. $1 only captured the first word. Also JSON-escape the reason before embedding in the approval record (via python3 json.dumps) so quotes, backslashes, and newlines do not break the JSON body. This resolves the non-blocking JSON-escape note too. 3. README honesty on the approval log. Previously claimed the chain "records exactly which actions were human-gated and when," which was overstating: approval log entries under ./review-receipts/approvals/ are plain JSON, not signed. Rewrote that paragraph to explicitly separate the signed PostToolUse chain (covered by @veritasacta/verify) from the operator-trust approval log. Points users at protect-mcp sign directly if they need signed approval records for regulated environments. 4. Added an explicit note on what the signed chain covers when the approval flag is present: PreToolUse short-circuits without calling Cedar, so the downstream PostToolUse receipt has decision:allow but no policy_digest. Auditors walking the chain should expect this. Resolves the "document the short-circuit" non-blocking item. Not addressed (pending Seth's follow-up): - marketplace.json conflict with wshobson#496 will be resolved by rebase order (whichever merges first; the other rebases) Tests: - python3 -m json.tool validates marketplace.json, plugin.json, hooks.json - grep -c '\\u' on marketplace.json = 0
Three blocking items + one non-blocking clarification from the review: 1. marketplace.json unicode regression FIXED. Reset the file to upstream HEAD, then inserted ONLY the review-agent-governance entry with a string-based append that preserves every existing UTF-8 character byte-for-byte. No entries other than the new one are modified. `grep -c '\\u' marketplace.json` returns 0 escape sequences. 2. approve-review.md $1 → $ARGUMENTS. The marketplace slash-command convention (per plugins/codebase-cleanup/commands/deps-audit.md from PR wshobson#490) is $ARGUMENTS, which captures the full argument including spaces. $1 only captured the first word. Also JSON-escape the reason before embedding in the approval record (via python3 json.dumps) so quotes, backslashes, and newlines do not break the JSON body. This resolves the non-blocking JSON-escape note too. 3. README honesty on the approval log. Previously claimed the chain "records exactly which actions were human-gated and when," which was overstating: approval log entries under ./review-receipts/approvals/ are plain JSON, not signed. Rewrote that paragraph to explicitly separate the signed PostToolUse chain (covered by @veritasacta/verify) from the operator-trust approval log. Points users at protect-mcp sign directly if they need signed approval records for regulated environments. 4. Added an explicit note on what the signed chain covers when the approval flag is present: PreToolUse short-circuits without calling Cedar, so the downstream PostToolUse receipt has decision:allow but no policy_digest. Auditors walking the chain should expect this. Resolves the "document the short-circuit" non-blocking item. Not addressed (pending Seth's follow-up): - marketplace.json conflict with wshobson#496 will be resolved by rebase order (whichever merges first; the other rebases) Tests: - python3 -m json.tool validates marketplace.json, plugin.json, hooks.json - grep -c '\\u' on marketplace.json = 0
Hi @wshobson, third plugin in the
governancecategory, this one is ateaching skill rather than a runtime hook. Pairs naturally with the existing
protect-mcp(runtime) andreview-agent-governance(runtime + humanapproval) plugins without overlapping them.
What this is
A single skill file, ~1,600 words, walking through signed-audit-trail setup
end-to-end: Cedar policy authoring, hook configuration, first receipt,
offline verification with
@veritasacta/verify, live tamper-detectiondemonstration, and CI/CD integration. Plus: the three cryptographic
invariants (JCS + Ed25519 + hash chain), a cross-implementation interop
table, SLSA composition via ResourceDescriptor byproduct, and common
pitfalls.
Why a teaching plugin alongside the two runtime ones
protect-mcpis the production runtime. Install it, hooks fire, receiptswrite.
review-agent-governanceis a focused runtime for review-surface gating.signed-audit-trails(this one) is for a different user: someone who hasnot yet decided to commit to the infrastructure and wants to understand
the pattern in-session before proceeding.
A user invokes the skill via
Skillin Claude Code, gets the walkthrough,reproduces the demo locally, then either installs
protect-mcpforproduction use or decides receipts are not right for them. Education before
commitment.
Files in the PR
Plus one entry added to
.claude-plugin/marketplace.json, right afterprotect-mcp, keeping the governance category ordered by install-then-learnfor protect-mcp and learn-then-install for signed-audit-trails.
Verification
python3 -m json.toolvalidatesplugin.jsonandmarketplace.json(
name,description, YAML delimiters)protect-mcp/README.mdandreview-agent-governance/README.md(
tutorial,skill,recipe)Notes
protect-mcporreview-agent-governance.not require them to be installed; a user can read the skill, run the
demo with
npx, and never touch the runtime plugin if they choose notto.
terms for discovery.
Thanks for the governance category in #484 and #495. This rounds out the
shelf with a learn-before-commit entry point for users evaluating the
pattern.
cc @wshobson