From b9d56e581e7334add4ea1c88987a134446ed8e8e Mon Sep 17 00:00:00 2001 From: Zander Raycraft Date: Wed, 18 Mar 2026 17:35:43 -0500 Subject: [PATCH 1/4] test fix for claude call --- .github/workflows/claude-code-review.yml | 1 + .github/workflows/claude.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 04795bc18..d1ec11473 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -110,6 +110,7 @@ jobs: uses: anthropics/claude-code-action@9469d113c6afd29550c402740f22d1a97dd1209b # v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + show_full_output: true plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' plugins: 'code-review@claude-code-plugins' prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ steps.pr.outputs.number }}' diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 12fc0ccaa..874914857 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -104,6 +104,7 @@ jobs: uses: anthropics/claude-code-action@9469d113c6afd29550c402740f22d1a97dd1209b # v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + show_full_output: true # This is an optional setting that allows Claude to read CI results on PRs additional_permissions: | From b736dff10078955496a95ceb67360726fa167ee6 Mon Sep 17 00:00:00 2001 From: Zander Raycraft Date: Thu, 19 Mar 2026 14:08:48 -0500 Subject: [PATCH 2/4] claude reviewer update --- .github/workflows/claude-code-review.yml | 52 +++++------------------- .github/workflows/claude.yml | 51 ++++------------------- 2 files changed, 20 insertions(+), 83 deletions(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index d1ec11473..7fb230f66 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -2,9 +2,9 @@ name: Claude Code Review # Uses pull_request_target so the workflow runs as defined on the default branch, # which allows access to secrets for posting review comments on fork PRs. -# SECURITY: The checkout below uses the PR head SHA to review the correct code. -# The claude-code-action sandboxes execution — it does NOT run arbitrary code -# from the checked-out source. +# SECURITY: The checkout uses the fork's repo/branch directly so the action +# can find the ref. The claude-code-action sandboxes execution — it does NOT +# run arbitrary code from the checked-out source. on: # Trigger only when explicitly requested: @@ -15,8 +15,7 @@ on: issue_comment: types: [created] -# Serialize per-PR so concurrent @claude comments don't race on the -# temporary fork branch push/delete. +# Serialize per-PR to avoid racing review comments. concurrency: group: claude-review-${{ github.event.issue.number || github.event.pull_request.number }} cancel-in-progress: false @@ -47,13 +46,13 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 permissions: - contents: write # needed to create fork branch ref via API + contents: read pull-requests: write issues: read id-token: write steps: - # For issue_comment triggers, resolve the PR number, head SHA, and branch name + # For issue_comment triggers, resolve the PR number, head SHA, and fork repo - name: Resolve PR context id: pr uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 @@ -72,53 +71,24 @@ jobs: } core.setOutput('number', pr.number); core.setOutput('sha', pr.head.sha); + core.setOutput('repo', pr.head.repo.full_name); core.setOutput('branch', pr.head.ref); - core.setOutput('is_fork', String(pr.head.repo.full_name !== pr.base.repo.full_name)); - name: Checkout PR head uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: - ref: ${{ steps.pr.outputs.sha }} + repository: ${{ steps.pr.outputs.repo }} + ref: ${{ steps.pr.outputs.branch }} fetch-depth: 1 - # claude-code-action fetches branches by name from origin, which fails - # for fork PRs. Create a temporary branch ref via the API so the action - # can find it. Using the API (not git push) avoids the GITHUB_TOKEN - # restriction that blocks pushing commits containing workflow file changes. - # Use a prefixed temporary branch name to avoid overwriting real branches - # (e.g. a fork branch named "main" would overwrite origin/main). - - name: Create fork branch ref on origin - id: push-fork - if: steps.pr.outputs.is_fork == 'true' - env: - FORK_BRANCH: claude-tmp/fork-pr-${{ steps.pr.outputs.number }} - FORK_SHA: ${{ steps.pr.outputs.sha }} - GH_TOKEN: ${{ github.token }} - run: | - echo "FORK_BRANCH=$FORK_BRANCH" >> "$GITHUB_ENV" - gh api "repos/${{ github.repository }}/git/refs" \ - --method POST \ - -f ref="refs/heads/$FORK_BRANCH" \ - -f sha="$FORK_SHA" \ - || gh api "repos/${{ github.repository }}/git/refs/heads/$FORK_BRANCH" \ - --method PATCH \ - -f sha="$FORK_SHA" \ - -F force=true - - name: Run Claude Code Review id: claude-review uses: anthropics/claude-code-action@9469d113c6afd29550c402740f22d1a97dd1209b # v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + github_token: ${{ secrets.GITHUB_TOKEN }} + allowed_non_write_users: '*' show_full_output: true plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' plugins: 'code-review@claude-code-plugins' prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ steps.pr.outputs.number }}' - - # Clean up the temporary branch ref we created for fork PRs. - # Only delete if the create step actually succeeded. - - name: Delete fork branch ref from origin - if: always() && steps.push-fork.outcome == 'success' - env: - GH_TOKEN: ${{ github.token }} - run: gh api "repos/${{ github.repository }}/git/refs/heads/$FORK_BRANCH" --method DELETE || true diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 874914857..e1c6f031c 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -10,8 +10,7 @@ on: pull_request_review: types: [submitted] -# Serialize per-PR so concurrent @claude comments don't race on the -# temporary fork branch push/delete. +# Serialize per-PR/issue to avoid racing comments. concurrency: group: claude-code-${{ github.event.issue.number || github.event.pull_request.number || github.event.issue.id }} cancel-in-progress: false @@ -26,14 +25,13 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 permissions: - contents: write # needed to create fork branch ref via API + contents: read pull-requests: write issues: write id-token: write actions: read # required for Claude to read CI results on PRs steps: - # For PR-related triggers, resolve fork context so we can create a - # temporary branch ref (claude-code-action fetches by branch name). + # For PR-related triggers, resolve the fork repo so we can checkout correctly. - name: Resolve PR context id: pr uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 @@ -51,7 +49,6 @@ jobs: if (!prNumber) { core.setOutput('is_pr', 'false'); - core.setOutput('is_fork', 'false'); return; } @@ -61,59 +58,29 @@ jobs: pull_number: prNumber, }); const pr = resp.data; - const isFork = pr.head.repo.full_name !== pr.base.repo.full_name; core.setOutput('is_pr', 'true'); core.setOutput('number', String(prNumber)); - core.setOutput('is_fork', String(isFork)); - core.setOutput('branch', pr.head.ref); core.setOutput('sha', pr.head.sha); + core.setOutput('repo', pr.head.repo.full_name); + core.setOutput('branch', pr.head.ref); - name: Checkout repository uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: - ref: ${{ steps.pr.outputs.is_fork == 'true' && steps.pr.outputs.sha || '' }} + repository: ${{ steps.pr.outputs.is_pr == 'true' && steps.pr.outputs.repo || github.repository }} + ref: ${{ steps.pr.outputs.is_pr == 'true' && steps.pr.outputs.branch || '' }} fetch-depth: 1 - # claude-code-action fetches branches by name from origin, which fails - # for fork PRs. Create a temporary branch ref via the API so the action - # can find it. Using the API (not git push) avoids the GITHUB_TOKEN - # restriction that blocks pushing commits containing workflow file changes. - # Use a prefixed temporary branch name to avoid overwriting real branches - # (e.g. a fork branch named "main" would overwrite origin/main). - - name: Create fork branch ref on origin - id: push-fork - if: steps.pr.outputs.is_fork == 'true' - env: - FORK_BRANCH: claude-tmp/fork-pr-${{ steps.pr.outputs.number }} - FORK_SHA: ${{ steps.pr.outputs.sha }} - GH_TOKEN: ${{ github.token }} - run: | - echo "FORK_BRANCH=$FORK_BRANCH" >> "$GITHUB_ENV" - gh api "repos/${{ github.repository }}/git/refs" \ - --method POST \ - -f ref="refs/heads/$FORK_BRANCH" \ - -f sha="$FORK_SHA" \ - || gh api "repos/${{ github.repository }}/git/refs/heads/$FORK_BRANCH" \ - --method PATCH \ - -f sha="$FORK_SHA" \ - -F force=true - - name: Run Claude Code id: claude uses: anthropics/claude-code-action@9469d113c6afd29550c402740f22d1a97dd1209b # v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + github_token: ${{ secrets.GITHUB_TOKEN }} + allowed_non_write_users: '*' show_full_output: true # This is an optional setting that allows Claude to read CI results on PRs additional_permissions: | actions: read - - # Clean up the temporary branch ref we created for fork PRs. - # Only delete if the create step actually succeeded. - - name: Delete fork branch ref from origin - if: always() && steps.push-fork.outcome == 'success' - env: - GH_TOKEN: ${{ github.token }} - run: gh api "repos/${{ github.repository }}/git/refs/heads/$FORK_BRANCH" --method DELETE || true From 7ebbd818a907367746871e321324ed73a27faa42 Mon Sep 17 00:00:00 2001 From: Zander Raycraft Date: Thu, 19 Mar 2026 14:12:53 -0500 Subject: [PATCH 3/4] manual trigger for testing on pr comments --- .github/workflows/claude.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index e1c6f031c..43ffbec27 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -9,15 +9,24 @@ on: types: [opened, assigned] pull_request_review: types: [submitted] + # TEMP: Manual trigger to test fork checkout fix from a feature branch. + # Remove before merging to main. + workflow_dispatch: + inputs: + pr_number: + description: 'PR number to test against' + required: true + type: string # Serialize per-PR/issue to avoid racing comments. concurrency: - group: claude-code-${{ github.event.issue.number || github.event.pull_request.number || github.event.issue.id }} + group: claude-code-${{ github.event.issue.number || github.event.pull_request.number || github.event.issue.id || github.run_id }} cancel-in-progress: false jobs: claude: if: | + github.event_name == 'workflow_dispatch' || (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || @@ -39,7 +48,9 @@ jobs: script: | // Determine if this event is PR-related let prNumber = null; - if (context.eventName === 'issue_comment' && context.payload.issue.pull_request) { + if (context.eventName === 'workflow_dispatch') { + prNumber = Number(context.payload.inputs.pr_number); + } else if (context.eventName === 'issue_comment' && context.payload.issue.pull_request) { prNumber = context.payload.issue.number; } else if (context.eventName === 'pull_request_review_comment') { prNumber = context.payload.pull_request.number; From 96ec9f2b4221525ee30aa2ce4c22a760c29cc9ce Mon Sep 17 00:00:00 2001 From: Zander Raycraft Date: Thu, 19 Mar 2026 15:34:56 -0500 Subject: [PATCH 4/4] remove manual test --- .github/workflows/claude.yml | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 43ffbec27..e1c6f031c 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -9,24 +9,15 @@ on: types: [opened, assigned] pull_request_review: types: [submitted] - # TEMP: Manual trigger to test fork checkout fix from a feature branch. - # Remove before merging to main. - workflow_dispatch: - inputs: - pr_number: - description: 'PR number to test against' - required: true - type: string # Serialize per-PR/issue to avoid racing comments. concurrency: - group: claude-code-${{ github.event.issue.number || github.event.pull_request.number || github.event.issue.id || github.run_id }} + group: claude-code-${{ github.event.issue.number || github.event.pull_request.number || github.event.issue.id }} cancel-in-progress: false jobs: claude: if: | - github.event_name == 'workflow_dispatch' || (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || @@ -48,9 +39,7 @@ jobs: script: | // Determine if this event is PR-related let prNumber = null; - if (context.eventName === 'workflow_dispatch') { - prNumber = Number(context.payload.inputs.pr_number); - } else if (context.eventName === 'issue_comment' && context.payload.issue.pull_request) { + if (context.eventName === 'issue_comment' && context.payload.issue.pull_request) { prNumber = context.payload.issue.number; } else if (context.eventName === 'pull_request_review_comment') { prNumber = context.payload.pull_request.number;