|
1 | | -# Separate job: GitHub sends job-level secrets to the runner as soon as that job starts. |
| 1 | +# Gate before e2e jobs that use repository secrets (separate job so secrets are not sent if skipped). |
| 2 | +# |
| 3 | +# Uses the same collaborator permission API GitHub uses for push/merge access on |
| 4 | +# this repository (org base permissions, teams, and direct grants). |
2 | 5 | name: Authorize E2E secrets access |
3 | 6 |
|
4 | 7 | on: |
5 | 8 | workflow_call: |
6 | 9 | outputs: |
7 | 10 | authorized: |
8 | | - description: true if e2e may run with repository secrets |
9 | 11 | value: ${{ jobs.authorize.outputs.authorized }} |
10 | 12 |
|
11 | 13 | jobs: |
12 | 14 | authorize: |
13 | | - name: Check repository access |
| 15 | + name: Check repository owner or member |
14 | 16 | runs-on: ubuntu-latest |
15 | | - timeout-minutes: 2 |
| 17 | + timeout-minutes: 1 |
16 | 18 | if: github.event.action != 'labeled' || github.event.label.name == 'ok-to-test' |
17 | | - permissions: |
18 | | - contents: read |
19 | | - members: read |
| 19 | + # Do not set permissions: contents: read — it blocks reading collaborator permissions. |
20 | 20 | outputs: |
21 | 21 | authorized: ${{ steps.check.outputs.authorized }} |
22 | 22 | steps: |
23 | | - - name: Allow repo members, or ok-to-test from an owner |
| 23 | + - name: Allow repo owners and members, or ok-to-test from an owner |
24 | 24 | id: check |
25 | 25 | env: |
26 | 26 | GH_TOKEN: ${{ github.token }} |
27 | 27 | EVENT_NAME: ${{ github.event_name }} |
28 | 28 | EVENT_ACTION: ${{ github.event.action }} |
| 29 | + IS_FORK: ${{ github.event.repository.fork }} |
| 30 | + # PR author for merge-rights check (not github.actor — see dependabot hardening). |
29 | 31 | USER: ${{ github.event.pull_request.user.login || github.actor }} |
30 | 32 | ACTOR: ${{ github.actor }} |
| 33 | + REPO_OWNER: ${{ github.repository_owner }} |
31 | 34 | REPOSITORY: ${{ github.repository }} |
32 | 35 | run: | |
33 | 36 | set -euo pipefail |
34 | | -
|
35 | 37 | allow() { echo "$1"; echo "authorized=true" >> "$GITHUB_OUTPUT"; exit 0; } |
36 | 38 | deny() { echo "::warning::$1"; echo "authorized=false" >> "$GITHUB_OUTPUT"; exit 0; } |
37 | 39 |
|
38 | | - encode() { jq -nr --arg u "$1" '$u|@uri'; } |
39 | | -
|
40 | | - # True if the user is on this repository or an org owner/member. |
41 | | - is_repo_user_or_member() { |
42 | | - local encoded org role |
43 | | - encoded=$(encode "$1") |
44 | | - if gh api --silent "repos/${REPOSITORY}/collaborators/${encoded}"; then |
45 | | - return 0 |
46 | | - fi |
47 | | - org="${REPOSITORY%%/*}" |
48 | | - role=$(gh api "orgs/${org}/memberships/${encoded}" \ |
49 | | - --jq 'if .state == "active" then .role else "none" end' 2>/dev/null || echo none) |
50 | | - [ "$role" = "admin" ] || [ "$role" = "member" ] |
51 | | - } |
52 | | -
|
53 | | - repo_permission() { |
54 | | - gh api "repos/${REPOSITORY}/collaborators/$(encode "$1")/permission" --jq .permission 2>/dev/null || echo none |
| 40 | + permission_of() { |
| 41 | + gh api "repos/${REPOSITORY}/collaborators/$(jq -nr --arg u "$1" '$u|@uri')/permission" \ |
| 42 | + --jq .permission 2>/dev/null || echo none |
55 | 43 | } |
56 | 44 |
|
57 | 45 | [ "$EVENT_NAME" = "schedule" ] && allow "Scheduled run." |
58 | 46 |
|
59 | | - echo "executor=$USER" |
60 | | - if is_repo_user_or_member "$USER"; then |
61 | | - allow "$USER is a user or member of ${REPOSITORY}." |
62 | | - fi |
| 47 | + echo "user=${USER} actor=${ACTOR} event=${EVENT_NAME}/${EVENT_ACTION:-none} fork=${IS_FORK}" |
| 48 | +
|
| 49 | + # Push to upstream: only users with push (merge) rights can push here. |
| 50 | + [ "$EVENT_NAME" = "push" ] && [ "$IS_FORK" != "true" ] && allow "Push to upstream repository." |
| 51 | +
|
| 52 | + # Push to your own fork. |
| 53 | + [ "$EVENT_NAME" = "push" ] && [ "$ACTOR" = "$REPO_OWNER" ] && allow "Push by fork owner." |
| 54 | +
|
| 55 | + USER_PERM=$(permission_of "$USER") |
| 56 | + echo "user_permission=${USER_PERM}" |
| 57 | + case "$USER_PERM" in |
| 58 | + admin|maintain|write|triage|read) |
| 59 | + allow "${USER} has repository access (${USER_PERM}, same source as merge rights)." |
| 60 | + ;; |
| 61 | + esac |
63 | 62 |
|
64 | | - [ "$EVENT_ACTION" = "labeled" ] || deny "$USER is not a user or member of ${REPOSITORY}." |
| 63 | + # Outsider PR: repository owner added ok-to-test on this run. |
| 64 | + [ "$EVENT_ACTION" = "labeled" ] || deny "${USER} has no repository access." |
65 | 65 |
|
66 | | - LABELER_PERM=$(repo_permission "$ACTOR") |
67 | | - echo "ok-to-test labeler=$ACTOR permission=$LABELER_PERM" |
68 | | - [ "$LABELER_PERM" = "admin" ] && allow "Owner $ACTOR added ok-to-test." |
| 66 | + LABELER_PERM=$(permission_of "$ACTOR") |
| 67 | + echo "ok-to-test labeler=${ACTOR} permission=${LABELER_PERM}" |
| 68 | + [ "$LABELER_PERM" = "admin" ] && allow "Repository owner ${ACTOR} added ok-to-test." |
69 | 69 |
|
70 | | - deny "ok-to-test must be added by a repository owner." |
| 70 | + deny "ok-to-test must be added by a repository owner (admin)." |
0 commit comments