Skip to content

[codex] Add Claude GitHub Action workflow#2038

Draft
kkraus14 wants to merge 4 commits intoNVIDIA:mainfrom
kkraus14:add-claude-github-action
Draft

[codex] Add Claude GitHub Action workflow#2038
kkraus14 wants to merge 4 commits intoNVIDIA:mainfrom
kkraus14:add-claude-github-action

Conversation

@kkraus14
Copy link
Copy Markdown
Collaborator

@kkraus14 kkraus14 commented May 6, 2026

What changed

Adds the Claude Code GitHub Actions workflow so repository maintainers can invoke Claude from issues, PR comments, PR review comments, and PR reviews with @claude.

The workflow includes a read-only authorization job that checks the triggering actor's actual repository permission through GitHub before granting write permissions or exposing ANTHROPIC_API_KEY. The Claude job only runs for actors with write, maintain, or admin access.

Why

The Claude GitHub app and ANTHROPIC_API_KEY secret are already configured for this repository. This wires in the official anthropics/claude-code-action workflow while following Anthropic's security guidance that Claude usage should be restricted to users with write access.

Validation

  • git diff --check -- .github/workflows/claude.yml
  • pre-commit run actionlint --files .github/workflows/claude.yml

kkraus14 and others added 2 commits May 6, 2026 11:07
Adds the standard `anthropics/claude-code-action@v1` workflow so
maintainers can invoke Claude on issues and PRs via `@claude`. The
job's `if:` condition restricts triggering to actors whose
`author_association` on the comment/review/issue is `OWNER`, `MEMBER`,
or `COLLABORATOR` so that only repository maintainers can grant Claude
the read/write access this workflow exposes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@copy-pr-bot
Copy link
Copy Markdown
Contributor

copy-pr-bot Bot commented May 6, 2026

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@kkraus14 kkraus14 added the CI/CD CI/CD infrastructure label May 6, 2026 — with ChatGPT Codex Connector
@leofang
Copy link
Copy Markdown
Member

leofang commented May 6, 2026

@rwgk now is the one on the team who knows the best how to do permission/membership check robustly in GHA. Assigning Ralf as a reviewer.

@leofang leofang requested a review from rwgk May 6, 2026 17:53
if: needs.authorize.outputs.has_write_access == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Instead of this, I would much prefer if Claude could push all of its work to a fork and iterate on the fork, but that doesn't seem possible without extensive work. Would love thoughts here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just came to +1 this. I haven't even figured out how to get it to work on /my/ fork, and its habit of creating branches on the main fork makes the main fork much slower/harder to deal with.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My concern with direct iterative work on a public PR is reviewability: the intermediate agent churn can easily swamp the signal humans need. I’d rather keep AI iteration local and only surface milestones once a human decides the result is ready for shared review.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With Copilot I usually tell it to send a PR to my fork to avoid noise. Once I am happy, I send a PR upstream from the same branch. Example:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The benefit is that when upstream (CuPy) merges the PR, and I sync my fork with upstream, the fork PR is auto-closed. But it only works with the CuPy case because we do merge commits there instead of squash/rebase (yes, I am pointing fingers 😂 Squash/rebase is unfriendly to tooling and automation).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Conda-forge bots always do work in their forks. Example: conda-forge/cccl-python-feedstock#35 was sent from https://github.com/regro-cf-autotick-bot/cccl-python-feedstock. I imagine for Claude & co to follow the same pattern, we'd probably need a service account...?

Copy link
Copy Markdown
Contributor

@mdboom mdboom May 7, 2026

Choose a reason for hiding this comment

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

My concern with direct iterative work on a public PR is reviewability: the intermediate agent churn can easily swamp the signal humans need. I’d rather keep AI iteration local and only surface milestones once a human decides the result is ready for shared review.

+1 to this. I have been thinking this as well lately. It shouldn't be part of the normal workflow to create a PR just to interact with an agent. It's not necessary -- I have plenty of ways to interact with an agent on my machine. It crowds out the main space where humans interact, which requires a communication/collaboration tool like this.

@rwgk
Copy link
Copy Markdown
Contributor

rwgk commented May 6, 2026

github won't let me post a code comment (internal error for the last hour) :-(

Referring to this line:

+        contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) ||

Heads-up comment: While working on restricted-paths-guard.yml, I ran into the problem that CONTRIBUTOR appeared in some cases (but not all), where the user was also a COLLABORATOR. The situation wasn't exactly the same, but it's something I'd watch out for here.

xref: #1930 (comment)

@kkraus14
Copy link
Copy Markdown
Collaborator Author

kkraus14 commented May 6, 2026

I'm trying to use that just as a lossy filter to prevent launching extra github actions jobs to more deterministically determine if someone properly has write permission to the repo. It could potentially be extended to COLLABORATOR since that's still a small group?

Copy link
Copy Markdown
Contributor

@rwgk rwgk left a comment

Choose a reason for hiding this comment

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

Cursor GPT-5.4 Extra High Fast

Findings

  1. Blocking: .github/workflows/claude.yml:37 scoped the authorize job to contents: read, but the permission gate calls GitHub's collaborator-permission API from .github/workflows/claude.yml:53. That endpoint requires write-level repository access, so maintainer @claude requests can be skipped because the auth check fails before Claude runs.
  2. Medium: .github/workflows/claude.yml:53 previously suppressed all API errors with 2>/dev/null || true, then treated the actor as unauthorized. That hides real GitHub/API/auth failures behind a misleading "does not have write access" message and makes the workflow harder to debug.

Suggested fixes

  1. Change the authorize job permission to contents: write so the workflow token can call the collaborator-permission endpoint.
  2. Capture the gh api result explicitly, treat HTTP 404 as an expected "no effective access" case, and fail the job on other API errors so configuration or platform failures are surfaced immediately.
diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml
index f092ed3bd6..45451e295e 100644
--- a/.github/workflows/claude.yml
+++ b/.github/workflows/claude.yml
@@ -35,7 +35,7 @@ jobs:
         contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.issue.author_association))
     runs-on: ubuntu-latest
     permissions:
-      contents: read
+      contents: write  # Required for collaborator permission API
     outputs:
       has_write_access: ${{ steps.actor-permission.outputs.has_write_access }}
     steps:
@@ -48,7 +48,20 @@ jobs:
         run: |
           set -euo pipefail
 
-          permission="$(gh api "repos/${GH_REPO}/collaborators/${TRIGGERING_ACTOR}/permission" --jq '.permission' 2>/dev/null || true)"
+          PERMISSION_RESPONSE=""
+
+          if PERMISSION_RESPONSE=$(
+            gh api "repos/${GH_REPO}/collaborators/${TRIGGERING_ACTOR}/permission" \
+              --jq '.permission' 2>&1
+          ); then
+            permission="${PERMISSION_RESPONSE}"
+          elif [[ "${PERMISSION_RESPONSE}" == *"(HTTP 404)"* ]]; then
+            permission="none"
+          else
+            echo "::error::Failed to inspect collaborator permission for ${TRIGGERING_ACTOR}."
+            printf '%s\n' "${PERMISSION_RESPONSE}"
+            exit 1
+          fi
 
           case "${permission}" in
             admin|maintain|write)
@@ -56,7 +69,7 @@ jobs:
               ;;
             *)
               echo "has_write_access=false" >> "$GITHUB_OUTPUT"
-              echo "Skipping Claude because ${TRIGGERING_ACTOR} does not have write access to ${GH_REPO}."
+              echo "Skipping Claude because ${TRIGGERING_ACTOR} has ${permission} access to ${GH_REPO}; write, maintain, or admin is required."
               ;;
           esac

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

Labels

CI/CD CI/CD infrastructure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants