From 90625f6832d1c2bd17db7defc5c23c83d188d26d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 7 Apr 2026 07:29:08 -0700 Subject: [PATCH 1/2] CI: restrict cuda_bindings changes to NVIDIA members Keep the PR policy workflow self-contained by using the pull request payload and files API to block non-members from modifying low-level bindings. Made-with: Cursor --- .github/workflows/pr-metadata-check.yml | 62 ++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pr-metadata-check.yml b/.github/workflows/pr-metadata-check.yml index d8cf91579d..e86b431eda 100644 --- a/.github/workflows/pr-metadata-check.yml +++ b/.github/workflows/pr-metadata-check.yml @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -name: "CI: Enforce assignee/label/milestone on PRs" +name: "CI: Enforce PR metadata and cuda_bindings policy" on: pull_request_target: @@ -19,18 +19,32 @@ on: jobs: check-metadata: - name: PR has assignee, labels, and milestone + name: PR has required metadata and valid cuda_bindings author if: github.repository_owner == 'NVIDIA' runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read steps: - - name: Check for assignee, labels, and milestone + - name: Check PR metadata and cuda_bindings policy env: + # PR metadata inputs ASSIGNEES: ${{ toJson(github.event.pull_request.assignees) }} + AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association || 'NONE' }} LABELS: ${{ toJson(github.event.pull_request.labels) }} MILESTONE: ${{ github.event.pull_request.milestone && github.event.pull_request.milestone.title || '' }} + PR_AUTHOR: ${{ github.event.pull_request.user.login }} + PR_NUMBER: ${{ github.event.pull_request.number }} PR_URL: ${{ github.event.pull_request.html_url }} + + # Gating booleans IS_BOT: ${{ github.actor == 'dependabot[bot]' || github.actor == 'pre-commit-ci[bot]' || github.actor == 'copy-pr-bot[bot]' }} IS_DRAFT: ${{ github.event.pull_request.draft }} + + # API request context/auth + GITHUB_API_URL: ${{ github.api_url }} + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} run: | if [ "$IS_BOT" = "true" ] || [ "$IS_DRAFT" = "true" ]; then echo "Skipping check for bot or draft PR." @@ -103,10 +117,45 @@ jobs: ERRORS="${ERRORS}- **Blocked label detected**: label \`$label\` prevents merging. Remove it when the PR is ready.\n" done <<<"$BLOCKED_LABELS" + # Only NVIDIA organization members may change code under cuda_bindings. + if [ "$AUTHOR_ASSOCIATION" != "MEMBER" ] && [ "$AUTHOR_ASSOCIATION" != "OWNER" ]; then + page=1 + TOUCHES_CUDA_BINDINGS=false + while true; do + FILES_JSON=$(curl --silent --show-error --fail \ + -H "Authorization: Bearer $GH_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "$GITHUB_API_URL/repos/$REPO/pulls/$PR_NUMBER/files?per_page=100&page=$page") + + if jq -e ' + .[] + | select( + (.filename | startswith("cuda_bindings/")) + or ((.previous_filename // "") | startswith("cuda_bindings/")) + ) + ' <<<"$FILES_JSON" >/dev/null; then + TOUCHES_CUDA_BINDINGS=true + break + fi + + FILE_COUNT=$(jq 'length' <<<"$FILES_JSON") + if [ "$FILE_COUNT" -lt 100 ]; then + break + fi + + page=$((page + 1)) + done + + if [ "$TOUCHES_CUDA_BINDINGS" = "true" ]; then + ERRORS="${ERRORS}- **cuda_bindings policy**: See \`cuda_bindings/LICENSE\`. Only NVIDIA organization members may modify files under \`cuda_bindings/\` (PR author \`$PR_AUTHOR\` has association \`$AUTHOR_ASSOCIATION\`).\n" + fi + fi + if [ -n "$ERRORS" ]; then - echo "::error::This PR is missing required metadata. See the job summary for details." + echo "::error::This PR failed the required metadata/policy checks. See the job summary for details." { - echo "## PR Metadata Check Failed" + echo "## PR Requirements Check Failed" echo "" printf '%b' "$ERRORS" echo "" @@ -118,9 +167,10 @@ jobs: ASSIGNEE_LIST=$(echo "$ASSIGNEES" | jq -r '.[].login' | paste -sd ', ' -) LABEL_LIST=$(echo "$LABELS" | jq -r '.[].name' | paste -sd ', ' -) { - echo "## PR Metadata Check Passed" + echo "## PR Requirements Check Passed" echo "" echo "- **Assignees**: $ASSIGNEE_LIST" echo "- **Labels**: $LABEL_LIST" echo "- **Milestone**: $MILESTONE" + echo "- **Author association**: $AUTHOR_ASSOCIATION" } >> "$GITHUB_STEP_SUMMARY" From a52b862aa0bb566e15ea6abc230993855102eb65 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 7 Apr 2026 10:26:30 -0700 Subject: [PATCH 2/2] CI: use gh api for cuda_bindings policy checks Align the PR metadata workflow with repo conventions by using gh to paginate the PR file list, keeping the bindings restriction check simpler and easier to review. Made-with: Cursor --- .github/workflows/pr-metadata-check.yml | 45 ++++++++++--------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/.github/workflows/pr-metadata-check.yml b/.github/workflows/pr-metadata-check.yml index e86b431eda..8f6b915c5a 100644 --- a/.github/workflows/pr-metadata-check.yml +++ b/.github/workflows/pr-metadata-check.yml @@ -42,7 +42,6 @@ jobs: IS_DRAFT: ${{ github.event.pull_request.draft }} # API request context/auth - GITHUB_API_URL: ${{ github.api_url }} GH_TOKEN: ${{ github.token }} REPO: ${{ github.repository }} run: | @@ -119,33 +118,23 @@ jobs: # Only NVIDIA organization members may change code under cuda_bindings. if [ "$AUTHOR_ASSOCIATION" != "MEMBER" ] && [ "$AUTHOR_ASSOCIATION" != "OWNER" ]; then - page=1 - TOUCHES_CUDA_BINDINGS=false - while true; do - FILES_JSON=$(curl --silent --show-error --fail \ - -H "Authorization: Bearer $GH_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "$GITHUB_API_URL/repos/$REPO/pulls/$PR_NUMBER/files?per_page=100&page=$page") - - if jq -e ' - .[] - | select( - (.filename | startswith("cuda_bindings/")) - or ((.previous_filename // "") | startswith("cuda_bindings/")) - ) - ' <<<"$FILES_JSON" >/dev/null; then - TOUCHES_CUDA_BINDINGS=true - break - fi - - FILE_COUNT=$(jq 'length' <<<"$FILES_JSON") - if [ "$FILE_COUNT" -lt 100 ]; then - break - fi - - page=$((page + 1)) - done + if ! TOUCHES_CUDA_BINDINGS=$( + gh api \ + --paginate \ + --slurp \ + --jq ' + flatten + | any( + .[]; + (.filename | startswith("cuda_bindings/")) + or ((.previous_filename // "") | startswith("cuda_bindings/")) + ) + ' \ + "repos/$REPO/pulls/$PR_NUMBER/files" + ); then + echo "::error::Failed to inspect the PR file list." + exit 1 + fi if [ "$TOUCHES_CUDA_BINDINGS" = "true" ]; then ERRORS="${ERRORS}- **cuda_bindings policy**: See \`cuda_bindings/LICENSE\`. Only NVIDIA organization members may modify files under \`cuda_bindings/\` (PR author \`$PR_AUTHOR\` has association \`$AUTHOR_ASSOCIATION\`).\n"