summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuriy Andamasov <yuriy@vyos.io>2026-05-15 00:25:44 +0300
committerYuriy Andamasov <yuriy@vyos.io>2026-05-15 00:25:44 +0300
commit9b6a166382bdce525c1dcfb077c7a152267ee69e (patch)
treee1512c4c3b41dbf64c178b74347a79ff6bb1833d
parentab25a1a9412c3e0199f5d62f72badceb40ce70fc (diff)
downloadmergify-9b6a166382bdce525c1dcfb077c7a152267ee69e.tar.gz
mergify-9b6a166382bdce525c1dcfb077c7a152267ee69e.zip
T8782: Block merge while backport-conflict label is present via merge_protections
Add a merge_protections rule requiring `label != backport-conflict` for merge. The backport action above auto-applies the label on cherry-pick conflicts, so this closes the loop: the conflicted PR exists (workspace preserved), is labeled and assigned, AND cannot be merged until the operator pushes a resolution and removes the label manually. Per Mergify docs, merge_protections from `extends:` merges across parent and child with same-name override semantics; consumer repos can opt out by defining a same-named rule locally with weaker conditions. `dequeue` is not exposed as a YAML action under pull_request_rules — only as a user-facing slash command and a key under commands_restrictions. merge_protections is the declarative equivalent. Manual `@Mergifyio dequeue` remains available to Maintainers via commands_restrictions. Active ejection of an already-queued PR when the label arrives vs. holding the PR indefinitely in queue is not explicitly documented by Mergify; the comment marks this as TBD on first real backport conflict.
-rw-r--r--.mergify.yml57
1 files changed, 49 insertions, 8 deletions
diff --git a/.mergify.yml b/.mergify.yml
index 01b818e..74e9439 100644
--- a/.mergify.yml
+++ b/.mergify.yml
@@ -39,14 +39,22 @@ defaults:
# accountability loop — they wrote the change, they know what the
# backport should look like.
#
- # Operational caveat — the label DOES NOT block merge by itself. The
- # 2026-05-12 incident below shipped because branch protection did not
- # require a check that catches conflict markers. Repos consuming
- # `extends: mergify` need either (a) a required CI status that fails
- # on `<<<<<<<` in tracked files, or (b) a branch-protection ruleset
- # that forbids merging while `backport-conflict` is present. Both
- # belong to fleet-wide governance, tracked under T8850 (Cat 1 branch
- # governance rulesets) rather than this central-config repo.
+ # Merge is blocked while the label is present — see the
+ # `merge_protections` block at the bottom of this file. Mergify
+ # documents that merge_protections are "safe to edit live;
+ # re-evaluations happen automatically", so a PR that gains the
+ # label after queueing will fail the merge check at the next
+ # evaluation. Active ejection of a queued PR vs. holding it
+ # indefinitely is not explicitly documented; manual fallback is
+ # `@Mergifyio dequeue` (allowed to Maintainers per
+ # commands_restrictions below).
+ #
+ # This does NOT replace branch protection. A determined operator can
+ # still bypass via the GitHub "Merge" button if branch protection
+ # doesn't require Mergify checks. The defense-in-depth piece (required
+ # CI status that fails on `<<<<<<<` in tracked files, or branch-
+ # protection ruleset on the label) is tracked under T8850 (Cat 1
+ # branch governance rulesets).
#
# Incident history (2026-05-12):
# vyos/vyos-documentation#1994 was backported via `@Mergifyio backport
@@ -158,3 +166,36 @@ commands_restrictions:
requeue: *allowed
squash: *allowed
update: *allowed
+
+merge_protections:
+ # Block merge while the backport-conflict label is set on a PR. The
+ # `backport` action above adds this label whenever a backport cherry-pick
+ # produces conflict markers; this rule ensures the conflicted PR cannot
+ # proceed to merge until a human removes the label (which they should
+ # only do after pushing a resolution commit that overwrites the markers).
+ #
+ # Why merge_protections and not a pull_request_rules `dequeue` action:
+ # Mergify exposes `dequeue` as a user-facing slash command and as a key
+ # under `commands_restrictions`, but NOT as a YAML action in
+ # pull_request_rules. `merge_protections` is the declarative equivalent —
+ # a PR with the label fails the success_conditions and is held back from
+ # merge; manual `@Mergifyio dequeue` remains available as the escape
+ # hatch (allowed to Maintainers per commands_restrictions above).
+ #
+ # Inheritance: per Mergify docs, merge_protections from `extends:`
+ # merges across parent and child, with same-named rules in the child
+ # overriding the parent. Consumer repos can disable this rule by
+ # defining a same-named rule locally with weaker conditions.
+ #
+ # Caveat: merge_protections only governs Mergify-driven merges. A
+ # determined operator can still click GitHub's merge button if branch
+ # protection doesn't require Mergify checks. Defense-in-depth (required
+ # CI status, branch-protection ruleset on the label) is tracked under
+ # T8850 Cat 1 branch governance.
+ - name: backport-conflict label must be absent to merge
+ description: >
+ Block merge while the backport-conflict label is present. The label
+ is auto-applied by the backport action on cherry-pick conflicts and
+ must be manually removed after the conflict is resolved in the PR.
+ success_conditions:
+ - label != backport-conflict