-
Notifications
You must be signed in to change notification settings - Fork 0
feat: reusable Claude Code workflow with workflows write permission #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,95 @@ | ||||||||||||||
| # Reusable Claude Code workflow — single source of truth for the org. | ||||||||||||||
| # Repo-level claude.yml files call this to avoid duplicating the prompt and config. | ||||||||||||||
| # Standard: https://github.com/petry-projects/.github/blob/main/standards/ci-standards.md#4-claude-code-claudeyml | ||||||||||||||
| name: Claude Code (Reusable) | ||||||||||||||
|
|
||||||||||||||
| on: | ||||||||||||||
| workflow_call: | ||||||||||||||
| secrets: | ||||||||||||||
| CLAUDE_CODE_OAUTH_TOKEN: | ||||||||||||||
| description: "Claude Code OAuth token for API access" | ||||||||||||||
| required: true | ||||||||||||||
| GH_PAT_WORKFLOWS: | ||||||||||||||
| description: "PAT with workflows scope — lets Claude push .github/workflows/ changes" | ||||||||||||||
| required: false | ||||||||||||||
|
||||||||||||||
| required: false | |
| required: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check how anthropics/claude-code-action handles github_token input
# Look for default value or fallback behavior in action.yml
ast-grep --pattern $'inputs:
$$$
github_token:
$$$
'
# Also search for github_token usage in the action source
rg -n 'github_token' --type yamlRepository: petry-projects/.github
Length of output: 48
🌐 Web query:
anthropics/claude-code-action github_token input documentation
💡 Result:
The github_token input for anthropics/claude-code-action is documented in:
- Repo
action.yml(source of truth for inputs): defines an optionalgithub_tokeninput (“GitHub token with repo and pull request permissions (optional if using GitHub App)”). [1] - Repo docs (
docs/usage.md): describesgithub_tokenas “GitHub token for Claude to operate with” and notes you should only include this if you’re connecting a custom GitHub app of your own. [2] - Anthropic/Claude Code GitHub Actions docs: lists
github_tokenas an optional parameter (“GitHub token for API access”) and shows examples passing a GitHub App token (e.g., fromactions/create-github-app-token) intogithub_token. [3]
Typical usage (custom GitHub App token):
- uses: anthropics/claude-code-action@v1
with:
github_token: ${{ steps.app-token.outputs.token }}[3]
If you don’t set it: the action can use the default workflow GITHUB_TOKEN / installed Claude GitHub App flow instead. [1][3]
Sources: [1] action.yml in anthropics/claude-code-action; [2] docs/usage.md in anthropics/claude-code-action; [3] Claude Code “GitHub Actions” documentation.
🌐 Web query:
GitHub Actions secrets expression syntax fallback || operator
💡 Result:
In GitHub Actions expressions, || is the logical OR operator, and it’s commonly used as a fallback mechanism because falsy values include "" (empty string) and null (among others). GitHub lists || under expression operators, and notes that "" and null are falsy in conditionals/coercion. [1]
For secrets specifically: if a secret is not set, ${{ secrets.NAME }} evaluates to an empty string (""). [2] That makes || work well for fallbacks.
Examples
Fallback to another secret:
env:
TOKEN: ${{ secrets.PRIMARY_TOKEN || secrets.SECONDARY_TOKEN }}Fallback to a literal default:
env:
REGION: ${{ secrets.AWS_REGION || 'us-east-1' }}Chain multiple fallbacks:
env:
KEY: ${{ secrets.KEY_V3 || secrets.KEY_V2 || secrets.KEY_V1 }}Notes:
- This works because an unset secret becomes
""(falsy), so the next operand is chosen. [2] - GitHub docs also note secrets can’t be directly referenced in
if:conditionals (so use the fallback to set an env var, then use that env var inif:if needed). [2]
Sources: GitHub Actions expressions/operators and falsy values [1]; GitHub Actions secrets behavior when unset + if: limitation [2].
[1] (docs.github.com)
[2] (docs.github.com)
Citations:
- 1: https://docs.github.com/en/actions/reference/evaluate-expressions-in-workflows-and-actions
- 2: https://docs.github.com/actions/security-guides/using-secrets-in-github-actions
🏁 Script executed:
# Check if there's any documentation in the current repo about how this action is configured
# or if there are other workflows using this action with github_token
rg -n 'claude-code-action' -A 5 -B 5 --type yamlRepository: petry-projects/.github
Length of output: 3431
🏁 Script executed:
# Check if GH_PAT_WORKFLOWS is required or truly optional in the current workflow file
fd 'claude-code-reusable.yml' -x cat -n {} | head -30
# Also verify the context around line 77 to understand the full scope
fd 'claude-code-reusable.yml' -x cat -n {} | sed -n '70,80p'Repository: petry-projects/.github
Length of output: 48
🏁 Script executed:
# Search for workflow files in the repo
fd -e yml -e yaml | grep -i workflows | head -20
# Also check git status to see what files are in the repo
git ls-files | grep -i workflowRepository: petry-projects/.github
Length of output: 760
🏁 Script executed:
# Read the claude-code-reusable.yml file to see the context around lines 75-77
cat -n .github/workflows/claude-code-reusable.yml | sed -n '1,95p'Repository: petry-projects/.github
Length of output: 5109
Optional secret GH_PAT_WORKFLOWS passed without fallback—should omit or use explicit fallback.
Line 14 declares GH_PAT_WORKFLOWS as optional (required: false), but line 77 passes it directly to github_token. When the secret is not configured:
${{ secrets.GH_PAT_WORKFLOWS }}evaluates to an empty string, which may be treated differently by the action than omitting the input entirely- The standard template (standards/workflows/claude.yml, line 87-92) omits
github_tokenfor the same job, allowing the action to use the defaultGITHUB_TOKEN
Either omit the input (matching the standard) or provide an explicit fallback:
Option 1: Use fallback to github.token (explicit)
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
- github_token: ${{ secrets.GH_PAT_WORKFLOWS }}
+ github_token: ${{ secrets.GH_PAT_WORKFLOWS || github.token }}Option 2: Omit github_token (aligns with standard template)
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
- github_token: ${{ secrets.GH_PAT_WORKFLOWS }}
label_trigger: "claude"📝 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.
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| github_token: ${{ secrets.GH_PAT_WORKFLOWS }} | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| label_trigger: "claude" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/claude-code-reusable.yml around lines 75 - 77, The
workflow currently passes an optional secret directly to the action via the
github_token input using ${ secrets.GH_PAT_WORKFLOWS }, which can evaluate to an
empty string; either remove the github_token input so the action uses the
default GITHUB_TOKEN (align with the standard template) or supply an explicit
fallback expression that uses the PAT when present and falls back to the repo
token (e.g., adjust the github_token input for the job that currently sets
claude_code_oauth_token and github_token to reference GH_PAT_WORKFLOWS with a
fallback to github.token); update the inputs where github_token and
claude_code_oauth_token are set to implement one of these two options.
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,5 @@ | ||||||||||
| # AI-assisted code review via Claude Code Action on PRs. | ||||||||||
| # Issue automation: implement, open PR, self-review, check CI, notify maintainer. | ||||||||||
| # Claude Code — thin caller that delegates to the org-level reusable workflow. | ||||||||||
| # All logic and prompts are maintained centrally in claude-code-reusable.yml. | ||||||||||
| # Standard: https://github.com/petry-projects/.github/blob/main/standards/ci-standards.md#4-claude-code-claudeyml | ||||||||||
| name: Claude Code | ||||||||||
|
|
||||||||||
|
|
@@ -17,81 +17,13 @@ on: | |||||||||
| permissions: {} | ||||||||||
|
|
||||||||||
| jobs: | ||||||||||
| # Interactive mode: PR reviews and @claude mentions | ||||||||||
| claude: | ||||||||||
| if: >- | ||||||||||
| (github.event_name == 'pull_request' && | ||||||||||
| github.event.pull_request.head.repo.full_name == github.repository) || | ||||||||||
| (github.event_name == 'issue_comment' && github.event.issue.pull_request && | ||||||||||
| 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)) | ||||||||||
| runs-on: ubuntu-latest | ||||||||||
| timeout-minutes: 60 | ||||||||||
| claude-code: | ||||||||||
| uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main | ||||||||||
|
||||||||||
| uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main | |
| uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@<40-character-commit-sha> |
Copilot
AI
Apr 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reusable workflow is invoked with secrets: inherit, which passes all repository/org secrets to the called workflow even though only CLAUDE_CODE_OAUTH_TOKEN (+ optionally GH_PAT_WORKFLOWS) are needed. To reduce blast radius if this workflow is modified/compromised, prefer explicitly mapping only the required secrets when calling the reusable workflow.
| secrets: inherit | |
| secrets: | |
| CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| GH_PAT_WORKFLOWS: ${{ secrets.GH_PAT_WORKFLOWS }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reusable workflow defines multiple jobs but does not reset top-level
permissionsto{}. The repo standard (standards/ci-standards.md:451-466) requires multi-job workflows to setpermissions: {}at the workflow root and then scope per-job, to avoid future jobs inheriting default token permissions unexpectedly.