Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions claude/auto-review/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ jobs:
| `comment_pr_findings` | ❌ | `true` | Automatically post inline PR comments for findings saved to `findings.json` |
| `force_breaking_changes_agent` | ❌ | `false` | Force breaking changes subagent regardless of file heuristic |
| `force_license_compliance_agent` | ❌ | `false` | Force license compliance agent regardless of heuristic |
| `auto_approve` | ❌ | `false` | Enable AI-powered auto-approval after review |
| `auto_approve_app_id` | When `auto_approve` is `true` | - | GitHub App ID used to generate a token for PR approval |
| `auto_approve_private_key` | When `auto_approve` is `true` | - | GitHub App private key for PR approval |
| `auto_approve_scope_prompt` | ❌ | - | Instructions telling Claude when to approve or reject. Provide repo-specific criteria |

## Usage Examples

Expand Down Expand Up @@ -293,6 +297,77 @@ The auto-review action includes a specialized breaking changes subagent that is

**Force override:** Set `force_breaking_changes_agent: "true"` to always spawn the agent regardless of heuristic.

### Auto-Approve (AI-Powered)

The auto-approve feature lets Claude automatically approve PRs that pass review, using a repo-specific scope prompt to decide. This is useful for satisfying org-level "required approvals" rules on low-risk PRs (e.g. Terraform config changes, documentation updates).

#### How It Works

1. The normal auto-review runs (unchanged)
2. Findings are extracted into `findings.json` (unchanged)
3. Claude evaluates the diff, changed files, and review findings against your `auto_approve_scope_prompt`
4. If Claude decides the PR is safe, a GitHub App token is generated and the PR is approved
5. If Claude decides the PR is unsafe (or has CRITICAL/HIGH findings), approval is skipped

#### Setup

**1. Create a GitHub App** in your org (Settings → Developer settings → GitHub Apps → New GitHub App):
- **Name**: e.g. `Claude Reviewer` (must be unique across GitHub)
- **Homepage URL**: your org's GitHub URL (required field, any URL works)
- **Permissions**: Repository permissions → **Pull Requests → Read & Write**
- **Webhook**: uncheck "Active" (no webhook needed)
- **Installation**: "Only on this account"

**2. Generate a private key**: on the App's settings page, scroll to "Private keys" → "Generate a private key". Save the downloaded `.pem` file.

**3. Install the App** on the target repository (or all repositories): App settings → "Install App" → select your org → choose repositories.

**4. Add org secrets** (Org Settings → Secrets and variables → Actions → New organization secret):
- `CLAUDE_REVIEWER_APP_ID` — the App ID (visible on the App's "General" settings page)
- `CLAUDE_REVIEWER_PRIVATE_KEY` — the full contents of the `.pem` private key file
- Set repository access to "All repositories" or select specific repos that need auto-approve

#### Usage

```yaml
- name: Claude Review
uses: WalletConnect/actions/claude/auto-review@master
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
auto_approve: "true"
auto_approve_app_id: ${{ secrets.CLAUDE_REVIEWER_APP_ID }}
auto_approve_private_key: ${{ secrets.CLAUDE_REVIEWER_PRIVATE_KEY }}
auto_approve_scope_prompt: |
Only approve Terraform infrastructure changes.
All changed files must be under infrastructure/, monitoring/, or .github/workflows/*terraform*.
If the PR includes any non-Terraform files, reject.

Do NOT approve if:
- Resources are being destroyed or removed
- Database or storage resources are deleted
- force_destroy is enabled or prevent_destroy is removed
- Any change that could cause data loss

Approve if changes are safe: new resources, variable updates, policy changes, monitoring config.
```

The scope prompt is fully customizable per repository. Other examples:

```yaml
# Documentation-only auto-approve
auto_approve_scope_prompt: |
Only approve if every changed file is documentation (.md, .txt, .rst).
Reject if any code files are modified.
```

```yaml
# Dependency update auto-approve
auto_approve_scope_prompt: |
Only approve dependency version bumps (package.json, lockfiles).
Reject if any source code files are modified.
Reject if a dependency is added or removed (only version changes are safe).
```

## Best Practices

### 1. Provide Project Context
Expand Down
78 changes: 78 additions & 0 deletions claude/auto-review/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ inputs:
description: "Force data classification agent regardless of heuristic"
required: false
default: "false"
auto_approve:
description: "Enable AI-powered auto-approval after review. When enabled, Claude evaluates the diff and review findings against the scope_prompt to decide whether to approve."
required: false
default: "false"
auto_approve_app_id:
description: "GitHub App ID used to generate a token for PR approval. Required when auto_approve is true."
required: false
auto_approve_private_key:
description: "GitHub App private key used to generate a token for PR approval. Required when auto_approve is true."
required: false
auto_approve_scope_prompt:
description: "Instructions that tell Claude when to approve or reject. Provide repo-specific criteria (e.g. 'Only approve Terraform changes that do not destroy databases or remove resources')."
required: false

runs:
using: "composite"
Expand Down Expand Up @@ -427,3 +440,68 @@ runs:

chmod +x "$SCRIPT_PATH"
node "$SCRIPT_PATH"

# ── Auto-approve (opt-in) ──────────────────────────────────────────────
- name: Validate auto-approve inputs
if: inputs.auto_approve == 'true'
shell: bash
run: |
MISSING=""
if [[ -z "$APP_ID" ]]; then MISSING="auto_approve_app_id"; fi
if [[ -z "$PRIVATE_KEY" ]]; then MISSING="${MISSING:+$MISSING, }auto_approve_private_key"; fi
if [[ -n "$MISSING" ]]; then
echo "::error::Missing required inputs for auto_approve: $MISSING"
exit 1
fi
env:
APP_ID: ${{ inputs.auto_approve_app_id }}
PRIVATE_KEY: ${{ inputs.auto_approve_private_key }}

- name: Evaluate auto-approve
if: inputs.auto_approve == 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
AUTO_APPROVE_MODEL: ${{ inputs.model }}
AUTO_APPROVE_SCOPE_PROMPT: ${{ inputs.auto_approve_scope_prompt }}
run: |
SCRIPT_PATH="${{ github.action_path }}/scripts/auto-approve-evaluation.js"

if [[ ! -f "$SCRIPT_PATH" ]]; then
echo "::error::Auto-approve evaluation script not found at $SCRIPT_PATH"
exit 1
fi

chmod +x "$SCRIPT_PATH"
RESULT=$(node "$SCRIPT_PATH")

APPROVED=$(echo "$RESULT" | jq -r '.approved')
REASON=$(echo "$RESULT" | jq -r '.reason')

echo "AUTO_APPROVE_DECISION=$APPROVED" >> $GITHUB_ENV
echo "Auto-approve decision: approved=$APPROVED reason=\"$REASON\""

# Store reason for the approval body (multiline-safe)
echo "AUTO_APPROVE_REASON<<EOF" >> $GITHUB_ENV
echo "$REASON" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV

- name: Generate App Token for approval
if: inputs.auto_approve == 'true' && env.AUTO_APPROVE_DECISION == 'true'
id: approve-app-token
uses: actions/create-github-app-token@21cfef757ad23c4e5c14bcfa4b9ca7e524e1d1d3 # v1
with:
app-id: ${{ inputs.auto_approve_app_id }}
private-key: ${{ inputs.auto_approve_private_key }}

- name: Approve PR
if: inputs.auto_approve == 'true' && env.AUTO_APPROVE_DECISION == 'true'
shell: bash
env:
GH_TOKEN: ${{ steps.approve-app-token.outputs.token }}
APPROVE_REASON: ${{ env.AUTO_APPROVE_REASON }}
run: |
PR_NUMBER="${{ github.event.pull_request.number || github.event.issue.number }}"
gh pr review "$PR_NUMBER" --approve --body "$(printf '✅ **Auto-approved by Claude**\n\n%s' "$APPROVE_REASON")"
Loading