From fe37438d013c71524013773e035306c52e7c3b5e Mon Sep 17 00:00:00 2001 From: Andrew Rich Date: Fri, 6 Mar 2026 16:56:23 -0800 Subject: [PATCH 1/2] feat: add claude-assistant reusable workflow Extract Claude Code Action invocation into a workflow_call reusable workflow. All consumer repos can now use a thin caller that delegates implementation here, keeping the author_association security guard per-repo while centralizing the checkout + action steps. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/claude-assistant.yml | 56 ++++++++++++++++++++++++++ .github/workflows/claude.yml | 32 ++------------- 2 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 .github/workflows/claude-assistant.yml diff --git a/.github/workflows/claude-assistant.yml b/.github/workflows/claude-assistant.yml new file mode 100644 index 0000000..38f9aa8 --- /dev/null +++ b/.github/workflows/claude-assistant.yml @@ -0,0 +1,56 @@ +name: Claude Code Assistant + +# Reusable workflow: invokes Claude Code Action when @claude is mentioned. +# The caller workflow is responsible for event triggers and the +# author_association guard that restricts who can invoke Claude. +# +# Usage in a caller workflow: +# +# jobs: +# claude: +# 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)) +# uses: smartwatermelon/github-workflows/.github/workflows/claude-assistant.yml@v1 +# secrets: +# claude_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + +on: + workflow_call: + secrets: + claude_oauth_token: + description: 'Claude Code OAuth token (CLAUDE_CODE_OAUTH_TOKEN secret)' + required: true + +jobs: + run: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + actions: read # Required for Claude to read CI results on PRs + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.claude_oauth_token }} + + # Required for Claude to read CI results on PRs + additional_permissions: | + actions: read + + # Optional: Give a custom prompt to Claude. If not specified, Claude + # performs the instructions in the comment that tagged it. + # prompt: 'Update the pull request description to include a summary of changes.' + + # Optional: restrict which tools Claude can use + # claude_args: '--allowed-tools Bash(gh pr:*)' diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index fcaf98b..832c3e5 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -17,32 +17,6 @@ jobs: (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 - permissions: - contents: read - pull-requests: read - issues: read - actions: read # Required for Claude to read CI results on PRs - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Run Claude Code - id: claude - uses: anthropics/claude-code-action@v1 - with: - claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - - # This is an optional setting that allows Claude to read CI results on PRs - additional_permissions: | - actions: read - - # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. - # prompt: 'Update the pull request description to include a summary of changes.' - - # Optional: Add claude_args to customize behavior and configuration - # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md - # or https://code.claude.com/docs/en/cli-reference for available options - # claude_args: '--allowed-tools Bash(gh pr:*)' + uses: smartwatermelon/github-workflows/.github/workflows/claude-assistant.yml@v1 + secrets: + claude_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} From 50988fa6e7cee73e233a10581ee866e811c04b70 Mon Sep 17 00:00:00 2001 From: Andrew Rich Date: Fri, 6 Mar 2026 17:06:33 -0800 Subject: [PATCH 2/2] fix: pin action SHAs in claude-assistant.yml Per project convention, third-party actions must be pinned to full commit SHAs to prevent supply-chain attacks via tag mutation. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/claude-assistant.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/claude-assistant.yml b/.github/workflows/claude-assistant.yml index 38f9aa8..3d05212 100644 --- a/.github/workflows/claude-assistant.yml +++ b/.github/workflows/claude-assistant.yml @@ -34,13 +34,13 @@ jobs: actions: read # Required for Claude to read CI results on PRs steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 1 - name: Run Claude Code id: claude - uses: anthropics/claude-code-action@v1 + uses: anthropics/claude-code-action@26ec041249acb0a944c0a47b6c0c13f05dbc5b44 # v1 with: claude_code_oauth_token: ${{ secrets.claude_oauth_token }}