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
Comment on lines +23 to +25
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Allow review workflow token to write PR feedback

The automated review workflow also pins contents, pull-requests, and issues to read-only, which prevents the action from publishing review comments/results to the PR. Because this workflow’s purpose is to run Claude code review against pull requests, lacking write scopes breaks the core outcome (posting feedback), and the action’s own setup/examples require read/write access for these permissions.

Useful? React with 👍 / 👎.

id-token: write
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Insufficient write permissions prevent posting review comments

High Severity

The pull-requests permission is set to read, but the Claude Code Review action needs pull-requests: write to post review comments on pull requests. According to the official anthropics/claude-code-action documentation, the PR review workflow requires write access. This will cause the workflow to silently fail or error when attempting to submit its review.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8edf0ca. Configure here.


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'
Comment on lines +21 to +39
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/claude-code-review.yml

Repository: shakacode/react-on-django

Length of output: 1809


Add fork guard to prevent failed runs from external contributions.

This job uses secrets.CLAUDE_CODE_OAUTH_TOKEN (line 38) but runs on all pull_request events. Forked PRs cannot access repository secrets in GitHub Actions, causing the action to fail when called from external forks. Add a guard to skip the job for forked PRs.

🛠️ Proposed fix
 jobs:
   claude-review:
+    if: ${{ !github.event.pull_request.head.repo.fork }}
     runs-on: ubuntu-latest
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
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'
if: ${{ !github.event.pull_request.head.repo.fork }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
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'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/claude-code-review.yml around lines 21 - 39, The workflow
uses secrets.CLAUDE_CODE_OAUTH_TOKEN in the Run Claude Code Review job and
currently runs on pull_request events; add a fork-guard by adding an if
conditional to the job that ensures the job only runs for non-fork PRs (or
non-pull_request events). For example, add an if at the job level such as if:
github.event_name != 'pull_request' ||
github.event.pull_request.head.repo.full_name == github.repository (or compare
github.event.pull_request.head.repo.owner.login == github.repository_owner) so
the job (and the step using claude_code_oauth_token) is skipped for external
forked PRs.

plugins: 'code-review@claude-code-plugins'
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]
pull_request_review:
types: [submitted]

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
Comment on lines +15 to +20
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/claude.yml

Repository: shakacode/react-on-django

Length of output: 2304


🌐 Web query:

GitHub Actions author_association event context pull_request_review issue_comment

💡 Result:

In GitHub Actions, the github.event context provides access to the webhook payload for events like pull_request_review and issue_comment. The author_association field indicates the comment author's relationship to the repository (e.g., OWNER, MEMBER, COLLABORATOR, CONTRIBUTOR, FIRST_TIME_CONTRIBUTOR, FIRST_TIMER, NONE, MANNEQUIN). For issue_comment events (comments on issues or PRs): - Access via ${{ github.event.comment.author_association }} - Example from real workflow log: "author_association": "OWNER" For pull_request_review events: - Access via ${{ github.event.review.author_association }} - The review object matches the PullRequestReview REST API schema, which includes author_association. Use in workflows: on: issue_comment: types: [created] jobs: example: if: github.event.comment.author_association == 'OWNER' runs-on: ubuntu-latest steps: - run: echo "Owner commented" on: pull_request_review: types: [submitted] jobs: example: if: github.event.review.author_association == 'MEMBER' runs-on: ubuntu-latest steps: - run: echo "Member reviewed" The full github.event is available for debugging: run: echo '${{ toJSON(github.event) }}'. Primary source: GitHub Docs on contexts [1,6] and webhook payloads [12,16]; confirmed in examples [29].

Citations:


🌐 Web query:

GitHub Actions github.event.issue.author_association issues event context

💡 Result:

In GitHub Actions, github.event is the full webhook payload for the triggering event. For workflows triggered by the issues event (e.g., on: issues: types: [opened]), github.event.issue is the issue object from the webhook payload, which includes the author_association field. author_association indicates the level of association the issue's author (user) has with the repository. Possible values are: - NONE: No association. - FIRST_TIMER: Author has not previously committed to GitHub. - FIRST_TIME_CONTRIBUTOR: Author has not previously committed to this repository. - CONTRIBUTOR: Author has previously committed to this repository. - MANNEQUIN: Author is a placeholder for an unclaimed user. - MEMBER: Author is a member of the organization that owns the repository. - COLLABORATOR: Author has been invited to collaborate on the repository. - OWNER: Author is the owner of the repository. Example usage in a workflow: if: github.event.issue.author_association == 'OWNER' || github.event.issue.author_association == 'MEMBER' Note: There may be nuances in org repos where visibility settings affect the value (e.g., CONTRIBUTOR instead of MEMBER if private). As of 2026, author_association remains available in GitHub Actions webhook payloads, though recent changes removed it from some Events API payloads (not affecting Actions). Access via expression: ${{ github.event.issue.author_association }}

Citations:


🌐 Web query:

GitHub Actions workflow conditions contains fromJSON function syntax

💡 Result:

The fromJSON function in GitHub Actions expressions has the syntax fromJSON(value), where value is a JSON-formatted string. It returns a JSON object or data type (such as boolean, integer, array, or object) parsed from the input string. It is commonly used in workflow conditions (if), step attributes like continue-on-error or timeout-minutes, matrix strategies, and outputs. Examples from official documentation: 1. Converting string env vars to typed values in step conditions: env: continue: true time: 3 steps: - continue-on-error: ${{ fromJSON(env.continue) }} timeout-minutes: ${{ fromJSON(env.time) }} Here, env.continue ("true") becomes boolean true, and env.time ("3") becomes integer 3. 2. Parsing JSON output for matrix in job strategy: jobs: job1: outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - id: set-matrix run: echo 'matrix={"include":[{"project":"foo","config":"Debug"},{"project":"bar","config":"Release"}]}' >> $GITHUB_OUTPUT job2: needs: job1 strategy: matrix: ${{ fromJSON(needs.job1.outputs.matrix) }} Access properties with dot notation: ${{ fromJSON(needs.step1.outputs.matrix)[0].project }} or index: ${{ fromJSON(env.myjson)['foo2'] }}. For conditions, combine with operators: if: ${{ fromJSON(env.myvar) == true }} or numerical: if: ${{ fromJSON(needs.job.outputs.length) < fromJSON(env.MAX) }}. Note: Inputs to fromJSON must be valid JSON strings; invalid input may cause evaluation errors. Env vars and outputs are strings, so fromJSON converts them to native types for proper comparisons (e.g., numerical or boolean). Official source: GitHub Docs on expressions (updated as of 2024+), covering usage in if conditionals, strategies, and attributes.

Citations:


Add an actor trust gate before honoring @claude mentions.

Lines 15-19 currently allow any user who can comment to trigger the job. Add an author_association check (e.g., OWNER/MEMBER/COLLABORATOR) per event to prevent untrusted-trigger abuse of the CLAUDE_CODE_OAUTH_TOKEN secret on line 37.

🔐 Proposed condition hardening
 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')))
+      (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))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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
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
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/claude.yml around lines 15 - 20, The trigger condition
currently honors any '@claude' mention; restrict it by adding author_association
checks so only trusted actors (OWNER, MEMBER, COLLABORATOR) can trigger the job:
for github.event_name == 'issue_comment' and 'pull_request_review_comment' check
github.event.comment.author_association, for 'pull_request_review' check
github.event.review.author_association, and for 'issues' check
github.event.issue.author_association; combine each association check with the
existing contains(..., '@claude') predicates so the job will only run when both
the mention and a trusted author_association are present (this prevents
untrusted users from abusing the CLAUDE_CODE_OAUTH_TOKEN secret).

permissions:
contents: read
pull-requests: read
issues: read
Comment on lines +22 to +24
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Grant write scopes for interactive Claude job

This job is meant to respond to @claude mentions, but the workflow token is restricted to read-only repository, PR, and issue scopes, so Claude cannot post replies/reviews or apply changes back to GitHub. The upstream setup guidance for anthropics/claude-code-action lists Contents/Issues/Pull Requests as minimum Read & Write permissions, so this configuration will cause 403 write failures in normal mention-driven runs.

Useful? React with 👍 / 👎.

id-token: write
actions: read # Required for Claude to read CI results on PRs
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Read-only permissions prevent Claude from creating comments and commits

High Severity

The contents, pull-requests, and issues permissions are all set to read, but the interactive Claude workflow needs write access for these. The PR description states Claude's tools include "creating comments, branches, and commits," all of which require write permissions. The official example workflow uses contents: write, pull-requests: write, and issues: write.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8edf0ca. Configure here.

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