Skip to content

Commit 0dff619

Browse files
Gate CI on sync PRs to require committer authorship or approval (#462)
Sync PRs from non-committers could run CI on untrusted code. This adds a ci-gate job that checks the original commit author's repo permissions and blocks CI unless they have write access or the `ci-approved` label is added manually. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5491fa7 commit 0dff619

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

.github/workflows/main.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ on:
1515
- synchronize
1616
- reopened
1717
- ready_for_review
18+
- labeled
1819
branches:
1920
- main
2021
- ootb
@@ -33,7 +34,60 @@ defaults:
3334
shell: bash
3435

3536
jobs:
37+
ci-gate:
38+
runs-on: ubuntu-latest
39+
outputs:
40+
allowed: ${{ steps.check.outputs.allowed }}
41+
steps:
42+
- name: Check CI authorization for sync PRs
43+
id: check
44+
env:
45+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
46+
run: |
47+
# Always allow non-PR events (push, workflow_dispatch)
48+
if [[ "${{ github.event_name }}" != "pull_request" ]]; then
49+
echo "allowed=true" >> "$GITHUB_OUTPUT"
50+
exit 0
51+
fi
52+
53+
# Always allow non-sync PRs
54+
IS_SYNC="${{ contains(github.event.pull_request.labels.*.name, 'sync') }}"
55+
if [[ "$IS_SYNC" != "true" ]]; then
56+
echo "allowed=true" >> "$GITHUB_OUTPUT"
57+
exit 0
58+
fi
59+
60+
# Allow sync PRs with ci-approved label
61+
IS_APPROVED="${{ contains(github.event.pull_request.labels.*.name, 'ci-approved') }}"
62+
if [[ "$IS_APPROVED" == "true" ]]; then
63+
echo "CI approved via label"
64+
echo "allowed=true" >> "$GITHUB_OUTPUT"
65+
exit 0
66+
fi
67+
68+
# Check if the original commit author has write access
69+
AUTHOR=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/commits --jq '.[0].author.login')
70+
echo "Commit author: $AUTHOR"
71+
72+
if [[ -z "$AUTHOR" || "$AUTHOR" == "null" ]]; then
73+
echo "Could not determine commit author, blocking CI. Add 'ci-approved' label to override."
74+
echo "allowed=false" >> "$GITHUB_OUTPUT"
75+
exit 0
76+
fi
77+
78+
PERM=$(gh api repos/${{ github.repository }}/collaborators/$AUTHOR/permission --jq '.permission')
79+
echo "Permission level: $PERM"
80+
81+
if [[ "$PERM" == "admin" || "$PERM" == "write" || "$PERM" == "maintain" ]]; then
82+
echo "allowed=true" >> "$GITHUB_OUTPUT"
83+
else
84+
echo "Author $AUTHOR does not have write access. Add 'ci-approved' label to override."
85+
echo "allowed=false" >> "$GITHUB_OUTPUT"
86+
fi
87+
3688
script-tests:
89+
needs: ci-gate
90+
if: needs.ci-gate.outputs.allowed == 'true'
3791
runs-on: ubuntu-latest
3892
name: "Script unit tests"
3993
steps:
@@ -44,6 +98,8 @@ jobs:
4498
run: ./run-benchmarks-tests.sh
4599

46100
jvm-build-test:
101+
needs: ci-gate
102+
if: needs.ci-gate.outputs.allowed == 'true'
47103
runs-on: ubuntu-latest
48104
strategy:
49105
fail-fast: false

0 commit comments

Comments
 (0)