From 7e1aa0f9777803e22d8d01c151e680e07d8cb15d Mon Sep 17 00:00:00 2001 From: tommylauren Date: Fri, 17 Apr 2026 10:28:18 -0400 Subject: [PATCH 1/5] feat: add review-agent-governance plugin (closes review-bot failure class) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second inhabitant of the `governance` category. Addresses the failure mode where an AI agent posts PR reviews, comments, merges, or edits CI config without a human gate. Directly inspired by the Hermes-style incident pattern where review-bot hallucinations produce account-linked damage. Components ────────── - plugin.json, README.md, skills/review-agent-setup/SKILL.md - agents/review-policy-author.md (sonnet) — Cedar author specialized in review-surface gating across GitHub / GitLab / protected branches / CI paths / notification surfaces - commands/approve-review.md — opens an approval window via ./.review-approved flag file, records the reason in ./review-receipts/approvals/ - commands/list-pending.md — walks the receipt chain to show recent denials (the set of actions the agent tried that were blocked) - hooks/hooks.json — PreToolUse gate + PostToolUse sign - policies/review-agent-governance.cedar — default Cedar policy with five forbid rules covering gh/glab review actions, protected-branch pushes, CI config paths, and WebFetch POSTs to hooks.slack.com / api.github.com Behavior ──────── By default, the plugin forbids: - gh pr review|comment|merge|close|edit, gh issue comment|close|edit, gh release create|edit, gh api repos - GitLab and Bitbucket equivalents - git push to main|master|release|production - Writes to .github/workflows/, .gitlab-ci.yml, .circleci/config.yml, .github/CODEOWNERS - WebFetch POSTs to api.github.com / api.gitlab.com / hooks.slack.com / discord.com Non-review actions pass through unchanged. Composes with protect-mcp for general policy enforcement; configure separate receipt directories to keep the chains distinct. Approval pattern ──────────────── Human opens an approval window by creating ./.review-approved (or via /approve-review ""). The PreToolUse hook short-circuits to permit while the flag is present. Every action, approved or denied, still produces an Ed25519 receipt, so the chain records exactly what happened and under what approval. Marketplace entry ───────────────── Added under category: "governance" with seven discovery keywords. The governance category now has two inhabitants (protect-mcp + this one), which turns it from a vanity category into a real shelf. Standards ───────── - Ed25519 (RFC 8032), JCS (RFC 8785), Cedar (AWS) - IETF draft-farley-acta-signed-receipts - Uses protect-mcp as its evaluation/signing runtime --- .claude-plugin/marketplace.json | 25 ++- .../.claude-plugin/plugin.json | 10 + plugins/review-agent-governance/README.md | 181 ++++++++++++++++++ .../agents/review-policy-author.md | 164 ++++++++++++++++ .../commands/approve-review.md | 98 ++++++++++ .../commands/list-pending.md | 149 ++++++++++++++ .../review-agent-governance/hooks/hooks.json | 22 +++ .../policies/review-agent-governance.cedar | 103 ++++++++++ .../skills/review-agent-setup/SKILL.md | 178 +++++++++++++++++ 9 files changed, 925 insertions(+), 5 deletions(-) create mode 100644 plugins/review-agent-governance/.claude-plugin/plugin.json create mode 100644 plugins/review-agent-governance/README.md create mode 100644 plugins/review-agent-governance/agents/review-policy-author.md create mode 100644 plugins/review-agent-governance/commands/approve-review.md create mode 100644 plugins/review-agent-governance/commands/list-pending.md create mode 100644 plugins/review-agent-governance/hooks/hooks.json create mode 100644 plugins/review-agent-governance/policies/review-agent-governance.cedar create mode 100644 plugins/review-agent-governance/skills/review-agent-setup/SKILL.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 22ddd8f..f931ad0 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -13,7 +13,7 @@ { "name": "documentation-standards", "source": "./plugins/documentation-standards", - "description": "HADS (Human-AI Document Standard) — semantic tagging convention for writing docs that work efficiently for both humans and AI models. Reduces token consumption by separating machine-critical facts from human context.", + "description": "HADS (Human-AI Document Standard) \u2014 semantic tagging convention for writing docs that work efficiently for both humans and AI models. Reduces token consumption by separating machine-critical facts from human context.", "version": "1.0.0", "author": { "name": "Niksa Barlovic", @@ -900,7 +900,7 @@ "description": "Binary reverse engineering, malware analysis, firmware security, and software protection research for authorized security research, CTF competitions, and defensive security", "version": "1.0.0", "author": { - "name": "Dávid Balatoni", + "name": "D\u00e1vid Balatoni", "url": "https://github.com/balcsida" }, "homepage": "https://github.com/wshobson/agents", @@ -909,7 +909,7 @@ }, { "name": "conductor", - "description": "Context-Driven Development plugin that transforms Claude Code into a project management tool with structured workflow: Context → Spec & Plan → Implement", + "description": "Context-Driven Development plugin that transforms Claude Code into a project management tool with structured workflow: Context \u2192 Spec & Plan \u2192 Implement", "version": "1.2.1", "author": { "name": "Seth Hobson", @@ -1002,7 +1002,7 @@ "url": "https://github.com/Anasss/qa-orchestra.git", "path": "." }, - "description": "Multi-agent QA toolkit with 10 specialized agents covering the full QA lifecycle — orchestrator, environment-manager, functional-reviewer, test-scenario-designer, browser-validator, automation-writer, manual-validator, bug-reporter, release-analyzer, and smart-test-selector. Stack-agnostic, output-chained, designed around live validation via Chrome MCP.", + "description": "Multi-agent QA toolkit with 10 specialized agents covering the full QA lifecycle \u2014 orchestrator, environment-manager, functional-reviewer, test-scenario-designer, browser-validator, automation-writer, manual-validator, bug-reporter, release-analyzer, and smart-test-selector. Stack-agnostic, output-chained, designed around live validation via Chrome MCP.", "version": "1.0.0", "author": { "name": "Anass Rach", @@ -1015,7 +1015,7 @@ { "name": "protect-mcp", "source": "./plugins/protect-mcp", - "description": "Cedar policy enforcement + Ed25519 signed receipts for every Claude Code tool call. First cryptographic governance plugin — decisions are policy-gated before they run and every decision produces a tamper-evident receipt verifiable offline.", + "description": "Cedar policy enforcement + Ed25519 signed receipts for every Claude Code tool call. First cryptographic governance plugin \u2014 decisions are policy-gated before they run and every decision produces a tamper-evident receipt verifiable offline.", "version": "0.1.0", "author": { "name": "Tom Farley", @@ -1041,6 +1041,21 @@ "license": "MIT", "category": "governance", "keywords": ["tutorial", "skill", "recipe", "audit", "governance", "cedar", "receipts", "ed25519"] + }, + { + "name": "review-agent-governance", + "source": "./plugins/review-agent-governance", + "description": "Require a human approval signal before an AI agent can post PR reviews, comments, merges, or writes to CI configuration. Joins protect-mcp and signed-audit-trails in the governance category; composes with protect-mcp for runtime enforcement.", + "version": "0.1.0", + "author": { + "name": "Tom Farley", + "email": "tommy@scopeblind.com", + "url": "https://github.com/tomjwxf" + }, + "homepage": "https://veritasacta.com", + "license": "MIT", + "category": "governance", + "keywords": ["review", "governance", "cedar", "receipts", "human-approval", "pr-review", "ci-guard"] } ] } diff --git a/plugins/review-agent-governance/.claude-plugin/plugin.json b/plugins/review-agent-governance/.claude-plugin/plugin.json new file mode 100644 index 0000000..972f4bb --- /dev/null +++ b/plugins/review-agent-governance/.claude-plugin/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "review-agent-governance", + "version": "0.1.0", + "description": "Require a human approval signal before an AI agent can post PR reviews, comments, merges, or writes to CI config. Cedar-gated, receipt-signed, designed for the Hermes-style failure mode where a review bot posts without oversight.", + "author": { + "name": "Tom Farley", + "email": "tommy@scopeblind.com" + }, + "license": "MIT" +} diff --git a/plugins/review-agent-governance/README.md b/plugins/review-agent-governance/README.md new file mode 100644 index 0000000..f716747 --- /dev/null +++ b/plugins/review-agent-governance/README.md @@ -0,0 +1,181 @@ +# review-agent-governance + +Require a human approval signal before an AI agent can post PR reviews, +comments, merges, or writes to CI configuration. Built on +[`protect-mcp`](https://www.npmjs.com/package/protect-mcp) + Cedar, with +every decision producing an Ed25519-signed receipt that verifies offline. + +## The failure mode this addresses + +AI agents that post to review surfaces (PR comments, approvals, merges, +CI workflow edits) can take actions that affect other contributors, +regulated systems, and the integrity of the codebase itself. When the +agent hallucinates, mis-reads context, or is tricked into acting +incorrectly, the damage is immediate and visible: bogus reviews show up +under a real account, merges happen that should not, workflow files get +rewritten. + +This is not a hypothetical. Review bots have posted mass hallucinated +review comments, approved PRs they should not have approved, and edited +workflow files in ways that compromised other security controls. The +pattern is common enough to name: an automated agent is given scope to +act on review surfaces, and the lack of a human gate at the moment of +action is what turns a localized bug into a public incident. + +## What the plugin does + +Two hooks run around every Claude Code tool call: + +1. **`PreToolUse`** checks for a human approval flag. If absent, evaluates + a Cedar policy (`./review-governance.cedar`) that forbids review-surface + actions unconditionally. Cedar deny means the tool call exits with code + 2 and Claude Code blocks it. + +2. **`PostToolUse`** signs an Ed25519 receipt of the attempt, whether it + was approved, denied, or skipped. The receipt chain records exactly + which actions were authorized and when. + +Approved windows are opened by creating a `./.review-approved` flag file, +or by running the `/approve-review` slash command shipped with this plugin. +The window stays open until the flag is removed. + +## What gets gated + +The default policy forbids (unless approved): + +- **`gh pr review`, `gh pr comment`, `gh pr merge`, `gh pr close`, `gh pr edit`** +- **`gh issue comment`, `gh issue close`, `gh issue edit`** +- **`gh release create`, `gh release edit`** +- **`gh api repos`** (catches arbitrary GitHub REST calls) +- **GitLab / Bitbucket equivalents** (`glab mr comment` etc.) +- **`git push` to `main`, `master`, `release`, `production`** +- **Writes to `.github/workflows/`, `.gitlab-ci.yml`, `.circleci/config.yml`** +- **`WebFetch` POSTs to `api.github.com`, `hooks.slack.com`, Discord** + +Everything else passes through. This plugin is focused on the review +surface; use it alongside [protect-mcp](../protect-mcp/) if you want +general tool-call policy enforcement. + +## Installation + +```bash +claude plugin install wshobson/agents/review-agent-governance +``` + +Copy the default policy into your project: + +```bash +cp .claude/plugins/review-agent-governance/policies/review-agent-governance.cedar \ + ./review-governance.cedar +``` + +Then either: + +- **(Recommended)** keep hooks active for every session and open approval + windows explicitly before review actions, or +- Set `REVIEW_APPROVAL_FLAG=./never-approve` to effectively disable the + approval bypass (forces every review action through Cedar). + +## Opening an approval window + +### Flag file + +```bash +touch ./.review-approved +# Let the agent perform the approved action +rm ./.review-approved +``` + +### Slash command (from inside Claude Code) + +``` +/approve-review "Posting the code review for #123" +``` + +The command creates `./.review-approved` with a note describing the +approval reason and writes an approval-granted receipt before opening the +window. + +### Listing pending or denied actions + +``` +/list-pending +``` + +Walks the receipt chain at `./review-receipts/` and prints any recent +`decision: deny` entries, so you can see what the agent tried to do that +was blocked. + +## Example session + +An agent working on a PR wants to post a review comment. Without approval: + +``` +$ agent: gh pr review 42 --comment --body "LGTM" + → PreToolUse hook runs + → No ./.review-approved file, policy evaluates + → Cedar: forbid on context.command_pattern == "gh pr review" + → Exit 2: Claude Code blocks the tool call + → PostToolUse runs, signs a receipt with decision=deny +``` + +With approval: + +``` +$ touch ./.review-approved +$ agent: gh pr review 42 --comment --body "LGTM" + → PreToolUse hook runs + → ./.review-approved present, exit 0 + → Tool call proceeds + → PostToolUse signs a receipt (decision=allow, reason=human_approved) +$ rm ./.review-approved +``` + +The receipt chain at `./review-receipts/` records both attempts: the +initial deny and the subsequent allow after approval. An auditor reading +the chain later can see exactly which actions were human-gated and when. + +## Composing with protect-mcp + +This plugin focuses on review-surface actions specifically. For general +policy enforcement across all Claude Code tool calls, install +[protect-mcp](../protect-mcp/) alongside it. They compose naturally: + +- `protect-mcp` evaluates a general policy (e.g., deny `rm -rf`, restrict + `Write` to project root) for every tool call +- `review-agent-governance` adds the review-surface gate on top + +Both hooks run, both produce receipts. Configure different receipt +directories (`./receipts/` and `./review-receipts/`) to keep the chains +separate if that helps your audit workflow. + +## Why Cedar, why receipts + +**Cedar** (AWS's open authorization engine) expresses policy declaratively +and formally. Reviewers read the policy to understand exactly what is +gated without reading code. Policies type-check with `cedar validate`. +Changes to the policy are diffable. + +**Ed25519 receipts** (RFC 8032, JCS canonicalization per RFC 8785, +hash-chained) provide tamper-evident evidence that does not depend on the +operator. Any party with the public key can run +`npx @veritasacta/verify ./review-receipts/*.json` and get an exit code +that proves every receipt is authentic and the chain is intact. If any +receipt was altered after signing, verification fails with exit 1. + +## Standards + +- **Ed25519** (RFC 8032) for receipt signatures +- **JCS** (RFC 8785) for deterministic canonicalization before signing +- **Cedar** (AWS) for declarative, formally verifiable policy evaluation +- **IETF draft** [draft-farley-acta-signed-receipts](https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/) for receipt format + +## Related + +- [`protect-mcp`](../protect-mcp/) — general Cedar + receipt enforcement + for all Claude Code tool calls +- [`protect-mcp` on npm](https://www.npmjs.com/package/protect-mcp) — the + runtime this plugin depends on +- [`@veritasacta/verify`](https://www.npmjs.com/package/@veritasacta/verify) + — offline receipt verification CLI +- [Cedar for AI agents](https://github.com/cedar-policy/cedar-for-agents) diff --git a/plugins/review-agent-governance/agents/review-policy-author.md b/plugins/review-agent-governance/agents/review-policy-author.md new file mode 100644 index 0000000..d841f12 --- /dev/null +++ b/plugins/review-agent-governance/agents/review-policy-author.md @@ -0,0 +1,164 @@ +--- +name: review-policy-author +description: Cedar policy author specialized in gating AI agent review actions (PR comments, reviews, merges, CI edits) behind human approval. Use when writing, auditing, or extending a review-governance.cedar policy for review-bot governance. +model: sonnet +--- + +# Review Policy Author + +You are a Cedar policy expert specializing in review-surface gating: the set +of rules that decide whether an AI agent is allowed to post reviews, comment +on issues, merge pull requests, or edit CI configuration without human +approval. + +## What you know + +You understand the failure mode this policy class prevents. An AI agent with +unrestricted access to GitHub CLI or the GitHub API can post hallucinated +reviews, approve PRs with fabricated reasoning, close issues incorrectly, or +edit workflow files in ways that quietly bypass other security controls. The +damage is immediate, visible, and often attributed to the account running +the agent. Review-surface gating is the pattern that prevents this class of +incident. + +You know the specific command patterns and paths that make up the review +surface on each major platform: + +**GitHub (via `gh` CLI):** +`gh pr review`, `gh pr comment`, `gh pr merge`, `gh pr close`, `gh pr edit`, +`gh pr ready`, `gh issue comment`, `gh issue close`, `gh issue edit`, +`gh release create`, `gh release edit`, `gh api repos/.../comments`, +`gh api repos/.../reviews`, `gh api repos/.../pulls/.../merge` + +**GitLab (via `glab`):** +`glab mr comment`, `glab mr approve`, `glab mr merge`, `glab mr close`, +`glab issue comment`, `glab issue close`, `glab release create` + +**Bitbucket:** via `bb` CLI or direct API calls. + +**CI / CD paths that must be human-gated:** +`.github/workflows/`, `.github/CODEOWNERS`, `.gitlab-ci.yml`, +`.circleci/config.yml`, `buildkite/pipeline.yml`, `Jenkinsfile`, `azure-pipelines.yml` + +**Protected branches that must be gated:** `main`, `master`, `release`, +`production`, `prod`, `stable`. + +**Notification surfaces:** Slack webhooks (`hooks.slack.com`), Discord +webhooks, Teams webhooks, PagerDuty events, any email API. + +## How to help + +When writing a review-governance policy: + +1. **Start with the plugin's default.** Copy + `./plugins/review-agent-governance/policies/review-agent-governance.cedar` + to `./review-governance.cedar` and edit from there. The defaults cover + GitHub / GitLab / protected branches / CI paths and are a sound baseline. + +2. **Extend for the project's specific surfaces.** If the team uses Linear, + Jira, Notion, or a custom review tool, add `forbid` rules for the CLI + patterns or WebFetch hosts those tools use. + +3. **Do NOT gate read-only operations.** `gh pr view`, `gh issue list`, API + GETs — all fine for agents to do unattended. The gate is on write / + post / merge / close actions only. + +4. **Gate branches by name, not by path.** Use `context.target_branch in + ["main", ...]` not `context.resource_path starts with "refs/heads/main"`. + Branch names are what humans reason about. + +5. **Include the notification surfaces.** Slack and Discord webhooks are + where review-bot hallucinations amplify. Gate POSTs to those hosts. + +6. **Leave non-review actions alone.** This policy is focused. A permissive + `permit (principal, action, resource);` at the end lets everything else + through. Combine with `protect-mcp` for broader policy enforcement. + +## Example extensions + +### Teams that use Linear for issue triage + +```cedar +forbid ( + principal, + action == Action::"Bash", + resource +) when { + context.command_pattern starts with "linear" +}; + +forbid ( + principal, + action == Action::"WebFetch", + resource +) when { + context.method == "POST" && + context.url_host == "api.linear.app" +}; +``` + +### Teams with their own internal review bot + +```cedar +forbid ( + principal, + action == Action::"WebFetch", + resource +) when { + context.method in ["POST", "PUT", "PATCH", "DELETE"] && + context.url_host in [ + "review-bot.internal.company.com", + "code-review.internal.company.com" + ] +}; +``` + +### Teams that want to allow a specific bot account + +If the team wants to allow an agent running under a dedicated "automation" +identity but not a developer's personal account: + +```cedar +permit ( + principal == Principal::"gh-bot-reviewer", + action == Action::"Bash", + resource +) when { + context.command_pattern in ["gh pr comment"] +}; + +forbid ( + principal, + action == Action::"Bash", + resource +) unless { + principal == Principal::"gh-bot-reviewer" || + context.human_approved == true +}; +``` + +## Auditing an existing policy + +When reviewing a `review-governance.cedar`: + +1. Confirm every review-surface CLI command the team uses has a matching + `forbid` rule. +2. Check for gaps in API coverage. `gh api repos` catches arbitrary GitHub + REST calls; without it, an agent can `gh api repos/X/Y/pulls/42/reviews` + and bypass command-pattern-based rules. +3. Verify protected-branch `git push` rules cover every branch that is + actually protected in the repo settings. +4. Confirm CI / CD path rules match the files that actually gate behavior + in this project (for example, some teams use `deployment/` instead of + `.github/workflows/`). +5. Check that the default-allow rule at the end does not override an + earlier `forbid`. Cedar `forbid` is authoritative; a later `permit` + does not lift it. + +## References + +- [protect-mcp docs](https://www.npmjs.com/package/protect-mcp) — runtime + this plugin depends on +- [Cedar language reference](https://docs.cedarpolicy.com/) +- [Cedar for AI agents](https://github.com/cedar-policy/cedar-for-agents) +- The plugin's default policy at `../policies/review-agent-governance.cedar` diff --git a/plugins/review-agent-governance/commands/approve-review.md b/plugins/review-agent-governance/commands/approve-review.md new file mode 100644 index 0000000..e4a0ab5 --- /dev/null +++ b/plugins/review-agent-governance/commands/approve-review.md @@ -0,0 +1,98 @@ +--- +description: "Open a review-action approval window by creating the ./.review-approved flag file. Takes an optional reason string that is embedded in the receipt chain." +argument-hint: "[reason for approval]" +--- + +# Approve Review + +Open a human-approval window for review-surface actions (PR reviews, +comments, merges, CI edits). The window stays open until you remove the +flag file with `rm ./.review-approved` or restart the session. + +## Usage + +``` +/approve-review "Approving LGTM on PR #42 after visual inspection" +/approve-review # no reason, still opens the window +``` + +## What this does + +1. Creates a `./.review-approved` flag file in the project root. +2. If the user provided a reason, writes it into the file and into a + timestamped entry under `./review-receipts/approvals/`. +3. Prints a confirmation with the timestamp and, if provided, the reason. +4. Reminds the user to close the window with `rm ./.review-approved` as + soon as the approved action completes. + +## Implementation + +Run this in the Bash tool: + +```bash +REASON="${1:-}" +TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)" +FLAG="./.review-approved" + +# Write the flag file +{ + echo "approved_at=$TS" + if [ -n "$REASON" ]; then + echo "reason=$REASON" + fi +} > "$FLAG" + +# Record the approval in the receipt-adjacent log +mkdir -p ./review-receipts/approvals +cat > "./review-receipts/approvals/$TS.json" < 72: + summary = summary[:69] + "..." + policy = r.get("policy_id", "unknown") + print(f" {ts} {tool:10} {summary}") + print(f" policy={policy} receipt={f.name}") + print() + +print("To approve one of these and retry, run:") +print(' /approve-review ""') +print("Then retry the original tool call.") +print() +print(f"To audit the full chain: npx @veritasacta/verify $RECEIPTS_DIR/*.json") +PY +``` + +## What to show the user + +``` +Recent denials (most recent first, top 10): + + 2026-04-17T14:23:01Z Bash gh pr review 42 --approve --body 'LGTM' + policy=review-agent-governance receipt=2026-04-17T14-23-01Z.json + + 2026-04-17T14:22:45Z Write .github/workflows/ci.yml + policy=review-agent-governance receipt=2026-04-17T14-22-45Z.json + + 2026-04-17T14:20:11Z Bash gh issue comment 18 --body '...' + policy=review-agent-governance receipt=2026-04-17T14-20-11Z.json + +To approve one of these and retry, run: + /approve-review "" +Then retry the original tool call. + +To audit the full chain: npx @veritasacta/verify ./review-receipts/*.json +``` + +## When there are no denials + +``` +No denied actions found. The review-governance policy is not currently +blocking anything. +``` + +This is the common state. It means either the agent has not attempted any +review-surface actions, or the approval flag has been present for every +attempt. + +## Notes + +- Denials recorded before the current `./review-receipts/` directory was + created will not appear here. Use `@veritasacta/verify` directly against + any older receipt location. +- The command does not modify the receipt chain. It only reads. +- `./review-receipts/approvals/` (the log of explicit approvals) is + excluded from this listing since those are not tool-call receipts. + +## References + +- Approve an action: `/approve-review ""` +- Verify the chain: `npx @veritasacta/verify ./review-receipts/*.json` +- Plugin README: `../README.md` diff --git a/plugins/review-agent-governance/hooks/hooks.json b/plugins/review-agent-governance/hooks/hooks.json new file mode 100644 index 0000000..46e1b5e --- /dev/null +++ b/plugins/review-agent-governance/hooks/hooks.json @@ -0,0 +1,22 @@ +{ + "hooks": { + "PreToolUse": [ + { + "matcher": ".*", + "hook": { + "type": "command", + "command": "if [ -f \"${REVIEW_APPROVAL_FLAG:-./.review-approved}\" ]; then exit 0; fi; npx protect-mcp@latest evaluate --policy \"${REVIEW_GOVERNANCE_POLICY:-./review-governance.cedar}\" --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" + } + } + ], + "PostToolUse": [ + { + "matcher": ".*", + "hook": { + "type": "command", + "command": "npx protect-mcp@latest sign --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --output \"$TOOL_OUTPUT\" --receipts \"${REVIEW_GOVERNANCE_RECEIPTS:-./review-receipts/}\" --key \"${REVIEW_GOVERNANCE_KEY:-./review-governance.key}\"" + } + } + ] + } +} diff --git a/plugins/review-agent-governance/policies/review-agent-governance.cedar b/plugins/review-agent-governance/policies/review-agent-governance.cedar new file mode 100644 index 0000000..2896129 --- /dev/null +++ b/plugins/review-agent-governance/policies/review-agent-governance.cedar @@ -0,0 +1,103 @@ +// review-agent-governance: default Cedar policy +// +// Forbids an AI agent from taking consequential review actions without an +// explicit human approval signal. A human opens a short approval window by +// creating a ./.review-approved flag file (or using the /approve-review +// slash command shipped with this plugin). When the flag is present, the +// PreToolUse hook short-circuits to permit; when it is absent, this policy +// evaluates. +// +// Every tool call, approved or not, still produces an Ed25519 receipt via +// the PostToolUse hook. The chain records what was approved and when. + +// ───────────────────────────────────────────────────────────────────────── +// Forbid rules: the set of actions that require human approval +// ───────────────────────────────────────────────────────────────────────── + +// 1. Posting review-surface GitHub actions via gh CLI +forbid ( + principal, + action == Action::"Bash", + resource +) when { + context.command_pattern in [ + "gh pr review", + "gh pr comment", + "gh pr close", + "gh pr merge", + "gh pr edit", + "gh issue comment", + "gh issue close", + "gh issue edit", + "gh release create", + "gh release edit", + "gh api repos" + ] +}; + +// 2. Posting via GitLab / Bitbucket CLIs +forbid ( + principal, + action == Action::"Bash", + resource +) when { + context.command_pattern in [ + "glab mr comment", + "glab mr approve", + "glab mr merge", + "glab issue comment" + ] +}; + +// 3. Git operations on protected branches +forbid ( + principal, + action == Action::"Bash", + resource +) when { + context.command_pattern in ["git push", "git push --force", "git push -f"] && + context.target_branch in ["main", "master", "release", "production"] +}; + +// 4. Direct writes to CI / CD configuration paths. Modifying these files lets +// an agent change how future builds or reviews run, bypassing every other +// safeguard. Always require human approval. +forbid ( + principal, + action in [Action::"Write", Action::"Edit"], + resource +) when { + context.path_starts_with in [ + ".github/workflows/", + ".github/CODEOWNERS", + ".gitlab-ci.yml", + ".circleci/config.yml", + "buildkite/pipeline.yml" + ] +}; + +// 5. WebFetch POSTs to known review / chat platforms +forbid ( + principal, + action == Action::"WebFetch", + resource +) when { + context.method == "POST" && + context.url_host in [ + "api.github.com", + "api.gitlab.com", + "api.bitbucket.org", + "hooks.slack.com", + "discord.com" + ] +}; + +// ───────────────────────────────────────────────────────────────────────── +// Permit everything else +// +// This plugin is focused. Non-review actions pass through this policy +// unchanged. Run it alongside protect-mcp if you want general tool-call +// policy enforcement too. +// ───────────────────────────────────────────────────────────────────────── + +permit (principal, action, resource); diff --git a/plugins/review-agent-governance/skills/review-agent-setup/SKILL.md b/plugins/review-agent-governance/skills/review-agent-setup/SKILL.md new file mode 100644 index 0000000..e54182b --- /dev/null +++ b/plugins/review-agent-governance/skills/review-agent-setup/SKILL.md @@ -0,0 +1,178 @@ +--- +name: review-agent-setup +description: Configure human-in-the-loop gating for AI agent review actions in Claude Code. Use when setting up a project where an agent may post PR reviews, comments, merges, or edit CI configuration, and you want a cryptographically auditable approval trail with Cedar-enforced gates. +--- + +# review-agent-governance — Setup + +Gate AI agent review actions (PR reviews, comments, merges, CI edits) behind +explicit human approval. Every attempt, approved or denied, produces an +Ed25519-signed receipt. + +## When to use this plugin + +Install it in projects where a Claude Code agent: + +- Reviews, comments on, or merges pull requests (`gh pr review`, `gh pr merge`) +- Triages issues (`gh issue comment`, `gh issue close`) +- Publishes releases (`gh release create`) +- Modifies CI configuration (`.github/workflows/`, `.gitlab-ci.yml`) +- Pushes to protected branches (`main`, `master`, `release`, `production`) +- Posts to external notification surfaces (Slack webhooks, Discord) + +If the agent is only doing local file edits and running tests, this plugin is +overkill. Use `protect-mcp` for general tool-call policy enforcement and skip +this one. + +## One-time setup + +### 1. Install the plugin + +```bash +claude plugin install wshobson/agents/review-agent-governance +``` + +### 2. Copy the default policy to your project + +```bash +cp .claude/plugins/review-agent-governance/policies/review-agent-governance.cedar \ + ./review-governance.cedar +``` + +You can edit this file to match your project's specific rules. See +`../agents/review-policy-author.md` for guidance on authoring review +policies. + +### 3. Create a receipts directory and sign key + +```bash +mkdir -p ./review-receipts +echo "./review-receipts/" >> .gitignore +echo "./review-governance.key" >> .gitignore +echo "./.review-approved" >> .gitignore +``` + +The first invocation of `protect-mcp sign` will create the key. Commit the +public key from the first receipt so auditors can verify later. + +## Per-session workflow + +The Cedar policy denies review-surface actions unconditionally. To approve +a specific action, open an approval window before it and close it after. + +### Flag file (simplest) + +```bash +# Before the action you want to approve +touch ./.review-approved + +# Let Claude Code run the review / comment / merge + +# Immediately after +rm ./.review-approved +``` + +### Slash command (from within Claude Code) + +``` +/approve-review "Reviewing PR #123 authored by contributor X" +``` + +This creates `./.review-approved` with the given reason embedded as a note, +and writes a human-approved receipt to the chain. A follow-up `rm` is still +needed to close the window. + +### Dry-run everything (force full policy evaluation) + +If you want every tool call to go through Cedar with no approval bypass: + +```bash +export REVIEW_APPROVAL_FLAG=./.never-approve +``` + +Any tool call matching a forbid rule will be denied; approved windows have +no effect. Useful for CI or for a locked-down audit run. + +## Verifying the chain + +List all receipts: + +```bash +ls -la ./review-receipts/ +``` + +Verify the entire chain offline: + +```bash +npx @veritasacta/verify ./review-receipts/*.json +``` + +Exit 0 means every receipt is authentic and the chain is intact. Exit 1 +means one receipt has been tampered with. Exit 2 means a receipt is +malformed. + +Look at recent denials: + +``` +/list-pending +``` + +Within Claude Code this slash command walks the receipt chain and prints +any recent `decision: deny` entries with the tool name, command pattern, +and timestamp. + +## Example: approving a PR review + +```bash +# 1. Human reviews the agent's proposed comment +$ /list-pending + Recent denials: + - 2026-04-17T14:23:01Z Bash "gh pr review 42 --approve --body 'LGTM'" + - 2026-04-17T14:23:02Z Bash "gh pr comment 42 --body 'Looking good'" + +# 2. Human decides the first one is appropriate, approves it +$ /approve-review "Approving LGTM on PR 42 after visual inspection" + ./.review-approved created + +# 3. Agent retries the action; this time it succeeds +$ agent: gh pr review 42 --approve --body "LGTM" + [receipt: rec_XXX, decision=allow, reason=human_approved] + +# 4. Human closes the window +$ rm ./.review-approved +``` + +Every step is in the receipt chain. The chain is offline-verifiable for +regulators, counterparties, or downstream auditors who want to confirm +that no review action bypassed the human gate. + +## Composing with protect-mcp + +If both plugins are installed, run them side by side: + +```json +{ + "hooks": { + "PreToolUse": [ + { "matcher": ".*", "hook": { + "type": "command", + "command": "npx protect-mcp@latest evaluate --policy ./protect.cedar --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" + } }, + { "matcher": ".*", "hook": { + "type": "command", + "command": "if [ -f ./.review-approved ]; then exit 0; fi; npx protect-mcp@latest evaluate --policy ./review-governance.cedar --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" + } } + ] + } +} +``` + +Both hooks must pass for the tool call to proceed. Cedar deny in either +policy blocks it. + +## Standards + +- **Ed25519** — RFC 8032 (digital signatures) +- **JCS** — RFC 8785 (deterministic JSON canonicalization) +- **Cedar** — AWS's open authorization policy language +- **IETF draft** — [draft-farley-acta-signed-receipts](https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/) From cb381c47d1b58e6766849a4c84a0872a1e0dd8ef Mon Sep 17 00:00:00 2001 From: tommylauren Date: Fri, 17 Apr 2026 13:48:53 -0400 Subject: [PATCH 2/5] fix: address @wshobson review feedback on #495 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 #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 #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 --- .claude-plugin/marketplace.json | 10 +++--- plugins/review-agent-governance/README.md | 31 +++++++++++++++++-- .../commands/approve-review.md | 19 +++++++++--- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index f931ad0..b223296 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -13,7 +13,7 @@ { "name": "documentation-standards", "source": "./plugins/documentation-standards", - "description": "HADS (Human-AI Document Standard) \u2014 semantic tagging convention for writing docs that work efficiently for both humans and AI models. Reduces token consumption by separating machine-critical facts from human context.", + "description": "HADS (Human-AI Document Standard) — semantic tagging convention for writing docs that work efficiently for both humans and AI models. Reduces token consumption by separating machine-critical facts from human context.", "version": "1.0.0", "author": { "name": "Niksa Barlovic", @@ -900,7 +900,7 @@ "description": "Binary reverse engineering, malware analysis, firmware security, and software protection research for authorized security research, CTF competitions, and defensive security", "version": "1.0.0", "author": { - "name": "D\u00e1vid Balatoni", + "name": "Dávid Balatoni", "url": "https://github.com/balcsida" }, "homepage": "https://github.com/wshobson/agents", @@ -909,7 +909,7 @@ }, { "name": "conductor", - "description": "Context-Driven Development plugin that transforms Claude Code into a project management tool with structured workflow: Context \u2192 Spec & Plan \u2192 Implement", + "description": "Context-Driven Development plugin that transforms Claude Code into a project management tool with structured workflow: Context → Spec & Plan → Implement", "version": "1.2.1", "author": { "name": "Seth Hobson", @@ -1002,7 +1002,7 @@ "url": "https://github.com/Anasss/qa-orchestra.git", "path": "." }, - "description": "Multi-agent QA toolkit with 10 specialized agents covering the full QA lifecycle \u2014 orchestrator, environment-manager, functional-reviewer, test-scenario-designer, browser-validator, automation-writer, manual-validator, bug-reporter, release-analyzer, and smart-test-selector. Stack-agnostic, output-chained, designed around live validation via Chrome MCP.", + "description": "Multi-agent QA toolkit with 10 specialized agents covering the full QA lifecycle — orchestrator, environment-manager, functional-reviewer, test-scenario-designer, browser-validator, automation-writer, manual-validator, bug-reporter, release-analyzer, and smart-test-selector. Stack-agnostic, output-chained, designed around live validation via Chrome MCP.", "version": "1.0.0", "author": { "name": "Anass Rach", @@ -1015,7 +1015,7 @@ { "name": "protect-mcp", "source": "./plugins/protect-mcp", - "description": "Cedar policy enforcement + Ed25519 signed receipts for every Claude Code tool call. First cryptographic governance plugin \u2014 decisions are policy-gated before they run and every decision produces a tamper-evident receipt verifiable offline.", + "description": "Cedar policy enforcement + Ed25519 signed receipts for every Claude Code tool call. First cryptographic governance plugin — decisions are policy-gated before they run and every decision produces a tamper-evident receipt verifiable offline.", "version": "0.1.0", "author": { "name": "Tom Farley", diff --git a/plugins/review-agent-governance/README.md b/plugins/review-agent-governance/README.md index f716747..0c6a8e4 100644 --- a/plugins/review-agent-governance/README.md +++ b/plugins/review-agent-governance/README.md @@ -93,8 +93,24 @@ rm ./.review-approved ``` The command creates `./.review-approved` with a note describing the -approval reason and writes an approval-granted receipt before opening the -window. +approval reason and appends a JSON entry under +`./review-receipts/approvals/`. + +**Important note on the approval log:** entries under +`./review-receipts/approvals/*.json` are **plain JSON records, not signed +receipts**. They do not flow through `protect-mcp sign`, so +`@veritasacta/verify` does not cover them. The approval log is +operator-trust; it records what the human intended to approve but can be +edited after the fact without detection. + +What IS signed and tamper-evident: the `PostToolUse` tool-call receipts +that every action (allowed or denied) produces under +`./review-receipts/*.json`. Those are the authoritative audit trail. Use +`npx @veritasacta/verify ./review-receipts/*.json` to verify them. + +If you need signed approval records as well (for regulated environments), +run them through protect-mcp directly, or emit them as separate receipts +via `npx protect-mcp@latest sign --tool approve-review --input ...`. ### Listing pending or denied actions @@ -106,6 +122,17 @@ Walks the receipt chain at `./review-receipts/` and prints any recent `decision: deny` entries, so you can see what the agent tried to do that was blocked. +### A note on what the signed chain covers + +When the approval flag is present, the `PreToolUse` hook short-circuits +to `exit 0` without calling `protect-mcp evaluate`. The downstream +`PostToolUse` receipt for that approved action will therefore have +`decision: allow` but no `policy_digest` field, because no Cedar policy +was evaluated. Auditors walking the chain should expect this: an approved +tool call shows up as a signed receipt with `reason: human_approved` and +no policy reference. Denied tool calls and non-review actions (which do +go through Cedar) carry the `policy_digest` as usual. + ## Example session An agent working on a PR wants to post a review comment. Without approval: diff --git a/plugins/review-agent-governance/commands/approve-review.md b/plugins/review-agent-governance/commands/approve-review.md index e4a0ab5..b936526 100644 --- a/plugins/review-agent-governance/commands/approve-review.md +++ b/plugins/review-agent-governance/commands/approve-review.md @@ -27,14 +27,20 @@ flag file with `rm ./.review-approved` or restart the session. ## Implementation -Run this in the Bash tool: +Run this in the Bash tool. Capture the full user argument as `$ARGUMENTS` +(the marketplace slash-command convention) so a reason with spaces is +preserved verbatim. ```bash -REASON="${1:-}" +REASON="$ARGUMENTS" TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)" FLAG="./.review-approved" -# Write the flag file +# JSON-escape the reason so quotes, backslashes, newlines do not break +# the approval-record JSON below. +REASON_ESCAPED="$(printf '%s' "$REASON" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')" + +# Write the flag file (human-readable key=value, not JSON). { echo "approved_at=$TS" if [ -n "$REASON" ]; then @@ -42,12 +48,15 @@ FLAG="./.review-approved" fi } > "$FLAG" -# Record the approval in the receipt-adjacent log +# Record the approval. This is a plain JSON log file, NOT a signed +# receipt. The README explicitly notes that approval records are not +# signed by protect-mcp; only the PostToolUse tool-call receipts flow +# through the signer. mkdir -p ./review-receipts/approvals cat > "./review-receipts/approvals/$TS.json" < Date: Sat, 18 Apr 2026 20:10:26 -0400 Subject: [PATCH 3/5] fix(review-agent-governance): pin protect-mcp@0.5.5 in hooks.json Resolves wshobson's blocker: npx protect-mcp@latest reintroduces the reproducibility gap closed by #497 for the protect-mcp plugin. Pins both PreToolUse and PostToolUse hook invocations to 0.5.5. --- plugins/review-agent-governance/hooks/hooks.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/review-agent-governance/hooks/hooks.json b/plugins/review-agent-governance/hooks/hooks.json index 46e1b5e..1b8ae95 100644 --- a/plugins/review-agent-governance/hooks/hooks.json +++ b/plugins/review-agent-governance/hooks/hooks.json @@ -5,7 +5,7 @@ "matcher": ".*", "hook": { "type": "command", - "command": "if [ -f \"${REVIEW_APPROVAL_FLAG:-./.review-approved}\" ]; then exit 0; fi; npx protect-mcp@latest evaluate --policy \"${REVIEW_GOVERNANCE_POLICY:-./review-governance.cedar}\" --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" + "command": "if [ -f \"${REVIEW_APPROVAL_FLAG:-./.review-approved}\" ]; then exit 0; fi; npx protect-mcp@0.5.5 evaluate --policy \"${REVIEW_GOVERNANCE_POLICY:-./review-governance.cedar}\" --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" } } ], @@ -14,7 +14,7 @@ "matcher": ".*", "hook": { "type": "command", - "command": "npx protect-mcp@latest sign --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --output \"$TOOL_OUTPUT\" --receipts \"${REVIEW_GOVERNANCE_RECEIPTS:-./review-receipts/}\" --key \"${REVIEW_GOVERNANCE_KEY:-./review-governance.key}\"" + "command": "npx protect-mcp@0.5.5 sign --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --output \"$TOOL_OUTPUT\" --receipts \"${REVIEW_GOVERNANCE_RECEIPTS:-./review-receipts/}\" --key \"${REVIEW_GOVERNANCE_KEY:-./review-governance.key}\"" } } ] From 02e77c58caf890554d3d790b8a7c65d90a2a7103 Mon Sep 17 00:00:00 2001 From: Tom Farley Date: Sun, 26 Apr 2026 19:53:53 -0400 Subject: [PATCH 4/5] fix(review-agent-governance): use current hooks array schema Migrates plugins/review-agent-governance/hooks/hooks.json from the deprecated singular "hook": {...} shape to the current "hooks": [{...}] array shape, matching the schema fix that landed in #503 for plugins/protect-mcp/hooks/hooks.json. Same conversion applied to both PreToolUse and PostToolUse blocks: Before: { "matcher": ".*", "hook": {"type": "command", ...} } After: { "matcher": ".*", "hooks": [{"type": "command", ...}] } Verified the resulting structure matches the post-#503 shape used by plugins/protect-mcp/hooks/hooks.json byte-for-byte at the schema level. Without this fix, current Claude Code reports "path: hooks.PreToolUse.0.hooks - expected array, received undefined" on plugin load. --- .../review-agent-governance/hooks/hooks.json | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/plugins/review-agent-governance/hooks/hooks.json b/plugins/review-agent-governance/hooks/hooks.json index 1b8ae95..18a5289 100644 --- a/plugins/review-agent-governance/hooks/hooks.json +++ b/plugins/review-agent-governance/hooks/hooks.json @@ -3,19 +3,23 @@ "PreToolUse": [ { "matcher": ".*", - "hook": { - "type": "command", - "command": "if [ -f \"${REVIEW_APPROVAL_FLAG:-./.review-approved}\" ]; then exit 0; fi; npx protect-mcp@0.5.5 evaluate --policy \"${REVIEW_GOVERNANCE_POLICY:-./review-governance.cedar}\" --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" - } + "hooks": [ + { + "type": "command", + "command": "if [ -f \"${REVIEW_APPROVAL_FLAG:-./.review-approved}\" ]; then exit 0; fi; npx protect-mcp@0.5.5 evaluate --policy \"${REVIEW_GOVERNANCE_POLICY:-./review-governance.cedar}\" --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" + } + ] } ], "PostToolUse": [ { "matcher": ".*", - "hook": { - "type": "command", - "command": "npx protect-mcp@0.5.5 sign --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --output \"$TOOL_OUTPUT\" --receipts \"${REVIEW_GOVERNANCE_RECEIPTS:-./review-receipts/}\" --key \"${REVIEW_GOVERNANCE_KEY:-./review-governance.key}\"" - } + "hooks": [ + { + "type": "command", + "command": "npx protect-mcp@0.5.5 sign --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --output \"$TOOL_OUTPUT\" --receipts \"${REVIEW_GOVERNANCE_RECEIPTS:-./review-receipts/}\" --key \"${REVIEW_GOVERNANCE_KEY:-./review-governance.key}\"" + } + ] } ] } From 1ca21d893b9fc33e4ad7c2fff1d9d23d277d7242 Mon Sep 17 00:00:00 2001 From: Seth Hobson Date: Mon, 27 Apr 2026 20:27:59 -0400 Subject: [PATCH 5/5] docs(review-agent-governance): fix SKILL.md compose example Update the "Composing with protect-mcp" example to use the current hooks array schema and pin protect-mcp@0.5.5, matching the runtime hooks.json. Prevents users from copy-pasting a config that current Claude Code refuses to load. --- .../skills/review-agent-setup/SKILL.md | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/plugins/review-agent-governance/skills/review-agent-setup/SKILL.md b/plugins/review-agent-governance/skills/review-agent-setup/SKILL.md index e54182b..0bee6ad 100644 --- a/plugins/review-agent-governance/skills/review-agent-setup/SKILL.md +++ b/plugins/review-agent-governance/skills/review-agent-setup/SKILL.md @@ -154,14 +154,24 @@ If both plugins are installed, run them side by side: { "hooks": { "PreToolUse": [ - { "matcher": ".*", "hook": { - "type": "command", - "command": "npx protect-mcp@latest evaluate --policy ./protect.cedar --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" - } }, - { "matcher": ".*", "hook": { - "type": "command", - "command": "if [ -f ./.review-approved ]; then exit 0; fi; npx protect-mcp@latest evaluate --policy ./review-governance.cedar --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" - } } + { + "matcher": ".*", + "hooks": [ + { + "type": "command", + "command": "npx protect-mcp@0.5.5 evaluate --policy ./protect.cedar --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" + } + ] + }, + { + "matcher": ".*", + "hooks": [ + { + "type": "command", + "command": "if [ -f ./.review-approved ]; then exit 0; fi; npx protect-mcp@0.5.5 evaluate --policy ./review-governance.cedar --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" + } + ] + } ] } }