Skip to content

feat: switch to org-level reusable Claude Code workflow - #40

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

feat: switch to org-level reusable Claude Code workflow#40
don-petry merged 1 commit into
mainfrom
feat/reusable-claude-workflow

Conversation

@don-petry

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

Copy link
Copy Markdown
Contributor

Summary

  • Replaces inline claude.yml with a thin caller that delegates to petry-projects/.github/.github/workflows/claude-code-reusable.yml@main
  • Prompt, config, and GH_PAT_WORKFLOWS support are now maintained centrally in the org repo
  • No behavioral change — same triggers, same permissions, same Claude behavior

Why

Centralizes maintenance so prompt/config updates only need one change instead of 7. Also adds github_token with workflows write scope so Claude can push .github/workflows/ files (previously blocked).

Test plan

  • CI passes on this PR
  • After merge, label a compliance issue with claude and verify Claude creates a PR

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Streamlined GitHub Actions workflow configuration by consolidating automation jobs into a centralized reusable workflow template. This improves maintainability and consistency of automated processes.

Copilot AI review requested due to automatic review settings April 6, 2026 18:17
@coderabbitai

coderabbitai Bot commented Apr 6, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The workflow consolidates two separate inline jobs for Claude Code automation into a single job that delegates to an organization-level reusable workflow. This reduces code duplication by centralizing workflow execution logic and configuration management at the org level.

Changes

Cohort / File(s) Summary
Workflow Refactoring
.github/workflows/claude.yml
Replaced two inline jobs (claude, claude-issue) with a single job (claude-code) calling the org reusable workflow. Removed conditional if logic, explicit checkout and action invocation steps, and specific parameters (label_trigger, track_progress, claude_args). Switched from explicit token input to secrets: inherit while preserving job permissions.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Possibly related PRs

  • Add Claude Code GitHub Action #5: Directly modifies the same .github/workflows/claude.yml file; that PR adds inline Claude Code job configuration while this PR consolidates to an org-level reusable workflow approach.
🚥 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 'feat: switch to org-level reusable Claude Code workflow' accurately and concisely describes the main change: replacing inline workflow jobs with a centralized reusable workflow from the org repository.
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

sonarqubecloud Bot commented Apr 6, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
2 Security Hotspots

See analysis details on SonarQube Cloud

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Switches the repository’s Claude automation workflow to a thin “caller” that delegates execution to an org-level reusable GitHub Actions workflow, aiming to centralize maintenance of prompts/config and permissions.

Changes:

  • Replaces the inline Claude Code workflow implementation with a uses: reference to petry-projects/.github/.github/workflows/claude-code-reusable.yml.
  • Inherits secrets and defines job permissions in the caller workflow.
  • Updates workflow header comments to reflect the new delegation model.

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

contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association))
runs-on: ubuntu-latest
timeout-minutes: 60
claude-code:

Copilot AI Apr 6, 2026

Copy link

Choose a reason for hiding this comment

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

The caller job no longer has the event/author gating that previously prevented runs unless (a) the PR head repo is this repo, or (b) an org member/collaborator mentions @claude on a PR/PR review comment. Without an equivalent if: in this workflow, every issue_comment / pull_request_review_comment create event will invoke the reusable workflow, which can unintentionally increase runs and may expose secrets to untrusted triggers. Consider re-adding the if: conditions at the caller level so the security boundary is enforced even if the reusable workflow changes.

Suggested change
claude-code:
claude-code:
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') &&
(github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')) ||
(github.event_name == 'pull_request_review_comment' &&
contains(github.event.comment.body, '@claude') &&
(github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')) ||
github.event_name == 'issues'

Copilot uses AI. Check for mistakes.
timeout-minutes: 60
claude-code:
uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main
secrets: inherit

Copilot AI Apr 6, 2026

Copy link

Choose a reason for hiding this comment

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

secrets: inherit passes all repository/environment secrets to the called workflow. The previous inline workflow only consumed specific secrets (e.g., CLAUDE_CODE_OAUTH_TOKEN), so this is an expansion of secret exposure if the reusable workflow is ever changed/compromised. Prefer explicitly passing only the required secrets to the reusable workflow (or using a dedicated environment with tightly scoped secrets).

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

Copilot uses AI. Check for mistakes.
runs-on: ubuntu-latest
timeout-minutes: 60
claude-code:
uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main

Copilot AI Apr 6, 2026

Copy link

Choose a reason for hiding this comment

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

The reusable workflow reference is pinned to @main. Elsewhere in this repo, GitHub Actions are pinned to immutable SHAs, which reduces supply-chain risk and avoids unexpected behavior changes. Consider pinning the reusable workflow to a specific commit SHA (or an immutable, versioned tag) instead of a moving branch.

Suggested change
uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main
uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@0123456789abcdef0123456789abcdef01234567

Copilot uses AI. Check for mistakes.
Comment on lines 19 to 24
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
secrets: inherit
permissions:
contents: write

Copilot AI Apr 6, 2026

Copy link

Choose a reason for hiding this comment

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

The previous workflow had issue-label automation concurrency (group: claude-issue-${{ github.event.issue.number }} with cancel-in-progress: true) to prevent overlapping runs per issue. That concurrency control is not present in the caller job, so unless the reusable workflow enforces it internally, repeated label events can run in parallel and race. Consider adding the concurrency block back at the caller level (or confirming it exists in the reusable workflow).

Copilot uses AI. Check for mistakes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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.yml:
- Line 21: The reusable workflow reference currently uses the mutable ref
"petry-projects/.github/.github/workflows/claude-code-reusable.yml@main";
replace the "@main" ref with an immutable commit SHA for that reusable workflow
to prevent downstream changes (update the uses: entry to point to the specific
commit SHA of petry-projects/.github that you trust). Locate the uses: line in
this file (the line containing
petry-projects/.github/.github/workflows/claude-code-reusable.yml@main) and
substitute the branch name with the exact commit SHA, then commit the change.
- Line 22: The workflow currently forwards all secrets via "secrets: inherit"
when calling the reusable workflow (uses:
petry-projects/.github/.github/workflows/claude-code-reusable.yml@main); replace
that with an explicit list of only the secrets that reusable workflow actually
needs by opening that reusable workflow file and copying its required secret
names, then change the caller to map each required secret explicitly (e.g.,
SECRET_NAME: ${{ secrets.SECRET_NAME }}) instead of inheriting everything;
remove "secrets: inherit" and only pass the minimal set discovered in the
reusable workflow.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 17227aa7-6754-44a5-9a53-0b9bfc4dd7c7

📥 Commits

Reviewing files that changed from the base of the PR and between a171dbf and c3d8a52.

📒 Files selected for processing (1)
  • .github/workflows/claude.yml

runs-on: ubuntu-latest
timeout-minutes: 60
claude-code:
uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main

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 | head -30

Repository: petry-projects/ContentTwin

Length of output: 1055


🏁 Script executed:

# Check if there are other workflow references in the repository
find .github -name "*.yml" -o -name "*.yaml" | head -20

Repository: petry-projects/ContentTwin

Length of output: 266


🏁 Script executed:

# Search for other uses of reusable workflows to see if there's a pattern
rg "uses:.*/.github/workflows" .github

Repository: petry-projects/ContentTwin

Length of output: 179


Pin the reusable workflow to an immutable ref.

Line 21 uses @main, which allows behavior/security to change without a PR in this repo. Since this workflow has write permissions (contents, pull-requests, issues), pin to a commit SHA instead.

🔒 Suggested fix
-    uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main
+    uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@<commit-sha>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/claude.yml at line 21, The reusable workflow reference
currently uses the mutable ref
"petry-projects/.github/.github/workflows/claude-code-reusable.yml@main";
replace the "@main" ref with an immutable commit SHA for that reusable workflow
to prevent downstream changes (update the uses: entry to point to the specific
commit SHA of petry-projects/.github that you trust). Locate the uses: line in
this file (the line containing
petry-projects/.github/.github/workflows/claude-code-reusable.yml@main) and
substitute the branch name with the exact commit SHA, then commit the change.

timeout-minutes: 60
claude-code:
uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main
secrets: inherit

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:

# Check if the file exists and read the workflow
cat -n .github/workflows/claude.yml | head -40

Repository: petry-projects/ContentTwin

Length of output: 1055


🏁 Script executed:

# Search for any references to secrets in the repo and in this workflow file
rg -i "CLAUDE_CODE_OAUTH_TOKEN|GH_PAT_WORKFLOWS" --type yml

# Also check if the reusable workflow file exists locally
find . -name "claude-code-reusable.yml" -o -name "*reusable*" | head -20

Repository: petry-projects/ContentTwin

Length of output: 97


🏁 Script executed:

# Search for secrets without file type specification
rg "CLAUDE_CODE_OAUTH_TOKEN|GH_PAT_WORKFLOWS|secrets:" --max-count 20

# Check if the reusable workflow exists locally
find . -type f -name "*reusable*"

# List all workflow files
find .github/workflows -type f

Repository: petry-projects/ContentTwin

Length of output: 243


🏁 Script executed:

# Search for all secret references across workflow files
rg "\$\{\{.*secrets\." .github/

# Also check the main workflow for any secret usage
cat -n .github/workflows/claude.yml

# Check other workflow files for secret patterns
for file in .github/workflows/*.yml; do
  echo "=== $file ==="
  grep -i "secret" "$file" || echo "no secrets found"
done

Repository: petry-projects/ContentTwin

Length of output: 1626


🏁 Script executed:

# Check for secret definitions in the repository
rg -i "CLAUDE_CODE_OAUTH_TOKEN|GH_PAT_WORKFLOWS" .

# Check for any .github/workflows configuration files
find .github -type f

# Look for any environment or secret configuration files
find . -name "*.env*" -o -name "*secret*" | grep -v ".git"

Repository: petry-projects/ContentTwin

Length of output: 266


🏁 Script executed:

# Check if there are any comments or documentation about required secrets
rg -i "secret|oauth|pat" .github/

# Check if there are any setup files or documentation
cat .github/dependabot.yml

# Look for any references to the org standards or reusable workflow
rg "claude-code|petry-projects" .

Repository: petry-projects/ContentTwin

Length of output: 1555


🏁 Script executed:

# Final confirmation: check if these exact secrets are defined anywhere
rg "CLAUDE_CODE_OAUTH_TOKEN|GH_PAT_WORKFLOWS" --no-heading
echo "Exit code: $?"

Repository: petry-projects/ContentTwin

Length of output: 82


Pass only the required secrets instead of inheriting all.

Line 22 forwards all available secrets to the called workflow, which violates least-privilege security controls. However, the specific secrets suggested in the fix (CLAUDE_CODE_OAUTH_TOKEN, GH_PAT_WORKFLOWS) do not exist in this repository. Determine which secrets the reusable workflow (petry-projects/.github/.github/workflows/claude-code-reusable.yml@main) actually requires and pass only those explicitly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/claude.yml at line 22, The workflow currently forwards all
secrets via "secrets: inherit" when calling the reusable workflow (uses:
petry-projects/.github/.github/workflows/claude-code-reusable.yml@main); replace
that with an explicit list of only the secrets that reusable workflow actually
needs by opening that reusable workflow file and copying its required secret
names, then change the caller to map each required secret explicitly (e.g.,
SECRET_NAME: ${{ secrets.SECRET_NAME }}) instead of inheriting everything;
remove "secrets: inherit" and only pass the minimal set discovered in the
reusable workflow.

@don-petry
don-petry merged commit 1f9ac59 into main Apr 6, 2026
15 of 17 checks passed
@don-petry
don-petry deleted the feat/reusable-claude-workflow branch April 6, 2026 18:33
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