Skip to content

Guard main: accept merges only from v2/main, and only as merge commits #5119

Description

@cliffhall

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

  1. 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.
  2. 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.
  3. 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.

Activity

  1. added this to the v2.0.0 milestone on Oct 11, 2026
  2. added
    choreMaintenance: deps, build tooling, CI, cleanup — no user-facing behavior change
    on Oct 11, 2026
  3. self-assigned this
    on Oct 11, 2026
  4. added a commit that references this issue on Oct 11, 2026
  5. cliffhall commented on Oct 11, 2026

    @cliffhall
    MemberAuthor

    Shipped: the guard reached main through #5122 (bootstrap) and v2/main through #5120. Ruleset 24866866 requires Source is v2/main (GitHub Actions app) and allows only merge commits, with no bypass actors. Live probes #5123 (pass) and #5124 (fail) behaved as expected. Follow-up: #5121.

    Note: this issue auto-closed early, when #5122 merged into main, before #5120 had merged. #5122's body explained why it used Part of, and that explanation contained the phrase "close #5119", which GitHub parses as a closing keyword on the default branch. Its card is now Done, which is correct now that #5120 has merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

choreMaintenance: deps, build tooling, CI, cleanup — no user-facing behavior changev2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions