diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 2c005c0c5..1b505cbb2 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -50,19 +50,22 @@ jobs: env: EVENT_NAME: ${{ github.event_name }} AUTHORIZED_USERS: ${{ secrets.AUTHORIZED_USERS }} - GITHUB_ACTOR: ${{ github.actor }} + # Gate on the PR AUTHOR (whose code this is), NOT github.actor (who triggered the run). + # On pull_request_target a trusted actor (e.g. a maintainer pushing to a fork PR) triggering + # a run must NOT cause an untrusted author's fork code to execute with our AWS role/secrets. + PR_AUTHOR: ${{ github.event.pull_request.user.login }} run: | if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then echo "✅ Manual workflow dispatch — authorized" echo "is_authorized=true" >> "$GITHUB_OUTPUT" exit 0 fi - if [[ ",$AUTHORIZED_USERS," == *",${GITHUB_ACTOR},"* ]]; then - echo "✅ User ${GITHUB_ACTOR} is authorized" + if [[ ",$AUTHORIZED_USERS," == *",${PR_AUTHOR},"* ]]; then + echo "✅ PR author ${PR_AUTHOR} is authorized" echo "is_authorized=true" >> "$GITHUB_OUTPUT" else - echo "⏭️ User ${GITHUB_ACTOR} is not in AUTHORIZED_USERS — skipping E2E tests." - echo "ℹ️ External contributors: ask a maintainer to run the E2E tests manually via workflow_dispatch." + echo "⏭️ PR author ${PR_AUTHOR} is not in AUTHORIZED_USERS — skipping E2E tests." + echo "ℹ️ External contributors: a maintainer can run the E2E tests via workflow_dispatch after reviewing the code." echo "is_authorized=false" >> "$GITHUB_OUTPUT" fi @@ -85,6 +88,11 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + # Safe because the `authorize` job above gates on the PR AUTHOR being in AUTHORIZED_USERS: + # external authors skip at the gate, so only trusted authors' code is ever checked out here. + # Needed because authorized maintainers routinely open PRs from their own forks, and + # checkout@v7 otherwise refuses fork-PR checkout in pull_request_target. + allow-unsafe-pr-checkout: true - uses: actions/setup-node@v6 with: node-version: '20.x' diff --git a/.github/workflows/pr-security-review.yml b/.github/workflows/pr-security-review.yml index bac101a83..4b0e8a3ea 100644 --- a/.github/workflows/pr-security-review.yml +++ b/.github/workflows/pr-security-review.yml @@ -160,6 +160,12 @@ jobs: with: ref: ${{ steps.pr.outputs.head_sha }} fetch-depth: 0 + # Safe to opt in here: the `authorize` job already gates on the PR AUTHOR having write/admin + # (getCollaboratorPermissionLevel), and this job only READS the code (compute diff, build + # prompt, run the review) — it never executes fork code (no npm ci / npm scripts). checkout@v7 + # otherwise refuses fork-PR checkout in pull_request_target, which would break the review on + # an authorized author's fork PR. Reviewing the PR head is the whole point of this job. + allow-unsafe-pr-checkout: true - name: Compute diff id: diff diff --git a/.github/workflows/pr-tarball.yml b/.github/workflows/pr-tarball.yml index 5221b7884..b62de6638 100644 --- a/.github/workflows/pr-tarball.yml +++ b/.github/workflows/pr-tarball.yml @@ -17,13 +17,16 @@ jobs: id: check env: AUTHORIZED_USERS: ${{ secrets.AUTHORIZED_USERS }} - GITHUB_ACTOR: ${{ github.actor }} + # Gate on the PR AUTHOR (whose code this npm build runs), NOT github.actor (who triggered the + # run). Otherwise a trusted actor pushing to a fork PR would run untrusted fork npm scripts + # with the contents:write GITHUB_TOKEN + App token in this job. + PR_AUTHOR: ${{ github.event.pull_request.user.login }} run: | - if [[ ",$AUTHORIZED_USERS," == *",${GITHUB_ACTOR},"* ]]; then - echo "✅ User ${GITHUB_ACTOR} is authorized" + if [[ ",$AUTHORIZED_USERS," == *",${PR_AUTHOR},"* ]]; then + echo "✅ PR author ${PR_AUTHOR} is authorized" echo "is_authorized=true" >> "$GITHUB_OUTPUT" else - echo "⏭️ User ${GITHUB_ACTOR} is not in AUTHORIZED_USERS — skipping." + echo "⏭️ PR author ${PR_AUTHOR} is not in AUTHORIZED_USERS — skipping." echo "is_authorized=false" >> "$GITHUB_OUTPUT" fi @@ -35,6 +38,11 @@ jobs: - uses: actions/checkout@v7 with: ref: ${{ github.event.pull_request.head.sha }} + # Safe because the `authorize` job above gates on the PR AUTHOR being in AUTHORIZED_USERS: + # external authors skip at the gate, so only trusted authors' code is ever checked out here. + # Needed because authorized maintainers routinely open PRs from their own forks, and + # checkout@v7 otherwise refuses fork-PR checkout in pull_request_target. + allow-unsafe-pr-checkout: true - uses: actions/setup-node@v6 with: node-version: '20.x'