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
95 changes: 95 additions & 0 deletions .github/workflows/claude-code-reusable.yml
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:
Comment on lines +6 to +8
Copy link

Copilot AI Apr 6, 2026

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 permissions to {}. The repo standard (standards/ci-standards.md:451-466) requires multi-job workflows to set permissions: {} at the workflow root and then scope per-job, to avoid future jobs inheriting default token permissions unexpectedly.

Copilot uses AI. Check for mistakes.
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
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

GH_PAT_WORKFLOWS is declared as an optional secret (required: false), but the workflow always passes it to anthropics/claude-code-action as github_token. If the secret isn’t set in a given repo/org, this will likely resolve to an empty value and can break the claude-issue job. Either make the secret required, or default github_token to github.token when GH_PAT_WORKFLOWS is not provided.

Suggested change
required: false
required: true

Copilot uses AI. Check for mistakes.

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
permissions:
contents: write
id-token: write
pull-requests: write
issues: write
actions: read
checks: read
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
- name: Run Claude Code
if: github.event_name != 'pull_request' || github.event.pull_request.user.login != 'dependabot[bot]'
uses: anthropics/claude-code-action@6e2bd52842c65e914eba5c8badd17560bd26b5de # v1.0.89
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
additional_permissions: |
actions: read
checks: read

# Automation mode: issue-triggered work — implement, open PR, review, and notify
claude-issue:
if: >-
github.event_name == 'issues' && github.event.action == 'labeled' &&
github.event.label.name == 'claude'
concurrency:
group: claude-issue-${{ github.event.issue.number || github.run_id }}
cancel-in-progress: true
runs-on: ubuntu-latest
timeout-minutes: 60
permissions:
contents: write
id-token: write
pull-requests: write
issues: write
actions: read
checks: read
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
- name: Run Claude Code
uses: anthropics/claude-code-action@6e2bd52842c65e914eba5c8badd17560bd26b5de # v1.0.89
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.GH_PAT_WORKFLOWS }}
Comment on lines +75 to +77
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 | 🟡 Minor

🧩 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 yaml

Repository: 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 optional github_token input (“GitHub token with repo and pull request permissions (optional if using GitHub App)”). [1]
  • Repo docs (docs/usage.md): describes github_token as “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_token as an optional parameter (“GitHub token for API access”) and shows examples passing a GitHub App token (e.g., from actions/create-github-app-token) into github_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 in if: 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:


🏁 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 yaml

Repository: 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 workflow

Repository: 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_token for the same job, allowing the action to use the default GITHUB_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.

Suggested change
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.

label_trigger: "claude"
track_progress: "true"
additional_permissions: |
actions: read
checks: read
claude_args: |
--allowedTools "Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr comment:*),Bash(gh issue comment:*),Bash(gh run view:*),Bash(gh run watch:*),Edit,Write"
prompt: |
Implement a fix for issue #${{ github.event.issue.number }}.

After implementing:
1. Create a pull request with a clear title and description. Include "Closes #${{ github.event.issue.number }}" in the PR body.
2. Self-review your own PR — look for bugs, style issues, missed edge cases, and test gaps. If you find problems, push fixes.
3. Review all comments and review threads on the PR. For each one:
- If you can address the feedback, make the fix, push, and mark the conversation as resolved.
- If the comment requires human judgment, leave a reply explaining what you need.
4. Check CI status. If CI fails, read the logs, fix the issues, and push again. Repeat until CI passes.
5. When CI is green, all actionable review comments are resolved, and the PR is ready, read the CODEOWNERS file and leave a comment tagging the relevant code owners to review and merge.
78 changes: 5 additions & 73 deletions .github/workflows/claude.yml
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

Expand All @@ -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
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

jobs.<job>.uses points at .../claude-code-reusable.yml@main, which is a mutable branch ref. This conflicts with the repo’s action pinning policy (standards/ci-standards.md:425-447) and creates supply-chain / reproducibility risk if main changes unexpectedly. Pin the reusable workflow to a commit SHA (or a version tag that is itself immutably managed) and update via Dependabot or a controlled bump process.

Suggested change
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 uses AI. Check for mistakes.
secrets: inherit
Copy link

Copilot AI Apr 6, 2026

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.

Suggested change
secrets: inherit
secrets:
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
GH_PAT_WORKFLOWS: ${{ secrets.GH_PAT_WORKFLOWS }}

Copilot uses AI. Check for mistakes.
permissions:
contents: write
id-token: write
pull-requests: write
issues: write
actions: read
checks: read
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
- name: Run Claude Code
if: github.event_name != 'pull_request' || github.event.pull_request.user.login != 'dependabot[bot]'
uses: anthropics/claude-code-action@6e2bd52842c65e914eba5c8badd17560bd26b5de # v1.0.89
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
additional_permissions: |
actions: read
checks: read

# Automation mode: issue-triggered work — implement, open PR, review, and notify
claude-issue:
if: >-
github.event_name == 'issues' && github.event.action == 'labeled' &&
github.event.label.name == 'claude'
concurrency:
group: claude-issue-${{ github.event.issue.number }}
cancel-in-progress: true
runs-on: ubuntu-latest
timeout-minutes: 60
permissions:
contents: write
id-token: write
pull-requests: write
issues: write
actions: read
checks: read
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
- name: Run Claude Code
uses: anthropics/claude-code-action@6e2bd52842c65e914eba5c8badd17560bd26b5de # v1.0.89
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
label_trigger: "claude"
track_progress: "true"
additional_permissions: |
actions: read
checks: read
claude_args: |
--allowedTools "Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr comment:*),Bash(gh issue comment:*),Bash(gh run view:*),Bash(gh run watch:*),Edit,Write"
prompt: |
Implement a fix for issue #${{ github.event.issue.number }}.

After implementing:
1. Create a pull request with a clear title and description. Include "Closes #${{ github.event.issue.number }}" in the PR body.
2. Self-review your own PR — look for bugs, style issues, missed edge cases, and test gaps. If you find problems, push fixes.
3. Review all comments and review threads on the PR. For each one:
- If you can address the feedback, make the fix, push, and mark the conversation as resolved.
- If the comment requires human judgment, leave a reply explaining what you need.
4. Check CI status. If CI fails, read the logs, fix the issues, and push again. Repeat until CI passes.
5. When CI is green, all actionable review comments are resolved, and the PR is ready, read the CODEOWNERS file and leave a comment tagging the relevant code owners to review and merge.
Loading