diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index a1ad5a7..5a2e832 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -1183,9 +1183,34 @@ tfstate involved, and dc1 still measures 6 v6 planes ABSENT -- only dc0 was authorised. `dc-plane-ipam check vr1-dc0` now reports the six v6 planes `[ok]`; its remaining reds are the 12 unreserved D-134 bands. - **STILL NOT DONE, each an operator-gated live mutation:** dc1's v6 carve, the band - reservations both DCs, the v6 bands (forced to follow each DC's carve), the rack-bridge v6 - legs, and the apex population. +- **D-134's BANDS NOW EXIST -- STEP 3's MAAS HALF IS COMPLETE, BOTH DCs, 2026-07-27** + (operator-gated: "Process 1,2,3. All approved"). Capture + `docs/audit/dc-plane-ipam-executed-20260727.txt`. Sequence: dc1 v6 carve, then dc0 reserve, + then dc1 reserve -- each pre-apply re-verified in the same session, each write READ BACK. + **dc1 carve 6 applied / 0 errors. dc0 reserve 13 applied (12 bands + FIP pool). dc1 reserve + 12 applied, 1 error = the FIP refusal.** Totals: MAAS subnets **18 -> 30** (12 v6 planes, + 6 per DC), ipranges **3 -> 28** (3 dynamic unchanged, 25 reserved created). **`dc-plane-ipam + check` now reports pass=24 fail=0 on BOTH DCs, from a 6/18 baseline** -- the gate that had + never passed, passing, having first been proven able to fail 18 times per DC. **This closes + the "RULED IS NOT BUILT" finding for D-134:** its band table existed only as prose since + 2026-07-23 and MAAS held ZERO reserved ranges; the bands are now artifacts. **Machines + measured 18 Ready + 2 Deployed UNCHANGED throughout** -- no node, no tfstate, no running + service touched. + **MEASURED CORRECTION TO R4's EXECUTION MODEL -- MAAS ALREADY RESERVES THE ENTIRE LOW IPv6 + BLOCK.** Every explicit v6 band create FAILED with "Requested reserved range conflicts with + an existing range." Cause measured via `maas admin subnet reserved-ip-ranges`: MAAS + auto-reserves **`::1` - `::ffff:ffff`** (purpose `reserved`) on EVERY IPv6 subnet, plus `::` + under RFC 4291 s2.6.1; allocatable space begins only at `:0:1::`. The ruled v6 bands + sit ENTIRELY inside that, so they are already protected far more broadly than the band -- + the write is both impossible and unnecessary. **R4's "v6 bands follow as a second pass with + the same tool" is therefore NOT EXECUTABLE and does not need to be**; the tool now VERIFIES + the coverage property instead of writing. Execution-level correction only -- R4's INTENT + (v6 planes carry band discipline) is satisfied. Verified identically on ULA and GUA subnets. + Harness case T19 was RE-POINTED at the surviving invariant rather than deleted, per the + standing rule that remediating a finding must not be resolved by removing the assertion. + **STILL NOT DONE, each an operator-gated live mutation:** the rack-bridge v6 legs (U17), and + the apex population (bands + VIPs as scoped objects). **STILL NEEDING A RULING: dc1's FIP + pool** -- unset in `lib-net.sh` by design, so R4 cannot close for dc1 until it is ruled. - Position inside Stage 3: deploy step A EXECUTED 2026-07-19 (6/0/6 exact; convergence zero -- `docs/audit/outer-plan-20260719-postA-converged.txt`). **Deploy step B diff --git a/docs/audit/dc-plane-ipam-executed-20260727.txt b/docs/audit/dc-plane-ipam-executed-20260727.txt new file mode 100644 index 0000000..4fdf54d --- /dev/null +++ b/docs/audit/dc-plane-ipam-executed-20260727.txt @@ -0,0 +1,80 @@ +STEP 3 BAND/CARVE EXECUTION -- AS-EXECUTED, 2026-07-28T10:10:24Z +Operator-gated: 'Process 1,2,3. All approved'. No run-logged.sh window (P0-4 class). + +SEQUENCE: carve-v6 dc1 --commit; reserve dc0 --commit; reserve dc1 --commit + +RESULTS + carve-v6 vr1-dc1 : 6 applied / 1 skipped / 0 errors, each READ BACK + reserve vr1-dc0 : 13 applied (12 D-134 bands + FIP pool) / 0 errors + reserve vr1-dc1 : 12 applied (12 D-134 bands) / 1 error = FIP pool REFUSED + +GATE, both DCs: dc-plane-ipam check = pass=24 fail=0 (baseline was 6/18 each) + ipranges 3 -> 28 (3 dynamic unchanged + 25 reserved created) + subnets 18 -> 30 (12 v6 planes created, 6 per DC) + machines 18 Ready + 2 Deployed -- UNCHANGED THROUGHOUT + +FINDING -- MAAS ALREADY RESERVES THE WHOLE LOW IPv6 BLOCK. + Every explicit v6 band create FAILED with: + 'Requested reserved range conflicts with an existing range.' + Measured cause via 'maas admin subnet reserved-ip-ranges ': MAAS + auto-reserves ::1 - ::ffff:ffff (purpose 'reserved') on EVERY IPv6 subnet, + plus :: itself under RFC 4291 s2.6.1. Allocatable space begins only at + :0:1::. The ruled v6 bands sit entirely inside that block, so they + are ALREADY protected -- far more broadly than the band itself. + CONSEQUENCE: R4's 'v6 bands follow as a second pass with the same tool' is + NOT EXECUTABLE in MAAS and does not need to be. The tool now VERIFIES the + coverage property instead of attempting a write. This is an execution-level + correction to R4; the INTENT (v6 planes carry band discipline) is satisfied. + Verified identically on ULA and GUA subnets. + +STILL OPEN: dc1's FIP pool is UNSET in lib-net BY DESIGN, so R4 cannot close + for dc1 until it is ruled. Not inferred from dc0's shape (hard rule 2). + +########## check vr1-dc0 ########## + [ok] v6 metal-internal fd50:840e:74e2:221::/64 present + [ok] v6 provider-public 2602:f3e2:f02:10::/64 present + [note] provider-public 2602:f3e2:f02:11::/64 provider VIP block, MAAS subnet=no (not asserted) + [ok] v6 replication fd50:840e:74e2:250::/64 present + [ok] v6 storage fd50:840e:74e2:240::/64 present + +-- D-134 reserved bands (v4) -- + [ok] provider-public util band 10.12.4.4-10.12.4.49 reserved + [ok] provider-public vip band 10.12.4.50-10.12.4.99 reserved + [ok] metal-admin util band 10.12.8.4-10.12.8.49 reserved + [ok] metal-admin vip band 10.12.8.50-10.12.8.99 reserved + [ok] metal-internal util band 10.12.12.4-10.12.12.49 reserved + [ok] metal-internal vip band 10.12.12.50-10.12.12.99 reserved + [ok] data-tenant util band 10.12.16.4-10.12.16.49 reserved + [ok] data-tenant vip band 10.12.16.50-10.12.16.99 reserved + [ok] storage util band 10.12.32.4-10.12.32.49 reserved + [ok] storage vip band 10.12.32.50-10.12.32.99 reserved + [ok] replication util band 10.12.36.4-10.12.36.49 reserved + [ok] replication vip band 10.12.36.50-10.12.36.99 reserved + +RESULT: pass=24 fail=0 +PASS: dc-plane-ipam check vr1-dc0 + +########## check vr1-dc1 ########## + [ok] v6 metal-internal fd50:840e:74e2:321::/64 present + [ok] v6 provider-public 2602:f3e2:f03:10::/64 present + [note] provider-public 2602:f3e2:f03:11::/64 provider VIP block, MAAS subnet=no (not asserted) + [ok] v6 replication fd50:840e:74e2:350::/64 present + [ok] v6 storage fd50:840e:74e2:340::/64 present + +-- D-134 reserved bands (v4) -- + [ok] provider-public util band 10.12.64.4-10.12.64.49 reserved + [ok] provider-public vip band 10.12.64.50-10.12.64.99 reserved + [ok] metal-admin util band 10.12.68.4-10.12.68.49 reserved + [ok] metal-admin vip band 10.12.68.50-10.12.68.99 reserved + [ok] metal-internal util band 10.12.72.4-10.12.72.49 reserved + [ok] metal-internal vip band 10.12.72.50-10.12.72.99 reserved + [ok] data-tenant util band 10.12.76.4-10.12.76.49 reserved + [ok] data-tenant vip band 10.12.76.50-10.12.76.99 reserved + [ok] storage util band 10.12.80.4-10.12.80.49 reserved + [ok] storage vip band 10.12.80.50-10.12.80.99 reserved + [ok] replication util band 10.12.84.4-10.12.84.49 reserved + [ok] replication vip band 10.12.84.50-10.12.84.99 reserved + +RESULT: pass=24 fail=0 +PASS: dc-plane-ipam check vr1-dc1 + diff --git a/docs/changelog-20260727-stage5-phase0.md b/docs/changelog-20260727-stage5-phase0.md index a8d2d04..9657a37 100644 --- a/docs/changelog-20260727-stage5-phase0.md +++ b/docs/changelog-20260727-stage5-phase0.md @@ -300,3 +300,44 @@ have no allocations today, but check rather than assume. **Capture.** `docs/audit/dc0-v6-carve-20260727.txt`. + +## 10. LIVE MUTATION -- dc1 v6 carve + D-134 band reservations, both DCs + +**What.** Operator-gated ("Process 1,2,3. All approved"), in dependency order: +`carve-v6 vr1-dc1 --commit` (6 subnets), `reserve vr1-dc0 --commit` (13 ranges), +`reserve vr1-dc1 --commit` (12 ranges). Each pre-apply re-verified in the same +session; every write read back. + +**Result.** MAAS subnets **18 -> 30**, ipranges **3 -> 28** (25 reserved created; +the 3 pre-existing dynamic ranges untouched). `dc-plane-ipam check` = **pass=24 +fail=0 on BOTH DCs**, from a 6/18 baseline. Machines **18 Ready + 2 Deployed, +unchanged throughout**. + +**Why it matters.** D-134's band table had existed only as decision prose since +2026-07-23 while MAAS held ZERO reserved ranges. The bands are now artifacts, closing +that "ruled is not built" finding. + +**FINDING -- MAAS already reserves the whole low IPv6 block.** Every explicit v6 band +create failed: *"Requested reserved range conflicts with an existing range."* Measured +via `maas admin subnet reserved-ip-ranges`: MAAS auto-reserves `::1`-`::ffff:ffff` +(purpose `reserved`) on every IPv6 subnet, plus `::` per RFC 4291 s2.6.1; allocatable +space starts at `:0:1::`. The ruled bands sit entirely inside that, so the write +is impossible AND unnecessary. R4's "v6 bands follow as a second pass" is not executable +in MAAS and needs not be. The tool now VERIFIES coverage instead of writing. Confirmed +identically on ULA and GUA subnets. + +**Harness.** T19 asserted a literal string the fix removed, so it was **re-pointed at the +surviving invariant** (bounds are the textual `4-99`, never the hex `4-63`) rather than +deleted -- the standing rule against going green by removing an assertion. 25/25; +gauntlet ALL GREEN (83). + +**Still refused, correctly:** dc1's FIP pool. Unset in `lib-net.sh` by design; R4 cannot +close for dc1 until it is ruled. Not inferred from dc0's shape. + +**Revert.** Reserved ranges are additive and safe to delete: +`maas admin ipranges read` -> for each id with `type=reserved` and a `10.12.*` start_ip +created today, `maas admin iprange delete `. For the dc1 v6 subnets, use item 9's +shape with the `:3xx::/64` prefixes. **Read occupancy before deleting a subnet** (the +2026-07-21 pod-delete cascade). + +**Capture.** `docs/audit/dc-plane-ipam-executed-20260727.txt`. diff --git a/tests/dc-plane-ipam/run-tests.sh b/tests/dc-plane-ipam/run-tests.sh index 29d96bf..878a020 100755 --- a/tests/dc-plane-ipam/run-tests.sh +++ b/tests/dc-plane-ipam/run-tests.sh @@ -60,6 +60,12 @@ PY exit 0 fi +if [ "\$2" = "subnet" ] && [ "\$3" = "reserved-ip-ranges" ]; then + # MAAS's MEASURED default on every IPv6 subnet (2026-07-27, live): the whole + # ::1-::ffff:ffff block is already reserved, plus :: per RFC 4291 s2.6.1. + echo '[{"start":"fd50:840e:74e2:220::","end":"fd50:840e:74e2:220::","purpose":["rfc-4291-2.6.1"]},{"start":"fd50:840e:74e2:220::1","end":"fd50:840e:74e2:220::ffff:ffff","purpose":["reserved"]}]' + exit 0 +fi if [ "\$2" = "ipranges" ]; then [ "$rrc" -ne 0 ] && exit $rrc python3 - "$bands" <<'PY' @@ -172,16 +178,20 @@ "T18 a same-bounds range of the WRONG type REFUSES rather than being overwritten" "$D" # --- T19: the v6 band mirror is TEXTUAL, not numeric --- -# Caught pre-ship: printf '%%x' 50 yields 32, which would have silently created -# ::32-::63 -- a plausible-looking band that is NOT the one ruled. The ruling -# mirrors the DIGITS: v4 .50 -> ::50. +# REPLACED 2026-07-27, not deleted. The original asserted that the tool PLANS a +# reserved range `...::50-...::99`. Measurement then showed MAAS AUTO-RESERVES +# ::1-::ffff:ffff on every IPv6 subnet, so an explicit create is both impossible +# ("conflicts with an existing range") and unnecessary -- the tool now VERIFIES +# coverage instead of writing. Remediating the finding turned this assertion red, +# so it is re-pointed at the surviving invariant rather than removed: +# the bounds checked must be the TEXTUAL octet mirror (4-99), never the hex +# conversion (4-63) that `printf '%x'` would have produced. D="$TMP/v6band"; mkdir -p "$D"; mkapex "$D/apex.json"; mkmaas "$D" full none out="$(cd "$REPO" && PATH="$D/fakebin:$PATH" APEX_RECORD="$D/apex.json" \ bash scripts/dc-plane-ipam.sh reserve vr1-dc0 2>&1)" -if grep -q 'fd50:840e:74e2:220::50-fd50:840e:74e2:220::99' <<<"$out" \ - && ! grep -q '::32-' <<<"$out"; then - ok "T19 v6 VIP band is ::50-::99 (textual octet mirror), NOT the hex ::32-::63" -else bad "T19 v6 band mirror wrong" "$(grep -E '::' <<<"$out" | head -4)"; fi +if grep -q "bands 4-99 already protected" <<<"$out" && ! grep -q 'bands 4-63' <<<"$out"; then + ok "T19 v6 bands verified over the TEXTUAL octet range 4-99, not the hex 4-63" +else bad "T19 v6 band bounds wrong" "$(grep -iE 'band|protect' <<<"$out" | head -3)"; fi # --- T20: dc1 must REFUSE to invent the FIP pool --- # lib-net deliberately unsets FIP_POOL_* for dc1 ("UNSET so any use fails loud").