Skip to content

Commit 1e1a0da

Browse files
docs+ci: estate dependabot policy — ignore semver-major by default (closes #297) (#301)
## Summary Documents the estate's policy on major-version dependabot bumps, derived from the 2026-05-29 echidna incident where five major bumps auto-merged green through validation gates that don't compile the workspace, then broke compile on every subsequent push for ~24h. ## Policy summary 1. Each repo's `.github/dependabot.yml` MUST ignore `version-update:semver-major` for each ecosystem. 2. Branch protection MUST require the compile / test gate (`Rust CI`, etc.) — closes the gap between "validated" and "compiles." 3. `--locked` (or the ecosystem equivalent) on every CI cargo / npm / deno invocation — already landed in standards#299. ## Changes - `docs/DEPENDABOT-POLICY.adoc` (new) — full policy document with rationale, recommended template, and migration plan. - `.github/dependabot.yml` — self-demonstrates the policy shape for the github-actions ecosystem (no semver-major ignore needed for github-actions because SHA pins are the real version; comment explains the carve-out). ## What this does NOT do - Does not fan out the ignore-semver-major stanza to all ~140 estate repos — that's a separate campaign issue (TODO file once this lands). - Does not block security-advisory-driven dependabot PRs (those flow via the `security-updates` path which is intentionally not gated by this policy). - Does not change `feedback_always_automerge_prs` — the auto-merge hook is fine for minor/patch PRs that pass the compile gate (recommendation #2 above ensures the compile gate is required). ## Cross-refs - echidna#92 + echidna#128 — the real-world incident. - standards#299 — `--locked` in rust-ci-reusable (complementary fix, already merged). - standards#294 / standards#298 — `--no-lock` for the file walker (orthogonal). - standards#296 / standards#300 — trusted-base 5-line window (orthogonal). Closes #297. EOF )
1 parent 94138da commit 1e1a0da

2 files changed

Lines changed: 115 additions & 3 deletions

File tree

.github/dependabot.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# SPDX-License-Identifier: PMPL-1.0-or-later
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Estate dependabot policy: see docs/DEPENDABOT-POLICY.adoc (standards#297).
23
version: 2
34
updates:
45
- package-ecosystem: "github-actions"
@@ -7,5 +8,8 @@ updates:
78
interval: "daily"
89
groups:
910
actions:
10-
patterns:
11-
- "*"
11+
patterns: ["*"]
12+
# github-actions major bumps are usually safe — the SHA pin is the real
13+
# version. Standards repo is the canonical-template host so we want the
14+
# PRs fast (daily) and grouped. If a specific action proves unstable on
15+
# majors, add a per-name ignore here.

docs/DEPENDABOT-POLICY.adoc

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// SPDX-License-Identifier: MPL-2.0
2+
// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
3+
:toc:
4+
:toc-placement: preamble
5+
6+
= Dependabot policy — major-version bumps + auto-merge
7+
8+
== TL;DR
9+
10+
* `feedback_always_automerge_prs` is fine for **minor / patch** dependabot PRs.
11+
* It is **structurally unsafe** for **major** bumps without a paired call-site update — they pass the validation gates (K9 / A2ML / language-policy) which do not compile the workspace, and only break the downstream compile checks on subsequent pushes.
12+
* Estate policy (this document): **dependabot must not open major-version bumps unattended.** Major bumps land via the normal author-supplied PR path (issue → branch → code update + dep bump in one PR → review → merge).
13+
14+
== Why
15+
16+
`hyperpolymath/echidna` (2026-05-29): five dependabot major-version bumps merged in a chain over ~2h:
17+
18+
[cols="1,3,5",options="header"]
19+
|===
20+
| PR | Bump | Real break
21+
22+
| #120 | axum 0.7 → 0.8 | tower-http 0.6 transitive mismatch
23+
| #121 | rand 0.9 → 0.10 | `Rng` trait renamed to `RngExt`; `use rand::Rng` no longer brings `random_range` / `random` into scope
24+
| #122 | criterion 0.5 → 0.8 | bench harness changes
25+
| #123 | nom 7 → 8 | combinators went closure-based → trait-based: `alt(args)(input)` → `alt(args).parse(input)`
26+
| #124 | rustyline 15 → 18 | editor API changes
27+
|===
28+
29+
Each passed the estate validation gates (`Validate K9 contracts`, `Validate A2ML manifests`, `governance / *`) — none of which compile the workspace — and was auto-merged green. Every subsequent push was red on `Rust CI` (compile errors) + `Live Provers` (all T1 + T2 fail to compile) + `MVP Smoke`. Recovery was a single revert PR (echidna#128) but `main` was effectively broken for ~24h.
30+
31+
The root cause is the gap between **what the auto-merge hook authorises** (any green PR) and **what the green PR has actually been tested against** (the validation gates, not the compile gates).
32+
33+
== Policy
34+
35+
=== 1. Dependabot config — ignore major bumps by default
36+
37+
Every estate repo's `.github/dependabot.yml` should ignore `version-update:semver-major` for each ecosystem entry. Minors and patches continue to flow normally.
38+
39+
[source,yaml]
40+
----
41+
# .github/dependabot.yml — recommended estate shape
42+
version: 2
43+
updates:
44+
- package-ecosystem: "cargo"
45+
directory: "/"
46+
schedule:
47+
interval: "weekly"
48+
groups:
49+
minors-and-patches:
50+
patterns: ["*"]
51+
update-types: ["minor", "patch"]
52+
ignore:
53+
# Major bumps require paired call-site updates — open them via
54+
# an author-supplied PR, not unattended dependabot auto-merge.
55+
# See standards/docs/DEPENDABOT-POLICY.adoc.
56+
- dependency-name: "*"
57+
update-types: ["version-update:semver-major"]
58+
59+
- package-ecosystem: "github-actions"
60+
directory: "/"
61+
schedule:
62+
interval: "weekly"
63+
groups:
64+
actions:
65+
patterns: ["*"]
66+
# github-actions major bumps are usually safe (the SHA pin is the
67+
# real version); group them with the others. Override per-repo if
68+
# a specific action has a history of breaking major-version moves.
69+
70+
# Add npm / nix / pip / mix / ... entries with the same ignore rule.
71+
----
72+
73+
=== 2. Branch protection — require the compile gate
74+
75+
For Rust repos, `Rust CI` (the `rust-ci-reusable.yml` wrapper) MUST be in the required-status-checks list. This catches any version drift at PR time, regardless of how the PR was opened.
76+
77+
For other ecosystems, the equivalent compile / test gate (e.g. `mix test` for Elixir, `deno check` for Deno) MUST be required.
78+
79+
=== 3. `--locked` everywhere it's available
80+
81+
Already landed in `rust-ci-reusable.yml` (standards#299). Cargo, npm, deno, bundler, mix, etc. all support a "use the lockfile verbatim" flag. CI MUST pass it. See standards#295 for the Rust case.
82+
83+
=== 4. The (rare) legitimate major bump path
84+
85+
When a major bump is genuinely wanted:
86+
87+
1. Open an issue: "bump `<dep>` `<old>` → `<new>`; touches `<file list>`".
88+
2. Branch + commit the matching call-site update + the dep bump in one PR.
89+
3. Normal review, normal CI (which now includes the compile gate).
90+
4. Squash-merge as usual.
91+
92+
This is the same path any other code change takes. The point of the policy is not "majors are forbidden" — it's "majors are not unattended."
93+
94+
== Migration
95+
96+
The estate has ~140 repos shipping `.github/dependabot.yml` (audit 2026-05-26). Fan-out the major-ignore stanza via a campaign — the patch is the same shape per repo. Track under a follow-up standards issue (TODO: file once this PR lands).
97+
98+
== Open questions
99+
100+
* **Per-dep override**: some deps (e.g. `serde`, `tokio`) have unusually stable major bumps and might be safe to auto-merge anyway. Carve-outs should be added with explicit rationale per repo, not as a blanket rule.
101+
* **Security advisories**: a major bump that's also a security fix is a different shape. Dependabot's `security-updates` flow opens those separately; this policy does not block them. See https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates.
102+
103+
== Cross-refs
104+
105+
* https://github.com/hyperpolymath/standards/issues/297[standards#297] — the issue this document closes.
106+
* https://github.com/hyperpolymath/echidna/issues/92[echidna#92] — the real-world incident the policy is derived from.
107+
* https://github.com/hyperpolymath/echidna/pull/128[echidna#128] — the revert that recovered echidna.
108+
* https://github.com/hyperpolymath/standards/pull/299[standards#299] — `--locked` in rust-ci-reusable (the complementary CI-level fix).

0 commit comments

Comments
 (0)