Add Claude Code GitHub Workflow#1
Conversation
📝 WalkthroughWalkthroughTwo GitHub Actions workflows are added to integrate Claude AI for code review. The first automatically reviews pull requests on creation or update, while the second provides interactive code review triggered by Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
.github/workflows/claude.yml (1)
18-20: Harden expression fields that can be null.Line 18 and Line 20 read body/title fields directly. Use
|| ''guards consistently to avoid event-shape edge failures.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/claude.yml around lines 18 - 20, The conditional expressions in the workflow use nullable fields directly (github.event.review.body, github.event.issue.body, github.event.issue.title) which can cause failures; update the two expressions that check for '@claude' to guard those fields with a fallback (e.g., `|| ''`) so they read the body/title safely, i.e., replace direct uses of github.event.review.body, github.event.issue.body, and github.event.issue.title with expressions that default to an empty string before calling contains..github/workflows/claude-code-review.yml (1)
30-30: Pin third-party actions to commit SHAs for supply-chain safety.Line 30 and Line 36 use mutable tags. Prefer immutable commit SHA pins.
Suggested pattern
- uses: actions/checkout@v4 + uses: actions/checkout@<full-length-commit-sha> - uses: anthropics/claude-code-action@v1 + uses: anthropics/claude-code-action@<full-length-commit-sha>Also applies to: 36-36
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/claude-code-review.yml at line 30, The workflow currently pins third-party GitHub Actions with mutable tags (e.g., uses: actions/checkout@v4 and the other uses entry at line 36); replace those tag pins with the corresponding immutable commit SHAs by editing the uses lines to reference the exact commit SHA (e.g., uses: actions/checkout@<commit-sha>) fetched from the action repo’s commits page or the action’s GitHub release, and update both occurrences so the workflow uses fixed SHAs instead of version tags.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/claude-code-review.yml:
- Around line 4-5: The workflow triggers on pull_request but uses
secrets.CLAUDE_CODE_OAUTH_TOKEN without guarding fork PRs; add a job-level
conditional to skip jobs that rely on repository secrets when the PR comes from
a fork — e.g., on the job that uses secrets.CLAUDE_CODE_OAUTH_TOKEN (the job
that executes the OAuth token usage), add an if condition checking the PR repo
matches the base repo (for example compare
github.event.pull_request.head.repo.full_name == github.repository or
github.event.pull_request.head.repo.owner.login == github.repository_owner) so
the job only runs for in-repo PRs and not for forked PRs.
In @.github/workflows/claude.yml:
- Around line 21-25: Update the GitHub Actions permissions to allow Claude to
perform code actions by changing the permission values from read to write: set
contents: write, pull-requests: write, and issues: write (leave id-token: write
as-is); apply these changes to both permissions blocks shown (the block
containing contents/pull-requests/issues/id-token and the second identical
block).
- Around line 15-20: The workflow condition allows any GitHub user to trigger
the run by mentioning `@claude`; restrict it by adding author_association checks
so only trusted associations can trigger it. Update each OR clause that inspects
github.event.comment, github.event.review, and github.event.issue to also
require the corresponding author_association be one of trusted values (e.g.,
OWNER, MEMBER, COLLABORATOR) — for example add checks like (contains(...,
'@claude') && (github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')) and analogous checks
using github.event.review.author_association and
github.event.issue.author_association so the CLAUDE_CODE_OAUTH_TOKEN can only be
used by repo owners/members/collaborators.
---
Nitpick comments:
In @.github/workflows/claude-code-review.yml:
- Line 30: The workflow currently pins third-party GitHub Actions with mutable
tags (e.g., uses: actions/checkout@v4 and the other uses entry at line 36);
replace those tag pins with the corresponding immutable commit SHAs by editing
the uses lines to reference the exact commit SHA (e.g., uses:
actions/checkout@<commit-sha>) fetched from the action repo’s commits page or
the action’s GitHub release, and update both occurrences so the workflow uses
fixed SHAs instead of version tags.
In @.github/workflows/claude.yml:
- Around line 18-20: The conditional expressions in the workflow use nullable
fields directly (github.event.review.body, github.event.issue.body,
github.event.issue.title) which can cause failures; update the two expressions
that check for '@claude' to guard those fields with a fallback (e.g., `|| ''`)
so they read the body/title safely, i.e., replace direct uses of
github.event.review.body, github.event.issue.body, and github.event.issue.title
with expressions that default to an empty string before calling contains.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0cbd1b16-4558-4893-a695-9b97222a2a5d
📒 Files selected for processing (2)
.github/workflows/claude-code-review.yml.github/workflows/claude.yml
| pull_request: | ||
| types: [opened, synchronize, ready_for_review, reopened] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm this workflow uses a secret without a fork/secret guard
rg -n "pull_request:|claude_code_oauth_token|head\\.repo\\.fork|secrets\\.CLAUDE_CODE_OAUTH_TOKEN|^\\s*if:" .github/workflows/claude-code-review.ymlRepository: Ageree/sthrip
Length of output: 151
🏁 Script executed:
cat -n .github/workflows/claude-code-review.ymlRepository: Ageree/sthrip
Length of output: 1797
Guard this workflow to prevent execution on fork PRs when using repository secrets.
The job uses secrets.CLAUDE_CODE_OAUTH_TOKEN (line 38) but has no guard preventing execution on fork-based PRs (lines 4–5). On public repos, fork PRs cannot access repository secrets by default in GitHub Actions, causing the workflow to fail silently or error out.
Add a conditional at the job level:
Suggested guard
jobs:
claude-review:
+ if: ${{ !github.event.pull_request.head.repo.fork && secrets.CLAUDE_CODE_OAUTH_TOKEN != '' }}🤖 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 4 - 5, The workflow
triggers on pull_request but uses secrets.CLAUDE_CODE_OAUTH_TOKEN without
guarding fork PRs; add a job-level conditional to skip jobs that rely on
repository secrets when the PR comes from a fork — e.g., on the job that uses
secrets.CLAUDE_CODE_OAUTH_TOKEN (the job that executes the OAuth token usage),
add an if condition checking the PR repo matches the base repo (for example
compare github.event.pull_request.head.repo.full_name == github.repository or
github.event.pull_request.head.repo.owner.login == github.repository_owner) so
the job only runs for in-repo PRs and not for forked PRs.
| 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 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether trusted-author gating is currently present
rg -n "author_association|contains\\(github\\.event\\..*@claude|fromJSON\\(" .github/workflows/claude.ymlRepository: Ageree/sthrip
Length of output: 518
🏁 Script executed:
cat -n .github/workflows/claude.ymlRepository: Ageree/sthrip
Length of output: 2292
Add author-association gating to prevent unauthorized workflow triggers.
Any GitHub user can trigger this workflow by mentioning @claude in comments, reviews, or issues—even without repository access. This allows unauthorized invocation of the Claude Code action and consumption of the CLAUDE_CODE_OAUTH_TOKEN secret. Gate the trigger condition on author_association to restrict execution to repository owners, members, or collaborators.
Lines 16–19 should include checks for trusted author_association values. Apply the suggested hardening to all four event types:
Suggested fix
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.
| 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 workflow condition
allows any GitHub user to trigger the run by mentioning `@claude`; restrict it by
adding author_association checks so only trusted associations can trigger it.
Update each OR clause that inspects github.event.comment, github.event.review,
and github.event.issue to also require the corresponding author_association be
one of trusted values (e.g., OWNER, MEMBER, COLLABORATOR) — for example add
checks like (contains(..., '@claude') &&
(github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')) and analogous checks
using github.event.review.author_association and
github.event.issue.author_association so the CLAUDE_CODE_OAUTH_TOKEN can only be
used by repo owners/members/collaborators.
| permissions: | ||
| contents: read | ||
| pull-requests: read | ||
| issues: read | ||
| id-token: write |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For anthropics/claude-code-action@v1, what GitHub Actions permissions are required to (1) comment on PRs/issues, (2) push commits/branches, and (3) open/update pull requests?
💡 Result:
For anthropics/claude-code-action@v1, the GitHub Actions workflow requires the following permissions at the job level to enable the specified operations. These are consistently shown in official documentation, examples, and GitHub issues. (1) Comment on PRs/issues: issues: write (also requires pull-requests: write for PR comments, as PR comments use the pull-requests scope). (2) Push commits/branches: contents: write. (3) Open/update pull requests: pull-requests: write. Full minimal set for all operations: permissions: contents: write issues: write pull-requests: write Additional notes: - id-token: write may be needed for OIDC authentication with cloud providers like Bedrock/Vertex. - contents: read is sufficient for read-only operations like reviews. - The official Claude GitHub App also requests read & write on Contents, Issues, Pull requests. - The action itself does not declare permissions in action.yml (it's a composite action), so workflow-level permissions are required.
Citations:
- 1: https://docs.anthropic.com/en/docs/claude-code/github-actions
- 2: https://github.com/anthropics/claude-code-action
- 3: Claude Code will read arbitrary files from the checked-out repository and post their full contents as PR comments anthropics/claude-code-action#957
- 4: https://github.com/anthropics/claude-code-action/blob/main/docs/faq.md
- 5: https://code.claude.com/docs/en/github-actions
- 6: v1.0.5 runs but can't pick up the PR context nor post the output as a comment on the PR itself. anthropics/claude-code-action#557
- 7: https://github.com/anthropics/claude-code-action/blob/main/action.yml
- 8: https://github.com/anthropics/claude-code-action/blob/eb99fb38/action.yml
- 9: https://cc.bruniaux.com/guide/workflows/github-actions/
Add missing write permissions for Claude code actions.
The current read-only permissions (contents: read, pull-requests: read, issues: read) are insufficient for Claude to create comments, push commits, and open PRs. Update to:
contents: write(for commits/branches)pull-requests: write(for PR comments and operations)issues: write(for issue comments)id-token: write(already correct for OIDC)
This applies to both permission blocks (lines 21–25 and 33–41).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/claude.yml around lines 21 - 25, Update the GitHub Actions
permissions to allow Claude to perform code actions by changing the permission
values from read to write: set contents: write, pull-requests: write, and
issues: write (leave id-token: write as-is); apply these changes to both
permissions blocks shown (the block containing
contents/pull-requests/issues/id-token and the second identical block).
Follow-up to fd6382b addressing 5-agent review of the PR1 commit. Real bugs introduced by PR1, now fixed: - F-5b — channel_signing.verify_channel_state regression (Agent#3 finding): PyNaCl's CryptoError is the parent of BadSignatureError, not the other way around. The narrowed `except BadSignatureError` left raw CryptoError uncaught, so a corrupt key would propagate as an unhandled 500 instead of cleanly rejecting the channel state. Add explicit `except CryptoError` and drop the redundant `binascii.Error` (it's a ValueError subclass in Python 3). Demote the BadSignatureError branch to DEBUG since it's the expected reject path. - F-9c — validate_session AttributeError on non-dict JSON (Agent#2 #1): json.loads accepts any valid JSON, not just objects. A stray "42" or "[1,2]" in the session payload would let the parse succeed but then `payload.get(...)` would AttributeError → 500. Guard with `isinstance(payload, dict)`. - F-9d — short-circuit before compare_digest (Agent#2 #2): `if not client_ip or not hmac.compare_digest(...)` returns faster on a missing IP than on a wrong IP, leaking presence of binding via timing. Always pass strings (`client_ip or ""`) so compare_digest runs in every branch. - F-9e — bound IP leaked in log (Agent#5 #1): The mismatch warning logged the bound IP in plaintext. Anyone with read access to Railway/Logtail logs would learn where each admin token was issued. Drop the IP from the log message. - F-13b — _secure_shuffle in-place mutation (Agents #1, #5): Violated the project-wide "ALWAYS create new objects, NEVER mutate" rule from ~/.claude/rules/common/coding-style.md. Now returns a fresh list; call site simplified. Documentation / config: - F-9b — trusted_proxy_hosts: documented Railway requirement in sthrip/config.py and .env.railway.example. Without ``TRUSTED_PROXY_HOSTS=*`` on Railway, request.client.host is the Railway edge IP, collapsing every admin session and rate-limit key to a single IP and bypassing F-9 binding. (Agent#3 finding.) - F-15b — CORS_DEV_AUTOEXTEND documented in .env.railway.example. - F-16 — _fix_pg_enums comment clarified: code "log+skips" unsafe entries, it does not raise.
🤖 Installing Claude Code GitHub App
This PR adds a GitHub Actions workflow that enables Claude Code integration in our repository.
What is Claude Code?
Claude Code is an AI coding agent that can help with:
How it works
Once this PR is merged, we'll be able to interact with Claude by mentioning @claude in a pull request or issue comment.
Once the workflow is triggered, Claude will analyze the comment and surrounding context, and execute on the request in a GitHub action.
Important Notes
Security
There's more information in the Claude Code action repo.
After merging this PR, let's try mentioning @claude in a comment on any PR to get started!
Summary by CodeRabbit