Skip to content

fix(dispatch)!: move the shim from pull_request_target to pull_request - #9230

Open
fullsend-ai-coder[bot] wants to merge 2 commits into
mainfrom
agent/9224-accept-pull-request-event
Open

fullsend-ai-coder[bot] wants to merge 2 commits into
mainfrom
agent/9224-accept-pull-request-event

Conversation

@fullsend-ai-coder

@fullsend-ai-coder fullsend-ai-coder Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

GitHub blocks pull_request_target by default in public repositories from December 2, 2026 (brownout again on November 16). This PR moves the fullsend shim to pull_request for same-repo PRs, following github/gh-aw, and keeps every dispatch path that still receives pull_request_target working until each repository upgrades.

Merge order: this PR implements ADR 0164 (#9227) and must merge after #9227. Do not enqueue before then.

Closes #9224. Part of #9221 (approach: #9221 (comment)).

What changes for users

Before After upgrading the shim
Same-repo PRs Auto review and retro on pull_request_target Auto review and retro on pull_request
Fork PRs (any author, including org members and maintainers working from a fork) Auto review and retro when the author passes authorization Skipped. Someone with triage+ access (or an OWNERS approver/reviewer) comments /fs-review; push branches to the repository to keep automatic review
Dependabot PRs Auto review Skipped (the run would get only Dependabot secrets); a maintainer comments /fs-review
PRs with a merge conflict Auto review No pull_request run until the conflict is resolved; /fs-review meanwhile
Repos not yet upgraded — Still routed, with a warning to re-run fullsend repos install

The shim update is a required upgrade, marked ! even though #9224 said no !. The dispatch inputs are unchanged and old shims keep working, but upgrading drops automatic fork and Dependabot review, and the release notes must say so: fullsend repos install rewrites the trigger and the pin in one commit. After the upgrade, GitHub PR events carry source.raw_type (and the harness event_type) pull_request instead of pull_request_target. Custom CEL triggers or harness filters that match on raw_type == "pull_request_target" must match both values, or use event.entity.kind / event.transition.kind. fullsend's built-in triggers do not read raw_type.

Docs: new section "Required upgrade: shim moves from pull_request_target to pull_request" and a troubleshooting entry in docs/guides/getting-started/repo-management.md.

Changes

Workflows (takeover commit)

  • internal/scaffold/fullsend-repo/templates/shim-per-repo.yaml and fullsend's own .github/workflows/fullsend.yaml: pull_request (same types as before) and the gh-aw same-repo guard github.event.pull_request.head.repo.id == github.repository_id.
  • reusable-dispatch.yml:
    • Routes pull_request exactly like pull_request_target (bash case and the CEL opt-in step).
    • Fork and Dependabot PRs never dispatch on pull_request: bash router, CEL opt-in step and both harness jobs. A pull_request run uses the PR's own copy of the shim, so a fork could delete the shim guard.
    • Base side for every checkout on pull_request. The 10 checkouts that pin a ref now use base.sha for pull_request too; on pull_request, github.sha is the PR merge commit. The 5 Checkout target repository steps that set no ref (triage, code, review, retro, harness) now check out the default branch on pull_request, which is what github.ref was on pull_request_target.
    • Vendored installs: a ./ reusable workflow on pull_request runs from the merge commit, so job.workflow_sha is the merge commit. Every job.workflow_sha read (checkouts, CLI build, version, cache keys) now uses base.sha when job.workflow_sha == github.sha. Remote @ref calls are unchanged.
    • ::warning:: when a caller still uses pull_request_target.
  • reusable-prioritize.yml: same checkout and job.workflow_sha rules.

Go (fs code agent commit)

  • IsLifecycleCloseAuthorized accepts a pull_request close as well as a pull_request_target close (retro role only). ghaevent.go already mapped both names; a new test pins raw_type.
  • Normative auth v1/v2 and normalized-event docs name both events.
  • Search of internal/ and cmd/ for non-test "pull_request_target" checks: only auth.go (fixed), ghaevent.go (already maps both), and comments in poll/events.go and cli/run.go.

Security notes

  • Same-repo authors run their own copy of the shim, which forwards the repository secrets. They have write access, so they could already push a workflow that reads those secrets; this matches gh-aw. ADR 0164 records it.
  • Vendored installs: the dispatch workflow is vendored in the repo, so its fork re-check runs from the PR's own copy. The only fork control left is GitHub not sending secrets to fork PR runs, which is the default; private repos must keep that setting off. This is in the docs.

Testing

  • New internal/scaffold/pr_trigger_test.go:
    • shim trigger and guard (template and fullsend's own copy);
    • TestEveryCheckoutHasTrustedRef: every actions/checkout step names a ref that is trusted on pull_request;
    • TestWorkflowSHAUsesAreTrusted: every job.workflow_sha read goes through the base-SHA rule;
    • harness jobs skip fork and Dependabot PRs;
    • Determine stage on same-repo, fork, deleted-head, Dependabot, human-push-to-Dependabot, bot-opened and pull_request_target events, including the warning.
  • Behaviour tests (the first run on this PR failed 4 scenarios that expected fork PR events to dispatch):
    • fork-bash-routing, fork-dispatch and the outsider fork scenario in actor-authorization now expect no dispatch from fork PR open, label or push, and dispatch from a maintainer comment on the fork PR (new step: "the posts ... on the fork pull request").
    • The outsider fork scenario now proves that the outsider's own comment is denied.
    • The GitHub Actions BT driver treats action_required runs (held for first-time-contributor approval) as runs that ran no job.
    • Fork scenarios are tagged @skip:gitlab (GitLab BT is not wired in CI).
  • cel_route_test.go: pull_request rows for the opt-in event gate and the bash/CEL agreement test; the opt-in if: assertion covers the fork guard.
  • Go route/auth/ghaevent parity rows for pull_request (bot commit).
  • Locally: go test ./internal/scaffold/ ./internal/cli/ ./internal/harnessdispatch/... ./internal/poll/ passes, except TestInstallFullsendCLIScript_ReleasePinDoesNotClearSettings, which fails on macOS arm64 only (unsupported architecture: arm64) and also fails on main. make lint passes.
  • Live validation in a scratch repo: see the validation comment on this PR.

Follow-ups (not in this PR)

🤖 Generated with Claude Code

@waynesun09

Copy link
Copy Markdown
Member

/fs-fix-stop

@github-actions github-actions Bot added the fullsend-no-fix Skip bot-triggered fix agent runs label Nov 9, 2026
@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown

Fix agent disabled for this PR. Remove the fullsend-no-fix label or use /fs-fix to re-engage.

@fullsend-ai-review

fullsend-ai-review Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ⚠️ Cancelled · Started 8:50 PM UTC · Completed 8:51 PM UTC

Commit: 68b588e · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5-5 · Effort: high · Cost: $0.16

This review was superseded by a newer commit. Check the current pull request HEAD's review status before merging.

@waynesun09 waynesun09 changed the title fix(dispatch): accept pull_request for the lifecycle-close exception fix(dispatch)!: move the shim from pull_request_target to pull_request Nov 9, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 8:53 PM UTC · Ended 9:07 PM UTC

Commit: 50dedcf · View workflow run →

This review was superseded by a newer commit. Check the current pull request HEAD's review status before merging.

@github-actions

github-actions Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Site preview

Preview: https://d82cddbc-site.fullsend-ai.workers.dev

Commit: 7acfcf19373daefac0a5af7a381d7e254e7ccb9b

@waynesun09
waynesun09 force-pushed the agent/9224-accept-pull-request-event branch from 50dedcf to 9f96820 Compare November 9, 2026 21:06
@fullsend-ai-review

Copy link
Copy Markdown

🤖 Finished Review · ⚠️ Cancelled · Started 8:53 PM UTC · Completed 9:06 PM UTC

Commit: 50dedcf · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5-5 · Effort: high · Cost: $1.73

This review was superseded by a newer commit. Check the current pull request HEAD's review status before merging.

@waynesun09
waynesun09 force-pushed the agent/9224-accept-pull-request-event branch from 9f96820 to dbeee1f Compare November 9, 2026 21:07
@fullsend-ai-review

fullsend-ai-review Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ⚠️ Cancelled · Started 9:09 PM UTC · Completed 9:19 PM UTC

Commit: dbeee1f · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5-5 · Effort: high · Cost: $2.63

This review was superseded by a newer commit. Check the current pull request HEAD's review status before merging.

@fullsend-ai-review

fullsend-ai-review Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:21 PM UTC · Completed 9:38 PM UTC

Commit: 4d9d683 · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5-5 · Effort: high · Cost: $3.28

@waynesun09

Copy link
Copy Markdown
Member

Live validation (scratch repo nonflux/tmp-9221-pr-shim)

The scratch repo has two shims, both pinned to this PR's head:

  • fullsend.yaml: the new template, on pull_request.
  • fullsend-old.yaml: the main template, on pull_request_target.

.fullsend/config.yaml disables every agent, so the route job decides and logs the stage, then the agent-check step stops before any agent job runs.

Case Event Result Run
Same-repo PR (new shim) pull_request Routed to stage: review, no warning 42701344439
Same-repo PR (old shim) pull_request_target Routed to stage: review + upgrade warning 42701345178
Same-repo PR closed pull_request / pull_request_target Routed to stage: retro on both 42697610876, 42697611997
Fork PR, shim guard intact pull_request dispatch job skipped by the shim guard 42699631298
Fork PR, fork deleted the shim guard pull_request Dispatch refuses: Fork pull request on pull_request: not routed 42701356574
Fork PR (old shim) pull_request_target Still routes, with the upgrade warning 42701352392
/fs-review on the fork PR issue_comment Routed to stage: review 42701659373
Route checkout on pull_request — git checkout ... 23dc2312 = PR base SHA (head was 987d2751) 42697126408
Local reusable workflow on pull_request — job.workflow_sha = github.sha = merge commit 9055d649 (base 7a362a45), which is why vendored reads now use base.sha 42699602779

Notes:

  • The first two rows are at the current head 4d9d68331. The other rows ran at the earlier heads 50dedcf9f / dbeee1ff9; routing has not changed since.
  • Not run live:
    • Dependabot skip: a scratch repo can't produce Dependabot PRs. It is covered by TestDetermineStagePullRequest.
    • Agent-job checkouts: those jobs need the mint and secrets. They are covered by TestEveryCheckoutHasTrustedRef and TestWorkflowSHAUsesAreTrusted.

@fullsend-ai-review fullsend-ai-review Bot added the risk/elevated PR risk: elevated label Nov 9, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Risk Assessment: elevated (3/5)

Details

Large blast radius across 32 files, modifications to 3 protected CI workflow files, high regression history and change coupling in dispatch workflows, and unflagged behavioral changes to dispatch routing elevate the composite risk to elevated.

Previous run

Risk Assessment: elevated (3/5)

Details

Elevated risk due to large blast radius modifying protected CI workflows across 28 files, high historical churn and regression frequency on dispatch files, and linked security issue context with no feature-flag rollback gate.

Previous run (2)

Risk Assessment: elevated (3/5)

Details

Elevated risk due to large blast radius modifying protected CI workflows across 23 files, high historical churn and regression frequency on dispatch files, and linked security issue context with no feature-flag rollback gate.

Previous run (3)

Risk Assessment: elevated (3/5)

Details

Elevated risk due to large blast radius modifying protected CI workflows across 23 files, high historical churn and regression frequency on dispatch files, and linked security issue context with no feature-flag rollback gate.

@fullsend-ai-review fullsend-ai-review Bot added the component/docs User-facing documentation label Nov 9, 2026
Per-repo shims are moving from pull_request_target to pull_request for
same-repo PRs (#9221). IsLifecycleCloseAuthorized only admitted a
pull_request_target close, so a retro on a pull_request close by a
read-only author, triager or role-less App bot would be denied by
`fullsend dispatch --route retro`. It now admits both event names;
every other condition (GitHub, change proposal, closed or merged,
harness role retro) is unchanged, and pull_request_target keeps
working for shims that have not upgraded.

ghaevent.go already maps both names through mapPREvent and keeps
source.raw_type as the exact event name. A search of internal/ and
cmd/ found no other non-test check of the literal.

Tests add pull_request rows next to the pull_request_target ones:
lifecycle-close auth, gha-event mapping parity, review and retro
route parity, retro routing and bot-role dispatch. The normative
authorization (v1, v2) and normalized-event docs name both events;
the v1 lifecycle-close anchor is kept.

Note: pre-commit could not fetch its remote hook repos (TLS error).
gofmt, go vet, lint-docs-links, lychee and lint-broken-symlinks ran
directly and passed; semgrep could not download its ruleset. Some
existing fetch/SSRF tests fail in this sandbox on main too (DNS
resolves to 198.18.0.0/15).

Closes #9224

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:56 PM UTC · Completed 11:07 PM UTC

Commit: e04dce8 · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5-5 · Effort: high · Cost: $2.76

fullsend-ai-review[bot]

This comment was marked as outdated.

@codecov

codecov Bot commented Nov 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@fullsend-ai-review

fullsend-ai-review Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 12:43 AM UTC · Ended 1:00 AM UTC

Commit: 082a890 · View workflow run →

This review was superseded by a newer commit. Check the current pull request HEAD's review status before merging.

…ll_request

GitHub blocks pull_request_target by default in public repositories from
2026-12-02 (#9221). Follow github/gh-aw: the shim triggers on pull_request
for same-repo PRs only (head.repo.id == github.repository_id); fork PRs are
reviewed when a maintainer comments /fs-review.

- shim template and fullsend's own fullsend.yaml: pull_request trigger plus
  the same-repo guard.
- reusable-dispatch.yml:
  - route pull_request like pull_request_target; warn when a caller still
    uses pull_request_target, which keeps working;
  - never route a fork or Dependabot PR on pull_request, in bash, CEL and
    the harness jobs. A pull_request run uses the PR's own copy of the shim,
    so a fork can drop the shim guard; Dependabot runs get only Dependabot
    secrets;
  - base side for every checkout on pull_request: base.sha where a ref is
    pinned, the default branch for the target-repo checkouts that used the
    event default (github.ref was the default branch on pull_request_target,
    it is the merge commit on pull_request);
  - job.workflow_sha reads use base.sha on pull_request when the reusable
    workflow lives in the caller repository (vendored installs), where
    job.workflow_sha would be the PR merge commit.
- reusable-prioritize.yml: same checkout and workflow_sha rules.
- scaffold tests: shim trigger and guard, every checkout has a trusted ref,
  every job.workflow_sha read is trusted, harness guard, routing of
  same-repo, fork, Dependabot and pull_request_target events.
- behaviour tests: fork PR scenarios now expect no dispatch from fork PR
  events (open, label, push) and dispatch from a maintainer comment on the
  fork PR (new step "the <actor> posts ... on the fork pull request");
  the outsider fork scenario checks the outsider's comment is denied; the
  GitHub Actions BT driver treats action_required runs (held for approval)
  as runs that ran no job; fork step trigger times are truncated.
- docs: required-upgrade section (merge-conflict PRs, forks, Dependabot,
  private-repo fork secrets setting), troubleshooting entry, user guides.

BREAKING CHANGE: after upgrading, fork and Dependabot PRs are no longer
reviewed or retro'd automatically; a maintainer comments /fs-review instead.

Assisted-by: Claude (fix), DeepSeek (review)
Signed-off-by: Wayne Sun <gsun@redhat.com>
@waynesun09
waynesun09 force-pushed the agent/9224-accept-pull-request-event branch from 082a890 to 7acfcf1 Compare November 10, 2026 01:00
@fullsend-ai-review

fullsend-ai-review Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:02 AM UTC · Completed 1:14 AM UTC

Commit: 7acfcf1 · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5-5 · Effort: high · Cost: $3.33

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review comment for full details.

@fullsend-ai-review fullsend-ai-review Bot added the component/e2e End-to-end tests label Nov 10, 2026
waynesun09 added a commit that referenced this pull request Nov 10, 2026
GitHub blocks pull_request_target by default on public repos from
2026-12-02, and a blocked run ends in startup_failure, which cannot be
re-run. This moves the four workflows that still use it, following the
gh-aw model (pull_request with a same-repo guard; fork PRs through a
maintainer slash command; writes in jobs that run no PR code):

- e2e.yml: pull_request for same-repo PRs, gated as before. Fork PRs get
  no secrets, so the gate and suites skip. A workflow_call with pr_number
  and head_sha runs the suites on a /ok-to-test-authorized sha, and each
  suite reports its job status as an output. The redaction script comes
  from the base sha, since pull_request's github.sha is the merge commit.
- e2e-ok-to-test.yml: issue_comment /ok-to-test instead of the
  ok-to-test label. The authorize job creates check runs named
  behaviour and playback on the authorized head sha and the report job
  completes them, so the required checks on main are met (the old
  workflow_call route reported "run / behaviour").
- vouch-check.yml: a 10-minute schedule running scripts/vouch-sweep.sh.
  First-time contributors' pull_request runs wait for approval, and fork
  runs get a read-only token, so a PR event cannot enforce the gate.
- notify-adr-slack.yml: push to main with the ADR paths filter, passing
  the pushed commits to scripts/notify-adr-merge.sh.

hack/workflow_triggers_test.py fails when any workflow's `on:` declares
pull_request_target; fullsend.yaml stays allowed until #9230 moves it.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
waynesun09 added a commit that referenced this pull request Nov 10, 2026
GitHub blocks pull_request_target by default on public repos from
2026-12-02, and a blocked run ends in startup_failure, which cannot be
re-run. This moves the four workflows that still use it, following the
gh-aw model (pull_request with a same-repo guard; fork PRs through a
maintainer slash command; writes in jobs that run no PR code):

- e2e.yml: pull_request for same-repo PRs, gated as before. Fork PRs get
  no secrets, so the gate and suites skip. A workflow_call with pr_number
  and head_sha runs the suites on a /ok-to-test-authorized sha, and each
  suite reports its job status as an output. On that path the relevance
  check diffs the authorized sha, not the live PR head. The redaction
  script comes from the base sha, since pull_request's github.sha is the
  merge commit (ci-workflows.md updated to match).
- e2e-ok-to-test.yml: issue_comment /ok-to-test on an open PR instead
  of the ok-to-test label. The authorize job creates check runs named
  behaviour and playback on the authorized head sha and the report job
  completes them, so the required checks on main are met (the old
  workflow_call route reported "run / behaviour").
- vouch-check.yml: a 10-minute schedule running scripts/vouch-sweep.sh.
  First-time contributors' pull_request runs wait for approval, and fork
  runs get a read-only token, so a PR event cannot enforce the gate.
- notify-adr-slack.yml: push to main with the ADR paths filter, passing
  the pushed commits to scripts/notify-adr-merge.sh.

hack/workflow_triggers_test.py fails when any workflow's `on:` declares
pull_request_target; fullsend.yaml stays allowed until #9230 moves it.

Assisted-by: Claude (fix), Claude (review), DeepSeek (review)
Signed-off-by: Wayne Sun <gsun@redhat.com>

This branch was successfully deployed

1 active and 1 inactive deployments
site-preview — 7acfcf19 Deployed Nov 10, 2026 by github-actions[bot]
dev — 7acfcf19 Deployed Nov 10, 2026 by waynesun09 via behaviour #19430
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/ci CI pipelines and checks component/dispatch Workflow dispatch and triggers component/docs User-facing documentation component/e2e End-to-end tests component/install CLI install and app setup fullsend-no-fix Skip bot-triggered fix agent runs ready-for-review Triggers review agent dispatch risk/elevated PR risk: elevated

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dispatch: accept pull_request wherever pull_request_target is accepted (Go part of #9221)

1 participant