|
1 | 1 | # SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
2 | 2 | # SPDX-License-Identifier: Apache-2.0 |
3 | 3 |
|
4 | | -name: "CI: Check PR author organization for restricted paths" |
| 4 | +name: "CI: Check PR author signals for restricted paths" |
5 | 5 |
|
6 | 6 | on: |
| 7 | + # Label updates on fork PRs require pull_request_target permissions. |
| 8 | + # TODO BEFORE MERGING: change to pull_request_target |
7 | 9 | pull_request: |
8 | 10 | types: |
9 | 11 | - opened |
|
13 | 15 |
|
14 | 16 | jobs: |
15 | 17 | check-author-org: |
16 | | - name: PR author may modify restricted paths |
| 18 | + name: PR author signals recorded for restricted paths |
17 | 19 | if: github.repository_owner == 'NVIDIA' |
18 | 20 | runs-on: ubuntu-latest |
19 | 21 | permissions: |
| 22 | + issues: write |
20 | 23 | pull-requests: read |
21 | 24 | steps: |
22 | | - - name: Check PR author organization for restricted paths |
| 25 | + - name: Inspect PR author signals for restricted paths |
23 | 26 | env: |
24 | 27 | # PR metadata inputs |
25 | 28 | AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association || 'NONE' }} |
| 29 | + EXISTING_LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }} |
26 | 30 | PR_AUTHOR: ${{ github.event.pull_request.user.login }} |
27 | 31 | PR_NUMBER: ${{ github.event.pull_request.number }} |
28 | 32 | PR_URL: ${{ github.event.pull_request.html_url }} |
29 | 33 |
|
| 34 | + # Workflow policy inputs |
| 35 | + REVIEW_LABEL: Check-PR-author-ORG |
| 36 | + |
| 37 | + # Checked-in allowlist inputs |
| 38 | + INTERNAL_AUTHOR_ALLOWLIST: | |
| 39 | + rwgk |
| 40 | +
|
30 | 41 | # API request context/auth |
31 | 42 | GH_TOKEN: ${{ github.token }} |
32 | 43 | REPO: ${{ github.repository }} |
33 | 44 | run: | |
| 45 | + set -euo pipefail |
| 46 | +
|
34 | 47 | if ! MATCHING_RESTRICTED_PATHS=$( |
35 | 48 | gh api \ |
36 | 49 | --paginate \ |
@@ -71,40 +84,78 @@ jobs: |
71 | 84 | echo '```' |
72 | 85 | } |
73 | 86 |
|
74 | | - IS_ALLOWED=false |
75 | | - case "$AUTHOR_ASSOCIATION" in |
76 | | - COLLABORATOR|MEMBER|OWNER) |
77 | | - IS_ALLOWED=true |
78 | | - ;; |
79 | | - esac |
| 87 | + HAS_TRUE_POSITIVE_SIGNAL=false |
| 88 | + ALLOWLIST_CHECK="not needed (no restricted paths)" |
| 89 | + LABEL_ACTION="not needed (no restricted paths)" |
| 90 | + TRUE_POSITIVE_SIGNALS="(none)" |
| 91 | + PR_AUTHOR_CANONICAL=${PR_AUTHOR,,} |
80 | 92 |
|
81 | | - if [ "$TOUCHES_RESTRICTED_PATHS" = "true" ] && [ "$IS_ALLOWED" = "false" ]; then |
82 | | - echo "::error::This PR failed the author organization check. See the job summary for details." |
83 | | - { |
84 | | - echo "## PR Author Organization Check Failed" |
85 | | - echo "" |
86 | | - echo "- **Author**: $PR_AUTHOR" |
87 | | - echo "- **Author association**: $AUTHOR_ASSOCIATION" |
88 | | - echo "- **Restricted paths**: \`cuda_bindings/\`, \`cuda_python/\`" |
89 | | - echo "" |
90 | | - write_matching_restricted_paths |
91 | | - echo "" |
92 | | - echo "- **Policy**: See \`cuda_bindings/LICENSE\` and \`cuda_python/LICENSE\`. Only NVIDIA organization members may modify files under \`cuda_bindings/\` or \`cuda_python/\`." |
93 | | - echo "" |
94 | | - echo "Please update the PR at: $PR_URL" |
95 | | - } >> "$GITHUB_STEP_SUMMARY" |
96 | | - exit 1 |
| 93 | + if [ "$TOUCHES_RESTRICTED_PATHS" = "true" ]; then |
| 94 | + case "$AUTHOR_ASSOCIATION" in |
| 95 | + MEMBER|OWNER) |
| 96 | + HAS_TRUE_POSITIVE_SIGNAL=true |
| 97 | + ALLOWLIST_CHECK="skipped (author association is a true positive)" |
| 98 | + LABEL_ACTION="not needed (author association is a true positive)" |
| 99 | + TRUE_POSITIVE_SIGNALS="author_association:$AUTHOR_ASSOCIATION" |
| 100 | + ;; |
| 101 | + esac |
| 102 | +
|
| 103 | + if [ "$HAS_TRUE_POSITIVE_SIGNAL" = "false" ]; then |
| 104 | + if printf '%s\n' "$INTERNAL_AUTHOR_ALLOWLIST" | tr '[:upper:]' '[:lower:]' | grep -Fxq "$PR_AUTHOR_CANONICAL"; then |
| 105 | + HAS_TRUE_POSITIVE_SIGNAL=true |
| 106 | + ALLOWLIST_CHECK="matched ($PR_AUTHOR_CANONICAL)" |
| 107 | + LABEL_ACTION="not needed (workflow allowlist is a true positive)" |
| 108 | + TRUE_POSITIVE_SIGNALS="workflow_allowlist:$PR_AUTHOR_CANONICAL" |
| 109 | + else |
| 110 | + ALLOWLIST_CHECK="not matched ($PR_AUTHOR_CANONICAL)" |
| 111 | + fi |
| 112 | + fi |
| 113 | + fi |
| 114 | +
|
| 115 | + LABEL_ALREADY_PRESENT=false |
| 116 | + if jq -e --arg label "$REVIEW_LABEL" '.[] == $label' <<<"$EXISTING_LABELS" >/dev/null; then |
| 117 | + LABEL_ALREADY_PRESENT=true |
| 118 | + fi |
| 119 | +
|
| 120 | + if [ "$TOUCHES_RESTRICTED_PATHS" = "true" ] && [ "$HAS_TRUE_POSITIVE_SIGNAL" = "false" ]; then |
| 121 | + if [ "$LABEL_ALREADY_PRESENT" = "true" ]; then |
| 122 | + LABEL_ACTION="already present" |
| 123 | + elif ! gh issue edit "$PR_NUMBER" --repo "$REPO" --add-label "$REVIEW_LABEL"; then |
| 124 | + echo "::error::Failed to add the $REVIEW_LABEL label." |
| 125 | + { |
| 126 | + echo "## PR Author Organization Check Failed" |
| 127 | + echo "" |
| 128 | + echo "- **Error**: Failed to add the \`$REVIEW_LABEL\` label." |
| 129 | + echo "- **Author**: $PR_AUTHOR" |
| 130 | + echo "- **Author association**: $AUTHOR_ASSOCIATION" |
| 131 | + echo "- **Allowlist check**: $ALLOWLIST_CHECK" |
| 132 | + echo "" |
| 133 | + write_matching_restricted_paths |
| 134 | + echo "" |
| 135 | + echo "Please update the PR at: $PR_URL" |
| 136 | + } >> "$GITHUB_STEP_SUMMARY" |
| 137 | + exit 1 |
| 138 | + else |
| 139 | + LABEL_ACTION="added" |
| 140 | + fi |
97 | 141 | fi |
98 | 142 |
|
99 | 143 | { |
100 | | - echo "## PR Author Organization Check Passed" |
| 144 | + echo "## PR Author Organization Check Completed" |
101 | 145 | echo "" |
102 | 146 | echo "- **Author**: $PR_AUTHOR" |
103 | 147 | echo "- **Author association**: $AUTHOR_ASSOCIATION" |
104 | 148 | echo "- **Touches restricted paths**: $TOUCHES_RESTRICTED_PATHS" |
105 | 149 | echo "- **Restricted paths**: \`cuda_bindings/\`, \`cuda_python/\`" |
| 150 | + echo "- **Allowlist check**: $ALLOWLIST_CHECK" |
| 151 | + echo "- **True positive signals**: $TRUE_POSITIVE_SIGNALS" |
| 152 | + echo "- **Label action**: $LABEL_ACTION" |
106 | 153 | if [ "$TOUCHES_RESTRICTED_PATHS" = "true" ]; then |
107 | 154 | echo "" |
108 | 155 | write_matching_restricted_paths |
109 | 156 | fi |
| 157 | + if [ "$TOUCHES_RESTRICTED_PATHS" = "true" ] && [ "$HAS_TRUE_POSITIVE_SIGNAL" = "false" ]; then |
| 158 | + echo "" |
| 159 | + echo "- **Manual follow-up**: No true positive signal was found, so \`$REVIEW_LABEL\` is required." |
| 160 | + fi |
110 | 161 | } >> "$GITHUB_STEP_SUMMARY" |
0 commit comments