ci: add Claude Code PR review workflow (OAuth auth)#9
Conversation
Runs anthropics/claude-code-action@v1 on non-draft PRs, authenticated with a Claude subscription OAuth token (CLAUDE_CODE_OAUTH_TOKEN) rather than an API key. Review prompt is tailored to CloakPipe: PII leak-safety, cryptographic ledger/verifier integrity, Rust correctness, hot-path performance, and the cloakleak/verifier gates. Uses track_progress for a live checklist, concurrency cancellation to review only the latest push, and least-privilege permissions.
v2 gate results
See PR artifacts for the scoreboards. |
Defines what Important means for CloakPipe (PII leakage, fail-open crypto verification, panics on untrusted input, concurrency hazards), caps nits, skips CI-enforced and intentionally-insecure baseline code, and lists always-check rules for the privacy and verifier invariants.
v2 gate results
See PR artifacts for the scoreboards. |
Avoids the 'Claude Code GitHub App not installed' 401 by passing the Actions token instead of falling back to app-token exchange.
v2 gate results
See PR artifacts for the scoreboards. |
1 similar comment
v2 gate results
See PR artifacts for the scoreboards. |
v2 gate results
See PR artifacts for the scoreboards. |
v2 gate results
See PR artifacts for the scoreboards. |
Responds to @claude mentions on issues and PRs via the same OAuth token. Note: comment-triggered workflows only run from the default branch, so this takes effect once merged to main.
v2 gate results
See PR artifacts for the scoreboards. |
v2 gate results
See PR artifacts for the scoreboards. |
v2 gate results
See PR artifacts for the scoreboards. |
|
Claude finished @rohansx's task in 2m 54s —— View job Claude Code Review1 important, 1 nit.
This PR only adds CI workflow files and a reviewer-instructions doc — no Rust/PII/crypto code is touched, so the review focuses on the workflow security/behavior itself rather than the CloakPipe-specific checklist in 🔴 Important
🟡 Nit
Other observations (no action needed)
|
v2 gate results
See PR artifacts for the scoreboards. |
| if: | | ||
| (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || | ||
| (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || | ||
| (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || | ||
| (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write # allow @claude to apply and push fixes when asked | ||
| pull-requests: write | ||
| issues: write | ||
| id-token: write |
There was a problem hiding this comment.
🔴 Important — anyone can trigger a write-privileged agent by commenting "@claude"
The job's if: only checks that the comment/issue/review body contains the string @claude (lines 25-28). It never checks github.event.comment.author_association (or the issue/review equivalents), and the job runs with contents: write, pull-requests: write, and issues: write (lines 31-34).
On a public repo this means any GitHub account — not just maintainers or collaborators — can open an issue or comment on any PR (including one they opened from a fork) with @claude <arbitrary instructions> and get an agent to run with push access to the repo and issue/PR write access. Since claude.yml doesn't set claude_args/--allowedTools at all, the action's default (fairly broad) tool access applies, so the blast radius of an untrusted instruction here is large — pushing unreviewed commits, editing issues/PRs, etc.
Suggest gating the condition on author association, e.g.:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') &&
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
...and the same for the pull_request_review_comment, pull_request_review, and issues branches.
|
|
||
| # Read-only repo access plus the ability to post review comments. | ||
| claude_args: | | ||
| --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)" |
There was a problem hiding this comment.
🟡 Nit: --allowedTools includes Bash(gh pr comment:*) alongside mcp__github_inline_comment__create_inline_comment and track_progress: true. This lets Claude post extra freeform top-level PR comments outside the single tracked/managed comment the rest of this setup relies on, which can lead to duplicate/orphaned comments on re-runs instead of one comment being updated. Consider dropping gh pr comment from the allowlist so all output goes through track_progress + inline comments.
…tools - claude.yml: require OWNER/MEMBER/COLLABORATOR to trigger the write-privileged @claude agent (was: anyone could trigger it). - claude-code-review.yml: drop Bash(gh pr comment:*) so track_progress keeps a single tracked comment instead of duplicate freeform ones.
|
Claude finished @rohansx's task in 48s —— View job Claude Code ReviewNo blocking issues.
This push (
No new issues found in this diff (only these two workflow files and |
v2 gate results
See PR artifacts for the scoreboards. |
|
Superseded by #10 (clean, squashed version, merged to main). Closing. |
Summary
Adds
.github/workflows/claude-code-review.yml— automated PR review viaanthropics/claude-code-action@v1, authenticated with a Claude subscription OAuth token (CLAUDE_CODE_OAUTH_TOKEN) instead of an API key.Behavior
pull_request:opened,synchronize,ready_for_review,reopened. Draft PRs are skipped.concurrency+cancel-in-progress: a new push cancels the in-flight review, so only the latest commit is reviewed.track_progress: true: posts a live checklist comment and inline line comments.contents: read,pull-requests: write,id-token: write.Required before it runs
Repo secret
CLAUDE_CODE_OAUTH_TOKENmust be set (claude setup-token, thengh secret set CLAUDE_CODE_OAUTH_TOKEN).Test plan
CLAUDE_CODE_OAUTH_TOKENsecret🤖 Generated with Claude Code