From 09ba2e691072f0776036caeb2050645c888019b4 Mon Sep 17 00:00:00 2001 From: Akshay Dodeja Date: Fri, 29 May 2026 12:31:17 -0700 Subject: [PATCH] fix(ci): address Greptile review on Claude Code workflows Follow-up to #229, which merged before the review was addressed. - Grant write scopes so Claude can actually post back via GITHUB_TOKEN: pull-requests/issues:write in both workflows, plus contents:write in claude.yml for commits/branches (P1). - Restrict claude.yml to trusted actors (OWNER/MEMBER/COLLABORATOR) so outside accounts can't invoke Claude and burn API quota (P2). - Pin claude-code-action from the mutable @v1 tag to commit SHA 787c5a0 (v1.0.133) per GitHub's third-party action hardening guide (P2). Kept `additional_permissions: actions: read` in claude.yml: it is the action's documented opt-in for reading CI results, not a true duplicate of the job-level scope (upstream's example declares both). Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/claude-code-review.yml | 6 +++--- .github/workflows/claude.yml | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index b5e8cfd4..e09e6d41 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -21,8 +21,8 @@ jobs: runs-on: ubuntu-latest permissions: contents: read - pull-requests: read - issues: read + pull-requests: write # Required for Claude to post review comments back to the PR + issues: write id-token: write steps: @@ -33,7 +33,7 @@ jobs: - name: Run Claude Code Review id: claude-review - uses: anthropics/claude-code-action@v1 + uses: anthropics/claude-code-action@787c5a0ce96a9a6cfb050ea0c8f4c05f2447c251 # v1.0.133 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 6b15fac7..0df481d1 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -12,16 +12,18 @@ on: jobs: claude: + # Only trigger for trusted collaborators so outside accounts can't invoke + # Claude (and consume API quota) by posting "@claude" on an issue/PR. if: | - (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')) || - (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + (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)) runs-on: ubuntu-latest permissions: - contents: read - pull-requests: read - issues: read + contents: write # Required for Claude to push commits / create branches + pull-requests: write # Required for Claude to post comments and open PRs + issues: write id-token: write actions: read # Required for Claude to read CI results on PRs steps: @@ -32,7 +34,7 @@ jobs: - name: Run Claude Code id: claude - uses: anthropics/claude-code-action@v1 + uses: anthropics/claude-code-action@787c5a0ce96a9a6cfb050ea0c8f4c05f2447c251 # v1.0.133 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}