Skip to content

feat: reusable Claude Code workflow with workflows write permission#77

Merged
don-petry merged 1 commit intomainfrom
feat/reusable-claude-workflow
Apr 6, 2026
Merged

feat: reusable Claude Code workflow with workflows write permission#77
don-petry merged 1 commit intomainfrom
feat/reusable-claude-workflow

Conversation

@don-petry
Copy link
Copy Markdown
Contributor

@don-petry don-petry commented Apr 6, 2026

Summary

  • Extracts the full Claude Code config (interactive + issue automation) into claude-code-reusable.yml — single source of truth for the org
  • Slims claude.yml to a thin caller that delegates via uses: + secrets: inherit
  • Adds github_token: ${{ secrets.GH_PAT_WORKFLOWS }} to the claude-issue job, granting Claude the workflows scope needed to push .github/workflows/ file changes

Why

All 51 open compliance issues labeled claude triggered successfully but ~40% involve missing workflow files (agent-shield.yml, codeql.yml, ci.yml). Claude was blocked from creating PRs for these because the Claude GitHub App token intentionally lacks workflows write. The PAT bypasses this limitation.

Centralizing the prompt avoids maintaining identical copies of claude.yml across 7 repos.

Test plan

  • Verify GH_PAT_WORKFLOWS org secret is set with a PAT that has workflow scope
  • Merge this PR, then update all repo-level claude.yml files to the slim caller
  • Re-label a workflow-related compliance issue with claude and confirm the PR is created successfully

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Introduced a new reusable GitHub Actions workflow for Claude Code integration
    • Refactored existing Claude Code workflow to utilize the new reusable workflow, improving maintainability and consistency across the organization
    • Maintains existing functionality for both interactive and automated code assistance modes

…port

Centralizes the Claude Code prompt and config into a reusable workflow
(claude-code-reusable.yml) so repo-level claude.yml files are thin callers.
Adds github_token input using GH_PAT_WORKFLOWS secret to grant workflows
write permission, unblocking Claude from pushing .github/workflows/ changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 6, 2026 16:27
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 6, 2026

📝 Walkthrough

Walkthrough

Introduces a new reusable GitHub Actions workflow that consolidates Claude Code automation logic previously split across jobs and steps. The existing workflow is refactored to call this centralized reusable workflow, reducing duplication while maintaining the same trigger conditions and execution paths.

Changes

Cohort / File(s) Summary
Reusable Claude Code Workflow
.github/workflows/claude-code-reusable.yml
New reusable workflow defining two jobs: claude for interactive PR/mention-triggered mode with PR/issue write permissions, and claude-issue for automated labeled-issue mode with concurrency control, custom prompts for multi-step implementation, and CODEOWNERS-based notifications.
Workflow Refactor
.github/workflows/claude.yml
Replaced two explicit jobs (claude, claude-issue) with their complete step definitions and configuration with a single job (claude-code) that calls the reusable workflow via uses: and delegates all logic and secret management.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: extracting the Claude Code workflow into a reusable workflow and adding workflows write permission support via the new PAT.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/reusable-claude-workflow

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Apr 6, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
2 Security Hotspots

See analysis details on SonarQube Cloud

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Centralizes the repository’s Claude Code automation by moving the full workflow logic into a reusable GitHub Actions workflow and converting .github/workflows/claude.yml into a thin caller, including support for using a PAT to enable workflow-file updates.

Changes:

  • Added a reusable workflow (claude-code-reusable.yml) containing both interactive and issue-automation Claude jobs.
  • Simplified .github/workflows/claude.yml to call the reusable workflow via workflow_call with inherited secrets.
  • Introduced passing a PAT (GH_PAT_WORKFLOWS) to Claude issue automation to allow changes under .github/workflows/.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
.github/workflows/claude.yml Replaced in-repo job definitions with a reusable workflow caller and delegated configuration.
.github/workflows/claude-code-reusable.yml New reusable workflow containing the full Claude interactive + issue automation configuration, including PAT support.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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.
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.
timeout-minutes: 60
claude-code:
uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main
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.
Comment on lines +6 to +8
on:
workflow_call:
secrets:
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.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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-reusable.yml:
- Around line 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.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0df51c1b-ac84-4a63-92aa-741daf9e92e5

📥 Commits

Reviewing files that changed from the base of the PR and between 6ce0e96 and b3c2aa1.

📒 Files selected for processing (2)
  • .github/workflows/claude-code-reusable.yml
  • .github/workflows/claude.yml

Comment on lines +75 to +77
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.GH_PAT_WORKFLOWS }}
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants