diff --git a/netbox/d139-gua-carve.py b/netbox/d139-gua-carve.py index 700af86..cc5584e 100644 --- a/netbox/d139-gua-carve.py +++ b/netbox/d139-gua-carve.py @@ -36,6 +36,14 @@ (0x40, "storage", "storage", True), (0x50, "replication", "replication", True), (0x80, "lbaas-mgmt", "lb-mgmt", True), + # OOB added 2026-08-01 by operator ruling ("make sure to include oob in the dual stack + # recordings" / "Dual-stack; rule 10.12.60.0/22 back into force for OOB"). It was absent + # because design-decisions.md:3066 declared lbaas-mgmt(:80), vpn(:e0) and oob(:f0) all out + # of scope of the six-plane tool; D-139 brought :80 back and left the other two. VR0 DC0 + # and Willamette both carve :f0::/60 + :f0::/64 with role `oob`, so this CONFORMS on the v6 + # side. Its IPv4 half (10.12.60.0/22) is NOT this tool's business -- prefixes only, v6 only. + # VPN (:e0) is the SAME omission and is deliberately NOT added: it was never ruled. + (0xf0, "oob", "oob", True), ] RETIRED_ULA_48 = "fd50:840e:74e2::/48" # retired FOR VR1; still a valid org aggregate STATUS = "active" # measured on all 44 VR1 plane rows, incl. the ULA rows being replaced diff --git a/tests/d139-gua-carve/run-tests.sh b/tests/d139-gua-carve/run-tests.sh index 7d070eb..3a349ae 100755 --- a/tests/d139-gua-carve/run-tests.sh +++ b/tests/d139-gua-carve/run-tests.sh @@ -50,8 +50,12 @@ [ "$RC" -eq 0 ] && has "DRY RUN -- nothing was written" && ok || bad "T05 dry run rc=0 + announcement" [ ! -s "$TMP/writes.log" ] && ok || bad "T06 dry run issued a WRITE to the apex: $(cat "$TMP/writes.log")" -# T07 counts, measured against the fixture (11 new + 3 pre-existing + 9 retiring per DC). -has "CREATE 11 | EXISTS 3 | RETIRE-REPORT 9" && ok || bad "T07 dc0 plan counts changed" +# T07 counts, measured against the fixture (13 new + 3 pre-existing + 9 retiring per DC). +# REPLACED 2026-08-01, not deleted, per the standing rule that remediating a finding must +# REPLACE the assertion with the new invariant: was "CREATE 11" until the operator ruled OOB +# into D-139 ("Dual-stack; rule 10.12.60.0/22 back into force for OOB"), which adds +# :f0::/60 + :f0::/64 = 2 rows. EXISTS and RETIRE are untouched -- OOB has no ULA predecessor. +has "CREATE 13 | EXISTS 3 | RETIRE-REPORT 9" && ok || bad "T07 dc0 plan counts changed" # T08 the D-139 ruling B dc0 carve, verbatim, with the role each prefix binds to. while read -r cidr role; do @@ -68,6 +72,8 @@ 2602:f3e2:f02:50::/64 replication 2602:f3e2:f02:80::/60 lbaas-mgmt 2602:f3e2:f02:80::/64 lbaas-mgmt +2602:f3e2:f02:f0::/60 oob +2602:f3e2:f02:f0::/64 oob EOF # T09 IDEMPOTENCE. provider-public :10/:11 are already built; they must be reported @@ -101,11 +107,14 @@ # T12 dc1 -- the other half of ruling B, same shape, different /48. run --dc vr1-dc1 -[ "$RC" -eq 0 ] && has "CREATE 11 | EXISTS 3 | RETIRE-REPORT 9" && ok || bad "T12 dc1 plan counts changed" +# REPLACED 2026-08-01 with the OOB ruling (was "CREATE 11"): dc1 gains :f0::/60 + :f0::/64 +# from its OWN /48, so the carve stays symmetric across the two DCs by construction. +[ "$RC" -eq 0 ] && has "CREATE 13 | EXISTS 3 | RETIRE-REPORT 9" && ok || bad "T12 dc1 plan counts changed" for cidr in "2602:f3e2:f03:20::/60" "2602:f3e2:f03:20::/64" "2602:f3e2:f03:21::/64" \ "2602:f3e2:f03:30::/60" "2602:f3e2:f03:30::/64" "2602:f3e2:f03:40::/60" \ "2602:f3e2:f03:40::/64" "2602:f3e2:f03:50::/60" "2602:f3e2:f03:50::/64" \ - "2602:f3e2:f03:80::/60" "2602:f3e2:f03:80::/64"; do + "2602:f3e2:f03:80::/60" "2602:f3e2:f03:80::/64" \ + "2602:f3e2:f03:f0::/60" "2602:f3e2:f03:f0::/64"; do printf '%s' "$OUT" | sed -n '/^ CREATE:/,/^$/p' | grep -qF "$cidr" && ok || bad "T12 dc1 CREATE missing $cidr" done printf '%s' "$OUT" | grep -qF "2602:f3e2:f02:" && bad "T12 dc1 run leaked a dc0 prefix" || ok @@ -143,14 +152,16 @@ # T17 the READ-BACK is not decoration. The stub answers every POST 201 but never # adds the row -- the opnsense-plugins.sh class, where apply reported success and -# had silently dry-run. --commit must catch all 11 and exit 1. (127.0.0.1 only.) +# had silently dry-run. --commit must catch all 13 and exit 1. (127.0.0.1 only.) +# 11 -> 13 on 2026-08-01: the OOB ruling adds two CREATE rows, and the read-back +# tally is one-per-CREATE, so this literal tracks the carve table by design. start_stub normal run --dc vr1-dc0 --commit [ "$RC" -eq 1 ] && ok || bad "T17 --commit rc=$RC after a write that did not land (want 1)" has "MISSING AFTER WRITE" && ok || bad "T17 read-back did not notice the writes never landed" -has "READ-BACK: 0/11 present" && ok || bad "T17 read-back tally wrong" -[ "$(wc -l < "$TMP/writes.log")" = "11" ] && ok || bad "T17 posted $(wc -l < "$TMP/writes.log") rows, want 11" -[ "$(grep -c '^POST /api/ipam/prefixes/$' "$TMP/writes.log")" = "11" ] && ok || bad "T17 wrote to an endpoint other than ipam/prefixes" +has "READ-BACK: 0/13 present" && ok || bad "T17 read-back tally wrong" +[ "$(wc -l < "$TMP/writes.log")" = "13" ] && ok || bad "T17 posted $(wc -l < "$TMP/writes.log") rows, want 13" +[ "$(grep -c '^POST /api/ipam/prefixes/$' "$TMP/writes.log")" = "13" ] && ok || bad "T17 wrote to an endpoint other than ipam/prefixes" # T18 an UNREACHABLE apex is UNEVALUABLE, not a write error. Port 1 refuses instantly. # rc MUST be 2 (REFUSE); rc 1 is this tool's "write/read-back error" and a dry run that diff --git a/tests/d139-gua-carve/stub-apex.py b/tests/d139-gua-carve/stub-apex.py index c8d4715..c5c629a 100644 --- a/tests/d139-gua-carve/stub-apex.py +++ b/tests/d139-gua-carve/stub-apex.py @@ -18,7 +18,7 @@ {"id": 9, "slug": "vr1-dc1", "name": "VR1 DC1"}] ROLES = [{"id": i, "slug": s} for i, s in enumerate( ["dc", "provider-public", "metal-admin", "metal-internal", "data-tenant", - "storage", "replication", "lbaas-mgmt", "edge", "transit"], start=1) + "storage", "replication", "lbaas-mgmt", "oob", "edge", "transit"], start=1) if not (MODE == "no-role" and s == "lbaas-mgmt")]