Problem
main is the release branch. Per AGENTS.md, the only PR that may target it is a milestone's merge PR, which is a pure merge of v2/main: its head is a commit already on v2/main, with no commits of its own. Nothing enforces that. The rulesets on main require a PR, a code-owner approval and Copilot review, and block deletion and force-pushes, but GitHub rulesets cannot restrict a PR's source branch. All three merge methods are allowed too, although the release merge must never be squashed.
So a PR from any branch can be merged into main after one approval. Recent history shows it happening: #4939 and #5081 merged commits of their own into main, and before v2 ordinary fix branches went straight there.
Proposal
- A guard workflow on
pull_request_target into main that fails unless the PR's head commit is an ancestor of (or equal to) origin/v2/main. The check is on the commit, not the branch name, because the release skill opens the merge PR from v2/chore/<N>-release-<milestone>, a branch pushed from origin/v2/main. pull_request_target runs main's copy of the workflow, so a PR cannot edit the guard into passing. It checks out only main and fetches the PR head as data; no PR code runs.
- Bootstrap: land it on
v2/main, then bring the same commit to main in a one-off PR (while the restriction does not yet exist), so the guard is live on main before the next milestone merge.
- Rulesets: once the workflow is on
main, make its check required for main, and restrict main's allowed merge methods to merge commits only.
Expected
A PR into main whose head carries any commit that is not on v2/main shows a failing required check and cannot merge; a release merge PR passes. Squash and rebase are unavailable on main.
Problem
mainis the release branch. PerAGENTS.md, the only PR that may target it is a milestone's merge PR, which is a pure merge ofv2/main: its head is a commit already onv2/main, with no commits of its own. Nothing enforces that. The rulesets onmainrequire a PR, a code-owner approval and Copilot review, and block deletion and force-pushes, but GitHub rulesets cannot restrict a PR's source branch. All three merge methods are allowed too, although the release merge must never be squashed.So a PR from any branch can be merged into
mainafter one approval. Recent history shows it happening: #4939 and #5081 merged commits of their own intomain, and before v2 ordinary fix branches went straight there.Proposal
pull_request_targetintomainthat fails unless the PR's head commit is an ancestor of (or equal to)origin/v2/main. The check is on the commit, not the branch name, because thereleaseskill opens the merge PR fromv2/chore/<N>-release-<milestone>, a branch pushed fromorigin/v2/main.pull_request_targetrunsmain's copy of the workflow, so a PR cannot edit the guard into passing. It checks out onlymainand fetches the PR head as data; no PR code runs.v2/main, then bring the same commit tomainin a one-off PR (while the restriction does not yet exist), so the guard is live onmainbefore the next milestone merge.main, make its check required formain, and restrictmain's allowed merge methods to merge commits only.Expected
A PR into
mainwhose head carries any commit that is not onv2/mainshows a failing required check and cannot merge; a release merge PR passes. Squash and rebase are unavailable onmain.