diff --git a/clientdocs/intake-form.md b/clientdocs/intake-form.md index 4bfc130..a671232 100644 --- a/clientdocs/intake-form.md +++ b/clientdocs/intake-form.md @@ -48,11 +48,14 @@ ## 5. Network ranges -Private address range(s) you want your cloud networks to use (RFC1918, e.g. -`10.x.x.0/24`). IMPORTANT: choose ranges that do NOT overlap your on-premises -or VPN networks if you ever plan to connect them to this environment. +OPTIONAL: the internal network range(s) (CIDR) you want your cloud networks +to use (RFC1918, e.g. `10.x.x.0/24`). Leave blank and you get our standard +default. Your range is private to your environment -- it does not need to be +unique among our clients, so pick whatever fits your plans. IMPORTANT: choose +ranges that do NOT overlap your on-premises or VPN networks if you ever plan +to connect them to this environment. -- Primary range: ______________________ +- Primary range (optional): ______________________ - Additional ranges (optional): ______________________ ## 6. Workload profile diff --git a/clientdocs/sweep-receipt.txt b/clientdocs/sweep-receipt.txt index 359dd31..570c4dd 100644 --- a/clientdocs/sweep-receipt.txt +++ b/clientdocs/sweep-receipt.txt @@ -12,16 +12,16 @@ d8595b7a1bb339af0a05ea547a814d63d906dc17e5a51609aa041bb56d637fd8 clientdocs/acceptance-checklist.md a7dcdd137fcf8f38fb32716a70c1d988c5365d379d6a450722e29fff99effb1c clientdocs/ci-integration-guide.md 5d3cc5597b550fdcadb3f084062479ddd4f1b22576a154c855bcb64f5cecc727 clientdocs/handover-pack.md -0ff49cdb77d87ca60f971b29bea33714ebc9e79622df11a7f1e744459fe222dd clientdocs/intake-form.md +307967ca80a0daf168e295b3a4fba0ff71b08e208932070bdb83b81a0f4b0ef9 clientdocs/intake-form.md c084b45c2dbe3d3430f0428b1aa55e4563787a88f59598938b024fdcd3f12a47 clientdocs/self-service-guide.md 488bda3e51ca1ddd6adb51bb317fccd5ee04731687fa7975e41a4043efe87adb clientdocs/welcome.md -917db0e786047491ff75c2624811c5bea212eef98c64327058fd87e680a6207b docs/tenant-onboarding-contract.md +04c0a08df9168448740514ae9763968eb7ea706cef58533c51c7448a5b0329c3 docs/tenant-onboarding-contract.md 64f99b638a1855b02180e907c9535db8bddc5847a502759a9e0d63c513b63077 policies/domain-manager-policy.yaml 02fe1fd7fcf07bfc6088622d4aa8430da53e435d60006d0b81f6b9c2e720a011 policies/overrides.zip 30919b61b2b79b33a853a29bc814558d7e0e940a3040b2f7710ea9a14333b71a runbooks/appendix-C-identity-rbac.md 8510402e5375a6d42cc47f28eec9698a23d88e04b22ef70ef6e129e1179f3d32 runbooks/appendix-D-magnum-trust-model.md -11d264207bc9e3ef5ebbb2df0ecd4ed22151270fb8732aec4ce6e1d4b8dd0b29 runbooks/tenant-onboarding-v2-DRAFT.md +927aa7261aa2d9fabe2cb7342499e6c0d0840a93ffbb323ee7003ac8eefe14a7 runbooks/tenant-onboarding-v2-DRAFT.md a6080e4d4207a0a47d0ce9e9f54f5b7b3235e0dbf96b00eb2fbc2238df9895ff scripts/tenant-acceptance.sh ad00be489480069d52df1b978be0360d7fb04dbf954a8cf487162872f2da0593 scripts/tenant-assert.sh 0b09bbc3de1927e299eb8650ea901c9f1939abc097e717aa70a049079b409edd scripts/tenant-offboard.sh -389e5fe25391a3e16bab71608b55fb3ad2153e80300ef66f76bf5687544ccf69 scripts/tenant-onboard.sh +3f5a3656ef8ebfc0ef9370b1ffd416ee98e40640c803b8bad8492e80ee289051 scripts/tenant-onboard.sh diff --git a/docs/design-decisions.md b/docs/design-decisions.md index 4fb4318..cd0d91f 100644 --- a/docs/design-decisions.md +++ b/docs/design-decisions.md @@ -1810,3 +1810,76 @@ is now QUEUED per the do-doc's close-out clause. Checker corrections made in-window: DOCFIX-095 (tenant-assert owner-context probe), DOCFIX-096 (amphora_headroom live CLI shapes). + +## D-074: Tenant CIDRs are tenant-chosen and may overlap (amends D-016) + +**Status: ADOPTED 2026-07-06** (operator rulings recorded same day; proposed by +the main-chat stream in docs/tenant-cidr-overlap-correction-PLAN.md). + +**Decision.** Tenant private (overlay) CIDRs are tenant-chosen and MAY overlap +across tenants. Non-collision is enforced ONLY against the reserved-ranges +registry, with real subnet-overlap math (containment in either direction), +plus RFC1918 membership (contract section 3 item 4's original intent). +Reserved ranges = the six PLANE_CIDRS /22s (scripts/lib-net.sh, keyed by +plane), the capi-mgmt tenant network (D-035; operator ruled: stays reserved; +resolved live by stable name capi-mgmt-subnet, never hardcoded), and the +metadata range. Default tenant CIDR policy (operator ruled): client-choice +with fallback default 10.100.0.0/24. + +**Why.** The stage-4 guard over-enforced relative to the onboarding contract +(rejected tenant-vs-tenant overlap the contract never required) while +under-enforcing what matters (exact-string match missed partial overlaps +against reserved ranges). Overlap-allowed tenant CIDRs is the standard +isolated-multi-tenant model and matches the SCS Domain Manager hard-isolation +persona; per D-035 the management path never routes into tenant overlay space +(an earlier main-chat "CAPI/Magnum reachability" claim is retracted in the +PLAN doc). Gains: contract/implementation alignment, no find-a-free-/24 step, +clients can align to their own on-prem ranges, NetBox uniqueness duty shrinks +to the routed space, the one-/16 (256-tenant) ceiling goes away. Costs: an IP +no longer identifies a tenant (triage needs net+tenant context); no +tenant-private-IP routing between tenants (an anti-pattern here anyway). + +**Phase-0 evidence (gates honored).** 0.1: allow_overlapping_ips=True read +live from the neutron-api leader's rendered neutron.conf (2026-07-06). 0.2: +exact-overlap proof executed inside foil1 (operator-ruled vehicle -- the +PLAN's "onboard an overlapping foil" was stale: foil1 already existed and the +old guard blocks exact-overlap onboarding): foil1-overlap-net/-subnet created +at 10.20.28.0/24 == beta-subnet EXACTLY, attached to foil1-router, and a +Magnum cluster (foil1-overlap, 1 master / 1 node, master-lb-enabled) built on +that overlapping network -- see the D-074 amendment recording the terminal +state and evidence path. Proof resources are torn down after evidence. + +**Forward-only.** Existing tenants keep their CIDRs (beta 10.20.28.0/24, +foil1 10.20.29.0/24 -- measured 2026-07-06; the PLAN's "northwind +10.20.20.0/24" example was fictional). No re-CIDR; design-decisions forbids +transient-overlap re-CIDR. + +**Implements:** guard rewrite in scripts/tenant-onboard.sh stage 4 + +scripts/net_overlap.py (DOCFIX-106); doc alignment (contract section 3, +onboarding runbook, clientdocs intake) rides the same delivery. +**Amends:** D-016 (its /16-pool uniqueness becomes vestigial, not reclaimed). +**Related:** D-035, D-051, D-066. + +## D-016 -- AMENDMENT (2026-07-06): uniqueness carve-out superseded by D-074 + +D-016's single-pool model (carve non-overlapping /24s from 10.20.0.0/16) +stops being enforced forward: D-074 (ADOPTED) makes tenant CIDRs +tenant-chosen and overlap-allowed, guarded only against reserved ranges. +The /16 pool remains as history for existing allocations; nothing is +re-numbered. See D-074. + +## D-074 -- AMENDMENT (2026-07-06): Phase 0.2 proof EXECUTED -- overlap+Magnum confirmed + +Executed same-day in the logged d074-phase0 session (Claude Code lane). +foil1-overlap-net/-subnet created at 10.20.28.0/24 (EXACT overlap with +beta-subnet, different tenant); Magnum cluster foil1-overlap reached +CREATE_COMPLETE in ~14.5 min (matches beta's ~13.5 min profile); kubeapi +octavia LB ACTIVE/ONLINE; tenant-fetched kubeconfig returned 2 Ready nodes +THROUGH the API-LB with node addresses (10.20.28.229, .54) inside the +overlapping range -- while beta's cluster on the same CIDR served undisturbed. +Both tenants ran Kubernetes on the same /24 simultaneously: the strongest +refutation of the retracted reachability concern. Evidence: +~/openstack-baseline/d074-phase02-evidence-20260706-234352.txt (jumphost). +Proof resources torn down (cluster, template, router-if, subnet, net -- +residual check clean); post-teardown cloud-assert PASS. Phase 0 gates are +fully discharged; the D-074 implementation (DOCFIX-106/107) ships. diff --git a/docs/repo-lint-nextfree-bug-FINDING.md b/docs/repo-lint-nextfree-bug-FINDING.md index e1c52e0..42723a1 100644 --- a/docs/repo-lint-nextfree-bug-FINDING.md +++ b/docs/repo-lint-nextfree-bug-FINDING.md @@ -39,10 +39,13 @@ 3. **Scans the test tree.** `all_text()` includes `tests/`. `tests/ledger-scan/run-tests.sh` contains a deliberately-high fixture line (`Next-free: D-071, DOCFIX-099, BUNDLEFIX-050 ... must NOT inflate`) written to PROVE - `ledger-scan` ignores pointer lines. repo_lint ingests that fixture's `BUNDLEFIX-050` + `ledger-scan` ignores pointer lines. repo_lint ingests that fixture's `BUNDLEFIX-`050 and reports `051` -- the precise trap the fixture was authored to catch. -Correction of the record: an earlier main-chat note called `BUNDLEFIX-051` "spurious." It is +Correction of the record: an earlier main-chat note called `BUNDLEFIX-`051 "spurious." It is +(tokens above de-fanged 2026-07-06, jumphost stream: identifier-shaped tokens above the +real high-water mark in docs/ prose inflate the ledger-scan counters -- the standing rule +this very FINDING is about; the table rows survive because "next-free" lines are excluded.) not -- it is `max+1` of the fixture token in defect 3. The imprecision is corrected here. ## Fix options (Code's lane; not implemented here) diff --git a/docs/session-ledger.md b/docs/session-ledger.md index 779f951..36ec434 100644 --- a/docs/session-ledger.md +++ b/docs/session-ledger.md @@ -31,8 +31,8 @@ - **OPEN security rows:** SEC-001 (rotate at v1 close, re-ruled 2026-07-06), SEC-003 (custodians + second-person unseal -- DEFERRED; keeps d011-06 MANUAL), SEC-004 (flip repo to private at v1 close -- deferral reaffirmed). -- **Next-free numbers:** D = 074, DOCFIX = 106, BUNDLEFIX = 012. - (Scan and the addendum-28 changelog next-free pointer agree.) +- **Next-free numbers:** D = 075, DOCFIX = 108, BUNDLEFIX = 012. + (Scan and the addendum-29 changelog next-free pointer agree.) --- @@ -271,6 +271,18 @@ - **Open (small):** Horizon manual checks on foil1 (operator, browser, non-blocking); capi-test-1 CREATE_FAILED leftover (orphan-sweep candidate); beta-cluster lbtest leftover; repo-lint worktree-exclusion DOCFIX candidate. +- **D-074 EXECUTED (addendum 29):** operator ADOPTED the main-chat CIDR + correction PLAN same-day (overlap-allowed tenant CIDRs; client-choice + + 10.100.0.0/24 fallback; capi-mgmt stays reserved; L5 print removed). + Phase 0 gates honored: allow_overlapping_ips=True measured; overlap+Magnum + proof via foil1 (EXACT 10.20.28.0/24 overlap with beta; cluster ~14.5 min; + 2 Ready nodes via API-LB while beta served the same CIDR); teardown clean; + cloud-assert PASS. Guard rewritten (DOCFIX-106, net_overlap.py, harness + 12->17), docs aligned (contract/runbook/intake), D-016 amended, repo_lint + L5 next-free removed (DOCFIX-107). FINDING-doc BUNDLEFIX token de-fanged + (counter was inflated to 052; restored 012). Phase 3 (devteam onboarding, + fallback CIDR) remains NEXT SESSION. Corrections fed back to main-chat via + addendum 29: northwind example fictional; runbook filename wrong in PLAN. - **INTEGRATED (addendum 28):** all six worktree drafts -> main as DOCFIX-098 (H4 drift detector), 099/100 (offboard orphan sweep + Phase E0 guard), 101 (clientdocs handover pack), 102 (cloud-snapshot.sh -- unblocks diff --git a/docs/tenant-onboarding-contract.md b/docs/tenant-onboarding-contract.md index 53c2661..21ec5b9 100644 --- a/docs/tenant-onboarding-contract.md +++ b/docs/tenant-onboarding-contract.md @@ -56,9 +56,14 @@ bus factor. 3. **Quota ask**: instances / vCPU / RAM, volumes + GB, networks/routers/FIPs, load balancers, clusters + node counts. (Maps to the stage-1 quota envelope.) -4. **Tenant CIDR(s)** -- RFC1918, non-colliding with our allocations AND with any - on-prem/VPN ranges they may later interconnect. Stage 4 fails closed on collision, - but collecting it up front avoids a restart. +4. **Tenant CIDR(s)** -- OPTIONAL (D-074): client-choice, RFC1918; fallback + default 10.100.0.0/24 when the client has no preference. Overlap with OTHER + TENANTS is explicitly PERMITTED (hard-isolation model; D-074 amends + D-016's uniqueness carve-out). Stage 4 fails closed only on real subnet + overlap (containment either way) with OUR reserved ranges (plane /22s, + capi-mgmt, metadata) or on non-RFC1918. Clients SHOULD still avoid their + own on-prem/VPN ranges they may later interconnect -- their homework, not + our guard's. 5. **Workload profile**: Kubernetes yes/no (sizing against the capi templates), LB count expectations (amphora capacity), storage expectations. 6. **Authorized requesters** -- who may request quota changes / password resets. diff --git a/docs/v1-redeploy-changelog.md b/docs/v1-redeploy-changelog.md index c9a23ab..cbc76a1 100644 --- a/docs/v1-redeploy-changelog.md +++ b/docs/v1-redeploy-changelog.md @@ -2433,3 +2433,65 @@ scripts/ledger-scan.sh tests/ledger-scan/run-tests.sh. Next-free after this push (per scan, keep this line unwrapped): D-074, DOCFIX-106, BUNDLEFIX-012. + +### 2026-07-06 (addendum 29, jumphost stream) -- D-074 ADOPTED+EXECUTED: overlap-allowed tenant CIDRs; DOCFIX-106/107 + +Work order authored by the main-chat stream (docs/tenant-cidr-overlap- +correction-PLAN.md + docs/repo-lint-nextfree-bug-FINDING.md, pushed this +session); operator rulings same-day: D-074 ADOPT; client-choice CIDR with +10.100.0.0/24 fallback; capi-mgmt 10.20.0.0/24 stays reserved; L5 next-free +print REMOVED. Phase 0 gates honored before any implementation shipped. + +- **Phase 0 (read-only gates, logged d074-phase0):** 0.1 allow_overlapping_ips + = True read from the neutron-api leader's rendered neutron.conf. 0.2 + overlap+Magnum proof via foil1 (operator-ruled vehicle; the PLAN's + onboard-a-foil step was stale -- foil1 existed and the old guard blocks + exact-overlap onboarding): EXACT-overlap subnet (10.20.28.0/24 == + beta-subnet) + cluster CREATE_COMPLETE ~14.5 min + 2 Ready nodes via the + API-LB while beta served on the same CIDR. Full detail + evidence path in + the D-074 Phase-0.2 amendment. Teardown clean; post cloud-assert PASS. +- **D-074 decision record + D-016 amendment** appended to design-decisions + (rationale, rulings, Phase-0 evidence, forward-only; corrections recorded: + the PLAN's "northwind 10.20.20.0/24" example was fictional -- live tenants + are beta/foil1). +- **DOCFIX-106 -- stage-4 guard rewrite (scripts/tenant-onboard.sh + + scripts/net_overlap.py).** Replaces the exact-string cloud-wide check + (over-enforced tenant uniqueness the contract never required; MISSED + partial overlaps) with real containment math: reject only non-RFC1918 + (explicit 10/8+172.16/12+192.168/16 -- python is_private would wrongly + accept TEST-NET) or overlap with PLANE_CIDRS (sourced from lib-net.sh), + the capi-mgmt net (resolved live by stable name, FAIL-CLOSED on lookup + miss), and metadata. tenant-onboard harness 12->17 cases: tenant-vs-tenant + exact overlap ALLOWED; partial-vs-reserved REJECTED; exact-reserved + REJECTED; capi partial REJECTED (dynamic); non-RFC1918 REJECTED; capi + lookup miss fails closed. Doc alignment same delivery: + docs/tenant-onboarding-contract.md section 3 item 4 (optional, + overlap-permitted, fallback default); runbooks/tenant-onboarding-v2-DRAFT.md + block 4.0 (new guard invocation; NOTE the PLAN named a nonexistent + "tenant-onboarding-runbook.md"); clientdocs/intake-form.md section 5 + (optional, overlap-safe wording); L7 receipt re-recorded after the review. + REVERT: git checkout HEAD~ -- scripts/tenant-onboard.sh + tests/tenant-onboard/run-tests.sh docs/tenant-onboarding-contract.md + runbooks/tenant-onboarding-v2-DRAFT.md clientdocs/intake-form.md + clientdocs/sweep-receipt.txt; git rm scripts/net_overlap.py; re-attach the + old guard only with a new D-NNN (D-074 governs). +- **DOCFIX-107 -- repo_lint.py L5 numbering print REMOVED** (the unreliable + next-free line; per the FINDING + doc's recommended option; all three defects confirmed: band-limited regex, + mention-counting without pointer-exclusion, tests/-fixture ingestion). + The duplicate-heading collision guard KEPT and its own regex widened past + the 099 boundary (same defect class as DOCFIX-105). ledger-scan is the + sole numbering authority. repo-lint harness green (T8 collision case + intact). REVERT: git checkout HEAD~ -- scripts/repo_lint.py. +- **FINDING-doc de-fang (rides this addendum):** the main-chat FINDING doc's + own prose carried a BUNDLEFIX token above high-water, inflating the + ledger-scan BUNDLEFIX counter to 052 the moment it was pulled -- de-fanged + in place with a note (the standing identifier-pollution rule; scan verified + restored to 012). +- **Gates:** tenant-onboard 17/17; repo-lint harness 17/17; gauntlet ALL + GREEN (35); repo-lint 0 fail / 1 legacy warn (worktree artifacts excluded); + baseline + post-phase-0 cloud-assert PASS. Phase 3 (devteam onboarding on + the corrected guard, TENANT_CIDR fallback 10.100.0.0/24) stays NEXT SESSION + per operator ruling. + +Next-free after this push (per scan, keep this line unwrapped): D-075, DOCFIX-108, BUNDLEFIX-012. diff --git a/logs/as-executed-index.md b/logs/as-executed-index.md index 8ff467c..2fe0a64 100644 --- a/logs/as-executed-index.md +++ b/logs/as-executed-index.md @@ -9,3 +9,4 @@ | 2026-07-05 | ops-update-20260705 | jesse.austin | routine update window: controller patch + model agents + in-channel charm refreshes (ops-update-procedure first execution) | | 2026-07-06 | d011-batch3 | jesse.austin (Claude Code lane, per-command wrap) | batch-3 window: D-073 policy apply + foil1 onboarding + d011-04/05 validation + close-out | | 2026-07-06 | ops-snapshot-devteam-gate | jesse.austin (Claude Code lane) | pre-devteam-onboarding cloud snapshot (first live cloud-snapshot.sh run) | +| 2026-07-06 | d074-phase0 | jesse.austin (Claude Code lane) | D-074 Phase 0: overlap+Magnum proof via foil1 (exact-overlap subnet + cluster + API-LB), teardown, cloud-assert | diff --git a/runbooks/tenant-onboarding-v2-DRAFT.md b/runbooks/tenant-onboarding-v2-DRAFT.md index ccb046e..87a02f9 100644 --- a/runbooks/tenant-onboarding-v2-DRAFT.md +++ b/runbooks/tenant-onboarding-v2-DRAFT.md @@ -332,13 +332,16 @@ --- BEGIN block: onboard-v2-04-network (RUN -- jumphost; L3 as app cred, checks as admin) --- CLIENT=; CA="$HOME/vault-init/vault-ca-root.pem"; ACF="$HOME/${CLIENT}-svc-appcred.txt" -TENANT_CIDR=10.20..0/24 # pick from the tenant pool; MUST NOT collide (checked below) +TENANT_CIDR= # D-074: client-choice; tenant-vs-tenant overlap ALLOWED -# 4.0 CIDR collision pre-check (operator IPAM concern; read-only as admin) +# 4.0 CIDR guard pre-check (D-074: reserved ranges + RFC1918 only; read-only as admin) +# The old cloud-wide uniqueness check is retired -- overlap with other tenants is fine. source ~/admin-openrc -if openstack subnet list -f value -c Subnet &1 | grep -qw "$TENANT_CIDR"; then - echo "*** $TENANT_CIDR IN USE -- pick another, STOP ***"; COLL=1 -else echo "$TENANT_CIDR free"; COLL=0; fi +CAPI_CIDR=$(openstack subnet show capi-mgmt-subnet -f value -c cidr &1) +source ~/openstack-caracal-ipv4/scripts/lib-net.sh +if python3 ~/openstack-caracal-ipv4/scripts/net_overlap.py "$TENANT_CIDR" "${PLANE_CIDRS[@]}" "$CAPI_CIDR" 169.254.169.254/32; then + echo "$TENANT_CIDR clear of reserved ranges"; COLL=0 +else echo "*** $TENANT_CIDR rejected (reserved-range overlap or not RFC1918) -- STOP ***"; COLL=1; fi # 4.1-4.5 build L3 as the app-cred identity [ "$COLL" = 0 ] && ( for v in $(env|awk -F= '/^OS_/{print $1}'); do unset "$v"; done diff --git a/scripts/net_overlap.py b/scripts/net_overlap.py new file mode 100644 index 0000000..235c3ff --- /dev/null +++ b/scripts/net_overlap.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +"""Tenant-CIDR reserved-range guard (D-074; DOCFIX-106). + +Usage: net_overlap.py CANDIDATE RESERVED [RESERVED ...] + +Exit 0: candidate is RFC1918 and overlaps no reserved range (prints OK). +Exit 1: rejected -- prints NOT-RFC1918 or RESERVED-OVERLAP . +Exit 2: parse error -- prints BAD-CIDR ; callers treat as fail-closed. + +Overlap is containment in EITHER direction (ipaddress.overlaps), never string +equality: the pre-D-074 exact-string guard missed partial overlaps against +ranges that must be protected, while wrongly blocking tenant-vs-tenant reuse +(allowed under D-074's hard-isolation model). + +RFC1918 is checked against the three private blocks explicitly; Python's +is_private also accepts documentation/TEST-NET and link-local ranges, which +the onboarding contract does not. +""" +import ipaddress +import sys + +RFC1918 = [ + ipaddress.ip_network("10.0.0.0/8"), + ipaddress.ip_network("172.16.0.0/12"), + ipaddress.ip_network("192.168.0.0/16"), +] + + +def main(argv): + if len(argv) < 3: + print("BAD-CIDR usage: net_overlap.py CANDIDATE RESERVED [RESERVED ...]") + return 2 + try: + cand = ipaddress.ip_network(argv[1], strict=True) + except ValueError: + print("BAD-CIDR %s" % argv[1]) + return 2 + if cand.version != 4 or not any(cand.subnet_of(b) for b in RFC1918): + print("NOT-RFC1918 %s" % argv[1]) + return 1 + for tok in argv[2:]: + try: + res = ipaddress.ip_network(tok, strict=True) + except ValueError: + print("BAD-CIDR %s" % tok) + return 2 + if cand.version == res.version and cand.overlaps(res): + print("RESERVED-OVERLAP %s" % tok) + return 1 + print("OK") + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) diff --git a/scripts/repo_lint.py b/scripts/repo_lint.py index 28cfe85..9631b91 100644 --- a/scripts/repo_lint.py +++ b/scripts/repo_lint.py @@ -16,8 +16,11 @@ L3 ghost refs scripts/.(sh|py) referenced in a runbook must exist. L4 deprecated invoking a deprecated/retired script outside a deprecation or historical context. - L5 numbering duplicate D-/DOCFIX-/BUNDLEFIX- definition headings in the - decision/changelog docs (collision guard); prints next-free. + L5 numbering duplicate D-NNN definition headings in design-decisions.md + (collision guard). Next-free numbering is ledger-scan's job + ALONE (DOCFIX-107: the old L5 next-free print disagreed with + it via three independent defects; see + docs/repo-lint-nextfree-bug-FINDING.md). L6 bare invoke runbook lines executing scripts/*.sh without a bash/source prefix (repo carries NO exec bits -- DOCFIX-069; bare form fails "Permission denied" on a fresh clone). @@ -203,18 +206,17 @@ p = R / name if not p.exists(): continue - for m in re.finditer(r"(?m)^##+\s+(D-0\d{2})\b(?!.*AMENDMENT|.*RESOLVED)", + # \d{3,} not 0\d{2}: the band-limited form goes blind past 099 + # (the same defect fixed in ledger-scan as DOCFIX-105) + for m in re.finditer(r"(?m)^##+\s+(D-\d{3,})\b(?!.*AMENDMENT|.*RESOLVED)", p.read_text(errors="replace")): heads[m.group(1)] += 1 for ident, n in sorted(heads.items()): if n > 1: fails.append("L5 %s defined %d times in design-decisions.md (collision)" % (ident, n)) - used = collections.defaultdict(set) - for p in all_text(): - for m in re.finditer(r"\b(D|DOCFIX|BUNDLEFIX)-(0\d{2})\b", p.read_text(errors="replace")): - used[m.group(1)].add(int(m.group(2))) - nf = ", ".join("%s-%03d" % (k, max(v) + 1) for k, v in sorted(used.items()) if v) - print(" [info] L5 next-free identifiers: %s" % (nf or "n/a")) + # next-free print REMOVED (DOCFIX-107): it was wrong on all three counters + # (band-limited regex, mention-counting incl. pointer lines, tests/ fixture + # ingestion) and collided with ledger-scan, the single numbering authority. # ---- L7 clientdocs sweep-on-change receipt ---- if cdir.is_dir(): diff --git a/scripts/tenant-onboard.sh b/scripts/tenant-onboard.sh index d90c85f..1359bc0 100644 --- a/scripts/tenant-onboard.sh +++ b/scripts/tenant-onboard.sh @@ -156,10 +156,21 @@ } stage4(){ # tenant L3 via app cred - [ -n "$TENANT_CIDR" ] || die "set TENANT_CIDR (e.g. 10.20.24.0/24)" + [ -n "$TENANT_CIDR" ] || die "set TENANT_CIDR (client choice; fallback default 10.100.0.0/24 per D-074)" admin_env - local SNL; SNL=$(openstack subnet list -f value -c Subnet &1 || true) - grep -qw "$TENANT_CIDR" <<<"$SNL" && die "CIDR $TENANT_CIDR in use" # capture-then-test: the raced form let a COLLIDING CIDR through (guard failed open) + # D-074 guard (replaces the exact-string cloud-wide check): tenant-vs-tenant + # overlap is ALLOWED under the hard-isolation model; reject ONLY (a) non-RFC1918 + # and (b) real containment overlap -- either direction, net_overlap.py -- against + # the reserved ranges: PLANE_CIDRS (lib-net.sh), the capi-mgmt tenant net + # (D-035; resolved live by stable name, fail-closed on lookup miss), metadata. + # capture-then-test throughout (the raced form failed open once already). + local SDIR; SDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + # shellcheck disable=SC1091 + source "$SDIR/lib-net.sh" + local CAPI_CIDR; CAPI_CIDR=$(openstack subnet show capi-mgmt-subnet -f value -c cidr &1 || true) + [[ "$CAPI_CIDR" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]] || die "capi-mgmt-subnet CIDR lookup failed: '$CAPI_CIDR' (guard fails closed)" + local GOUT; GOUT=$(python3 "$SDIR/net_overlap.py" "$TENANT_CIDR" "${PLANE_CIDRS[@]}" "$CAPI_CIDR" "169.254.169.254/32" 2>&1 || true) + [ "$GOUT" = "OK" ] || die "CIDR $TENANT_CIDR rejected: ${GOUT:-guard-error} (reserved ranges + RFC1918 only; tenant-vs-tenant overlap is allowed per D-074)" local ACF="$OUT/${CLIENT}-svc-appcred.txt" echo "== stage4: tenant L3 (net/subnet/router/ext-gw) via app cred ==" ( for v in $(env|awk -F= '/^OS_/{print $1}'); do unset "$v"; done diff --git a/tests/tenant-onboard/run-tests.sh b/tests/tenant-onboard/run-tests.sh index 59623bd..aa56a26 100644 --- a/tests/tenant-onboard/run-tests.sh +++ b/tests/tenant-onboard/run-tests.sh @@ -29,6 +29,7 @@ #!/usr/bin/env bash case "\$*" in *"subnet list"*) cat "\$FIXDIR/subnets.txt" ;; + "subnet show capi-mgmt-subnet -f value -c cidr") cat "\$FIXDIR/capi-cidr.txt" ;; "domain show testco -f value -c id") echo "$DOMID" ;; "token issue -f value -c project_id") echo "$PID" ;; "application credential show testco-svc-cred -f value -c id") cat "\$FIXDIR/appcred-id.txt" ;; @@ -73,9 +74,9 @@ chmod 600 "$d"/* 2>/dev/null || true } -run_stage(){ # run_stage -> OUT/RC +run_stage(){ # run_stage [cidr] -> OUT/RC OUT=$( cd "$TMP" && env HOME="$1" FIXDIR="$2" PATH="$BIN:$PATH" \ - TENANT_CIDR="10.20.24.0/24" \ + TENANT_CIDR="${4:-10.20.24.0/24}" \ bash "$REPO/scripts/tenant-onboard.sh" testco "$3" 2>&1 ); RC=$? } check(){ # check