#!/usr/bin/env python3 """Un lien de l'underlay peut etre un TUNNEL : ni VLAN, ni port physique. POURQUOI (2026-10-13). Le site de TechnoLibre n'a qu'une adresse DHCP ; ses adresses fixes sont louees sur un VPS (le relais) et lui arrivent par un tunnel WireGuard. Ce lien porte un sous-reseau de liaison mais aucune etiquette — la validation exigeait un `vlan` ou `segment_physique`, et l'aurait refuse. `tunnel: wireguard` le dit. Sur un underlay SYNTHETIQUE (aucun site requis) : - un tunnel declare passe ; - un type de tunnel inconnu est refuse (faute de frappe, pas un tunnel) ; - `tunnel` et `vlan` ensemble sont refuses ; - sans `tunnel` ni `vlan`, le lien est refuse comme avant (temoin : la garde n'a pas ete relachee pour tout le monde) ; - le role d'hote `relais` est connu, un role mal ecrit ne l'est pas. """ from __future__ import annotations import copy import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) import underlay as U # noqa: E402 BASE = { "index": 31, "reseaux": [ {"nom": "management", "nature": "fabric", "segment_physique": True, "sous_reseau": "10.31.0.0/24", "passerelle": "10.31.0.1"}, {"nom": "relais", "nature": "fabric", "fabric": "relais", "tunnel": "wireguard", "sous_reseau": "10.31.60.0/30", "mtu": 1420}, ], "hotes": [ {"nom": "requin", "reseau": "management", "ip": "10.31.0.1", "role": "frontiere"}, {"nom": "requin", "reseau": "relais", "ip": "10.31.60.2", "role": "frontiere"}, {"nom": "relais", "reseau": "relais", "ip": "10.31.60.1", "role": "relais"}, ], } def _erreurs(modif=None, sur="relais") -> list[str]: u = copy.deepcopy(BASE) if modif: modif(next(r for r in u["reseaux"] if r["nom"] == sur), u) return [e for e in U.valider(u) if "relais" in e or "relai" in e] def main() -> int: cas = [ ("tunnel declare", None, False), ("type de tunnel inconnu", lambda r, u: r.__setitem__("tunnel", "wireguardd"), True), ("tunnel et vlan ensemble", lambda r, u: r.__setitem__("vlan", 60), True), ("ni tunnel ni vlan (temoin)", lambda r, u: r.pop("tunnel"), True), ("role relais mal ecrit", lambda r, u: next(h for h in u["hotes"] if h["nom"] == "relais").__setitem__("role", "relai"), True), ] echecs = 0 for nom, modif, doit_refuser in cas: e = _erreurs(modif) if bool(e) != doit_refuser: echecs += 1 print(f"ECHEC {nom} : {'accepte' if not e else e}") else: print(f"OK {nom}" + (f" — refuse : {e[0][:70]}…" if e else "")) return 1 if echecs else 0 if __name__ == "__main__": sys.exit(main())