From 54db38be0896dc6c623db5051cbb0ce5e4afb72c Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 18 Oct 2026 18:10:29 +0200 Subject: [PATCH] gitea: a repository the module makes refuses an administrator's merge past its checks (issue 1141) narrowed never set block_admin_merge_override, so novox/mesh-delivery's main let an administrator merge past mesh/merge-gate and mesh/repo-check, unlike every other repository's main since 2026-10-07. narrowed sets it and isRight requires it, so the module's next start puts mesh-delivery right. --- .../gitea/cmd/repositories/override_test.go | 49 +++++++++++++++++++ .../gitea/cmd/repositories/repositories.go | 10 ++-- .../cmd/repositories/repositories_test.go | 1 + 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 modules/gitea/cmd/repositories/override_test.go diff --git a/modules/gitea/cmd/repositories/override_test.go b/modules/gitea/cmd/repositories/override_test.go new file mode 100644 index 00000000..b26f520d --- /dev/null +++ b/modules/gitea/cmd/repositories/override_test.go @@ -0,0 +1,49 @@ +package main + +import ( + "strings" + "testing" +) + +// 1141/AC1: a repository the program makes gets main's rule with an administrator's merge past a status refused, +// as every repository's main has had since 2026-10-07. +func TestNewRepositoryRefusesTheAdministratorsOverride(t *testing.T) { + f := newFake() + s, _ := syncer(t, f) + run(t, s, Value{"mesh-delivery": {Description: "d"}}) + rule := f.repos["novox/mesh-delivery"].Rules[mainRule] + if rule["block_admin_merge_override"] != true { + t.Errorf("main lets an administrator merge past its statuses: %v", rule) + } +} + +// 1141/AC2: a narrowed main rule that still lets an administrator override is not right: it is put right, its +// statuses kept, and a second pass changes nothing. +func TestNarrowedRuleLettingTheAdministratorOverrideIsPutRight(t *testing.T) { + f := newFake() + repo := f.add("novox/mesh-delivery", map[string]map[string]any{mainRule: { + "enable_push": false, "enable_push_whitelist": false, "push_whitelist_usernames": []any{}, + "enable_merge_whitelist": true, "merge_whitelist_usernames": []any{tools}, + "enable_status_check": true, "status_check_contexts": []any{"mesh/merge-gate", "mesh/repo-check", "other/x"}, + "block_admin_merge_override": false, + }}, "main") + s, _ := syncer(t, f) + o := run(t, s, Value{"mesh-delivery": {Description: "d"}}) + rule := repo.Rules[mainRule] + if rule["block_admin_merge_override"] != true { + t.Errorf("the administrator's override is still allowed: %v", rule) + } + for _, c := range []string{"mesh/merge-gate", "mesh/repo-check", "other/x"} { + if !has(strs(rule["status_check_contexts"]), c) { + t.Errorf("a status was dropped: %v", rule["status_check_contexts"]) + } + } + if r := result(o, "mesh-delivery"); r.Did != DidPutRight { + t.Errorf("outcome %+v, want put right", r) + } + before := len(f.writes()) + run(t, s, Value{"mesh-delivery": {Description: "d"}}) + if got := f.writes(); len(got) != before { + t.Errorf("a second pass wrote %s", strings.Join(got[before:], ", ")) + } +} diff --git a/modules/gitea/cmd/repositories/repositories.go b/modules/gitea/cmd/repositories/repositories.go index 475554e7..29985eeb 100644 --- a/modules/gitea/cmd/repositories/repositories.go +++ b/modules/gitea/cmd/repositories/repositories.go @@ -333,12 +333,14 @@ func statuses(rules ...rule) []string { } // narrowed is main's rule of ADR 0398 §2 (protection.ts mainRuleBody): no push, only the tools' account merges, -// requiring the statuses (ADR 0428 §5). A field the forge keeps beside these is left as it is. +// requiring the statuses (ADR 0428 §5), and no administrator merging past them, as every repository's main has been +// since 2026-10-07 (issue 1141). A field the forge keeps beside these is left as it is. func narrowed(r rule, toolsAccount string, also ...rule) map[string]any { return map[string]any{ "enable_push": false, "enable_push_whitelist": false, "push_whitelist_usernames": []string{}, "enable_merge_whitelist": true, "merge_whitelist_usernames": []string{toolsAccount}, "enable_status_check": true, "status_check_contexts": statuses(append([]rule{r}, also...)...), + "block_admin_merge_override": true, } } @@ -350,7 +352,8 @@ func isRight(r rule, toolsAccount string) bool { if m := strList(r["merge_whitelist_usernames"]); len(m) != 1 || m[0] != toolsAccount { return false } - return r["enable_status_check"] == true && hasAll(strList(r["status_check_contexts"])) + return r["enable_status_check"] == true && hasAll(strList(r["status_check_contexts"])) && + r["block_admin_merge_override"] == true } func hasAll(have []string) bool { @@ -394,9 +397,6 @@ func (s *Syncer) putRight(ctx context.Context, owner, name string) (bool, error) if n, _ := r["required_approvals"].(float64); n > approvals { approvals = n } - if r["block_admin_merge_override"] == true { - body["block_admin_merge_override"] = true - } } if approvals > 0 { body["required_approvals"] = approvals diff --git a/modules/gitea/cmd/repositories/repositories_test.go b/modules/gitea/cmd/repositories/repositories_test.go index 7f5b0399..90592f35 100644 --- a/modules/gitea/cmd/repositories/repositories_test.go +++ b/modules/gitea/cmd/repositories/repositories_test.go @@ -225,6 +225,7 @@ func TestStatusesAreAddedAndNeverDropped(t *testing.T) { more := f.add("novox/more", map[string]map[string]any{mainRule: { "enable_push": false, "enable_merge_whitelist": true, "merge_whitelist_usernames": []any{tools}, "enable_status_check": true, "status_check_contexts": []any{"mesh/merge-gate", "mesh/repo-check", "mesh/delivery"}, + "block_admin_merge_override": true, // right since issue 1141 }}, "main") s, _ := syncer(t, f) o := run(t, s, Value{"only": {}, "more": {}})