| name: Claude Code |
| |
| on: |
| issue_comment: |
| types: [created] |
| pull_request_review_comment: |
| types: [created] |
| issues: |
| # only "opened" — an issue's author_association gates the summon below; |
| # "assigned" would gate on the issue author, not the assigner, so a |
| # maintainer assigning an outsider's issue would be wrongly skipped. |
| types: [opened] |
| pull_request_review: |
| types: [submitted] |
| |
| jobs: |
| claude: |
| # Only trusted actors (repo owner/member/collaborator) may summon @claude, so the |
| # write-scoped token and OAuth secret are never issued for an outside contributor's |
| # comment on this public repo. Defense-in-depth on top of the action's own check. |
| if: | |
| (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') && |
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) || |
| (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && |
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) || |
| (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && |
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)) || |
| (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) && |
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.issue.author_association)) |
| runs-on: ubuntu-latest |
| permissions: |
| contents: write # allow Claude to push commits/branches when asked |
| pull-requests: write # allow Claude to comment on / update PRs |
| issues: write # allow Claude to comment on / update issues |
| id-token: write |
| actions: read # Required for Claude to read CI results on PRs |
| steps: |
| - name: Checkout repository |
| uses: actions/checkout@v6 |
| with: |
| fetch-depth: 1 |
| |
| - name: Run Claude Code |
| id: claude |
| uses: anthropics/claude-code-action@v1 |
| with: |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} |
| |
| # This is an optional setting that allows Claude to read CI results on PRs |
| additional_permissions: | |
| actions: read |
| |
| # Sign the bot's commits so they show as "Verified". The action commits |
| # automatically — on a PR comment it pushes to that PR's branch; on an |
| # issue comment it opens a new claude/* branch + PR with the fix. |
| use_commit_signing: true |
| |
| # No custom prompt: Claude performs the instructions in the @claude comment. |
| |
| # Deliberately NO Bash in the tool allowlist. @claude can be summoned on a |
| # fork PR (claude-code-review.yml even directs fork PRs here), and this job |
| # holds the OAuth secret + a write token. Any build/interpreter command |
| # (python -c, cmake/make custom targets, etc.) run against attacker- |
| # controlled PR content is arbitrary code + network execution, so no |
| # command allowlist can safely contain it. Claude still edits files and |
| # the action commits/opens the PR; the resulting commit is verified by the |
| # repo's CircleCI matrix. --max-turns gives room to investigate + fix. |
| claude_args: '--max-turns 30' |