#!/usr/bin/env python3 """D-77 — l'underlay tient dans la BANDE BASSE du supernet de son propre site. Ce que ce test garde, et pourquoi il existe. La regle « underlay dans la bande basse » n'est sure que parce que les zones d'un tenant commencent a `OCTET_ZONE + 1`. C'est une propriete de `inventory_rules`, pas une place qu'on aurait constatee libre un jour : si `OCTET_ZONE` bougeait sans que la borne suive, la validation continuerait a dire « oui » en laissant l'underlay recouvrir les zones — et personne ne le verrait avant que deux machines ne se disputent une adresse. Le test derive donc sa frontiere de la MEME constante que le code, et verifie les trois cas qui comptent, y compris ceux ou un prefixe FRANCHIT la frontiere (un /19 couvre les octets 0 a 31 : il deborde, meme s'il commence dans la bande basse). """ import sys from pathlib import Path RACINE = Path(__file__).resolve().parent.parent.parent sys.path.insert(0, str(RACINE / "scripts")) import underlay as u # noqa: E402 from inventory_rules import OCTET_ZONE # noqa: E402 SUPERNETS = ["10.11.0.0/16", "10.17.0.0/16"] # deux sites : index 11 et 17 MIEN = 11 def _erreurs(sous: str, index: int | None = MIEN) -> list[str]: site = {"reseaux": [{"nom": "g", "vlan": 10, "sous_reseau": sous}]} if index is not None: site["index"] = index return [e for e in u.valider(site, tenants_vlans=set(), tenants_supernets=SUPERNETS) if "deborde" in e or "chevauche le supernet" in e] def test_la_borne_derive_de_la_regle_des_zones(): """La frontiere n'est pas 16 en dur : elle suit `OCTET_ZONE`.""" assert u.PREMIER_OCTET_ZONE == OCTET_ZONE + 1 def test_bande_basse_de_son_propre_supernet_acceptee(): for sous in ("10.11.0.0/24", "10.11.4.0/24", "10.11.5.0/24", "10.11.15.0/24"): assert _erreurs(sous) == [], f"{sous} devrait etre conforme (bande basse)" def test_bande_des_zones_refusee(): for sous in (f"10.11.{OCTET_ZONE + 1}.0/24", "10.11.18.0/24", "10.11.16.0/20"): assert _erreurs(sous), f"{sous} devrait etre REFUSE (bande des zones)" def test_un_prefixe_qui_franchit_la_frontiere_est_refuse(): """Le piege : il COMMENCE dans la bande basse et deborde. Un test qui ne regarderait que le premier octet le laisserait passer.""" for sous in ("10.11.0.0/19", "10.11.0.0/16"): assert _erreurs(sous), f"{sous} couvre au-dela de {OCTET_ZONE} : a refuser" def test_supernet_d_un_autre_site_refuse(): """C'est ce qui empeche deux sites d'etre relies — l'erreur la plus couteuse.""" assert _erreurs("10.17.0.0/24"), "le supernet d'un autre site doit etre refuse" def test_hors_de_tout_supernet_accepte(): """Le stockage (192.168.x, identique partout) et l'heritage 10.0.x avant migration.""" for sous in ("192.168.20.0/24", "192.168.31.0/24", "10.0.0.0/24"): assert _erreurs(sous) == [], f"{sous} est hors des supernets : conforme" def test_sans_index_on_retombe_sur_la_regle_stricte(): """Un underlay qui n'a pas encore migre ne declare pas d'index : aucun chevauchement n'est alors tolere, ce qui reste le comportement sur.""" assert _erreurs("10.11.0.0/24", index=None), \ "sans index, tout chevauchement doit etre refuse" if __name__ == "__main__": n = 0 for nom, fn in sorted(globals().items()): if nom.startswith("test_") and callable(fn): fn() n += 1 print(f"OK — {n} test(s) D-77 (bande basse, frontiere derivee d'OCTET_ZONE={OCTET_ZONE}).")