Skip to content
Merged
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
44 changes: 44 additions & 0 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Claude Code Review

on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]
# Optional: Only run on specific file changes
# paths:
# - "src/**/*.ts"
# - "src/**/*.tsx"
# - "src/**/*.js"
# - "src/**/*.jsx"

jobs:
claude-review:
# Optional: Filter by PR author
# if: |
# github.event.pull_request.user.login == 'external-contributor' ||
# github.event.pull_request.user.login == 'new-developer' ||
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'

runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write

Comment on lines +21 to +27
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The permissions in this workflow are read-only (pull-requests: read, contents: read, issues: read). With these scopes, the action cannot create PR comments/reviews or push branches/commits, which conflicts with the PR description’s claim that Claude can “create comments, branches, and commits.” Either adjust the permissions (and document the security implications) or update the PR description/expectations to reflect read-only behavior.

Copilot uses AI. Check for mistakes.
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
plugins: 'code-review@claude-code-plugins'
Comment on lines +3 to +40
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pull_request workflows do not receive repository secrets for PRs coming from forks, so secrets.CLAUDE_CODE_OAUTH_TOKEN will be empty and this job will fail on fork-based contributions. If you want to support external PRs, add a fork guard (e.g., only run when github.event.pull_request.head.repo.full_name == github.repository) or switch to a safer pull_request_target pattern with additional hardening.

Copilot uses AI. Check for mistakes.
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options

50 changes: 50 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Claude Code

on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including issues: types: [opened, assigned] means that if an issue title/body contains @claude, the workflow will re-run every time the issue is assigned (even when no new mention was made). If the desired trigger is “only when someone asks Claude,” consider removing assigned (and/or using issue_comment only), or add additional checks so only newly-created comments/mentions trigger a run.

Suggested change
types: [opened, assigned]
types: [opened]

Copilot uses AI. Check for mistakes.
pull_request_review:
types: [submitted]

Comment on lines +3 to +12
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow is configured to trigger on issues opened/assigned and pull_request_review submitted events (and it scans issue titles/bodies and review bodies), but the PR description says the integration is invoked by mentioning @claude in an issue/PR comment. Either narrow the triggers to match the documented behavior (comments only), or update the PR description to reflect that opening/assigning issues and submitting PR reviews can also trigger runs.

Copilot uses AI. Check for mistakes.
jobs:
claude:
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: read
pull-requests: read
issues: read
id-token: write
Comment on lines +14 to +25
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow can be triggered by anyone who can create an issue/PR comment containing @claude, but there is no guard to restrict execution to users with write/maintain/admin permissions (or at least repo collaborators). This is a security/cost risk because the job runs with repository read access and id-token: write. Add an explicit permission check (e.g., via github.event.sender + repos.getCollaboratorPermissionLevel in a preliminary step, and gate the job) and consider removing id-token: write unless the action strictly requires OIDC.

Suggested change
claude:
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: read
pull-requests: read
issues: read
id-token: write
permission-check:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
has_permission: ${{ steps.check-permission.outputs.has_permission }}
steps:
- name: Check if sender has sufficient permissions
id: check-permission
uses: actions/github-script@v7
with:
github-token: ${{ github.token }}
script: |
const sender = context.payload.sender && context.payload.sender.login;
if (!sender) {
core.setOutput('has_permission', 'false');
return;
}
try {
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: sender,
});
const level = data.permission;
const allowedLevels = ['admin', 'maintain', 'write'];
const hasPermission = allowedLevels.includes(level);
core.setOutput('has_permission', hasPermission ? 'true' : 'false');
} catch (error) {
// If the user is not a collaborator or an error occurs, deny by default
core.info(`Permission check failed or user is not a collaborator: ${error.message}`);
core.setOutput('has_permission', 'false');
}
claude:
needs: permission-check
if: |
needs.permission-check.outputs.has_permission == 'true' &&
(
(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: read
pull-requests: read
issues: read

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +25
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The job permissions here are read-only (pull-requests: read, issues: read, contents: read). If the intent is for Claude to post replies back to the PR/issue thread (as described in the PR), this workflow won’t be able to do so using GITHUB_TOKEN. Either grant the minimum required write permissions (e.g., issues: write / pull-requests: write) or update the PR description to reflect that Claude will only run without posting back to GitHub.

Copilot uses AI. Check for mistakes.
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v4
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

# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
# prompt: 'Update the pull request description to include a summary of changes.'

# Optional: Add claude_args to customize behavior and configuration
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options
# claude_args: '--allowed-tools Bash(gh pr:*)'

Loading