ci: gate fork-PR E2E/tarball on PR author (fix pwn-request + checkout@v7 fork block)#1716
Conversation
#1710 bumped actions/checkout v6 -> v7. v7 refuses to check out fork-PR code in a `pull_request_target` workflow by default ("pwn request" protection), failing at the checkout step: Refusing to check out fork pull request code from a 'pull_request_target' workflow. ... set 'allow-unsafe-pr-checkout: true' This broke the `e2e` and `pr-tarball` jobs for every fork PR (they run on pull_request_target and check out `github.event.pull_request.head.sha`). Both jobs already gate on the `authorize` job (actor must be in AUTHORIZED_USERS) before they ever run, so the fork checkout only happens for pre-authorized users — that gate is the real pwn-request mitigation, and it's exactly the protection v7's default is conservatively enforcing. Opt back in with `allow-unsafe-pr-checkout: true` so authorized fork PRs get E2E/tarball coverage again (restores the pre-#1710 behavior while keeping checkout on v7).
Package TarballHow to installgh release download pr-1716-tarball --repo aws/agentcore-cli --pattern "*.tgz" --dir /tmp/pr-tarball
npm install -g /tmp/pr-tarball/aws-agentcore-0.23.0.tgz |
|
Claude Security Review: no high-confidence findings. (run) |
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
Fix itself looks correct — allow-unsafe-pr-checkout: true is the documented v7 opt-in for this exact scenario, the two touched jobs are both properly gated by the authorize job, and the comment explaining the reasoning is great.
However, this appears to miss a third workflow with the same pattern: .github/workflows/pr-security-review.yml. See lines 159–162 on the PR branch:
- name: Checkout PR head
uses: actions/checkout@v7
with:
ref: ${{ steps.pr.outputs.head_sha }}
fetch-depth: 0That's pull_request_target + actions/checkout@v7 + explicit fork PR head SHA — the same combination that triggers v7's "Refusing to check out fork pull request code" error, and it's behind the same style of authorize gate as the two workflows fixed here. Authorized fork PRs will fail the security review checkout for the same reason e2e and pr-tarball do.
For completeness, I also looked at the other pull_request_target workflows and I think these are fine as-is:
codeql.yml— checkout has no explicitref, so it uses the default merge-ref (base), not fork code. v7 doesn't refuse.pr-ai-review.yml— same (no explicitref).pr-size.yml,pr-title.yml— no checkout step.
Requested change: add allow-unsafe-pr-checkout: true (with a similar explanatory comment) to the Checkout PR head step in pr-security-review.yml so the security review job doesn't silently break on the next authorized fork PR.
Coverage Report
|
…n-request) Supersedes the earlier `allow-unsafe-pr-checkout: true` approach, which was unsafe: the `authorize` gate checked `github.actor` (who triggered the run), not the PR author (whose code runs). A trusted actor pushing to a fork PR (e.g. a maintainer editing an external contributor's PR) would pass the gate and then execute the fork's code with the AWS role / contents:write token / App token — a classic pull_request_target "pwn request". Fix: - Gate on `github.event.pull_request.user.login` (the PR author) against AUTHORIZED_USERS. External-author fork PRs now SKIP cleanly (no failure, no code execution with secrets) instead of running or hard-failing at checkout. - Drop `allow-unsafe-pr-checkout: true`; checkout@v7's fork-checkout refusal stays in force for any fork PR that reaches the step. Authorized authors' on-repo PRs run normally; fork PRs get E2E via manual workflow_dispatch after review (as the workflow already documents). Curated AUTHORIZED_USERS is intentionally kept (rather than any-write-collaborator) for these secret-bearing jobs.
|
Claude Security Review: no high-confidence findings. (run) |
…-only)
Completes the checkout@v7 fork-PR fix: pr-security-review.yml has the same
pull_request_target + checkout@v7 + fork-head pattern (its ref is computed in a
step, so it was easy to miss). Unlike e2e/pr-tarball, this job:
- is ALREADY gated on the PR author's write/admin permission
(getCollaboratorPermissionLevel), so external forks already skip it, and
- only READS the code (compute diff, build prompt, run the review) — it never
executes fork code (no npm ci / npm scripts).
So `allow-unsafe-pr-checkout: true` is the correct, low-risk fix here (reviewing the
PR head is the job's whole purpose), whereas for the secret-executing e2e/pr-tarball
jobs we instead moved to author-based gating and dropped the flag.
|
Claude Security Review: no high-confidence findings. (run) |
notgitika
left a comment
There was a problem hiding this comment.
Since we usually open PRs from forks (authorized users included), e2e and pr-tarball will now hard-fail at checkout on the normal path. authorize passes on the PR author, then checkout@v7 refuses the fork head with no allow-unsafe-pr-checkout. So authorized fork PRs go red and need a manual workflow_dispatch.
The gate is already on the PR author being in AUTHORIZED_USERS, so the pwn-request is closed adding allow-unsafe-pr-checkout: true here too (like you did for security review) would let authorized fork PRs run normally while external authors still skip at the gate.
…ated) Addresses review feedback: authorized maintainers routinely open PRs from their own forks, so gating on the author WITHOUT allow-unsafe made those normal fork PRs hard-fail at checkout@v7. Now that the authorize gate keys on the PR author (github.event.pull_request.user.login in AUTHORIZED_USERS), re-adding allow-unsafe-pr-checkout is safe: external authors skip at the gate, so only trusted authors' code is ever checked out — and their fork PRs run normally again. (The earlier scanner flag was about allow-unsafe combined with the ACTOR-based gate, which this no longer uses.) All three pull_request_target workflows now use the same author-gate + allow-unsafe combination.
|
Claude Security Review: no high-confidence findings. (run) |
notgitika
left a comment
There was a problem hiding this comment.
Thanks for addressing the comment and making this more secure!
Description
e2e,pr-tarball, andpr-security-reviewfail at checkout for fork PRs. Root cause: #1710 bumpedactions/checkoutv6→v7, and v7 refuses to check out fork-PR code in apull_request_targetworkflow by default (the "pwn request" protection). Since PRs here (including from authorized maintainers) are routinely opened from forks, this hard-fails those jobs at checkout.Fixing it also surfaced a pre-existing flaw in
e2e/pr-tarball: theirauthorizegate keyed ongithub.actor(who triggered the run), not the PR author (whose code runs). Onpull_request_target, a trusted actor pushing to a fork PR would pass the gate and run untrusted fork code with the AWS role / write token — a real pwn-request.Fix
All three
pull_request_targetworkflows now use the same, safe combination — gate on the PR author, then opt into the fork checkout:github.event.pull_request.user.login(the PR author):e2e/pr-tarball: author must be inAUTHORIZED_USERS(curated list — appropriate since these deploy real AWS resources / publish releases). (This replaces the previousgithub.actorgate — the actual pwn-request fix.)pr-security-review: already gated on author write/admin viagetCollaboratorPermissionLevel(unchanged).allow-unsafe-pr-checkout: trueon the checkout step. This is safe because of (1): external/untrusted authors skip at the gate, so only trusted authors' code is ever checked out — and their fork PRs (the normal path here) run again instead of hard-failing.The key correctness point:
allow-unsafe-pr-checkoutis only dangerous with an actor-based gate (trusted actor + untrusted author's code). With an author-based gate it's safe, since the code's author is the thing being trusted.Other
pull_request_targetworkflows were checked and are fine (codeql.yml,pr-ai-review.ymluse the default merge-ref, not fork head;pr-size.yml/pr-title.ymlhave no checkout).Type of Change
Related
Regression surfaced by #1710 (checkout v7 bump).
Checklist