Set-OPS-Public/scripts/tests/test_underlay_tunnel.py
Daniel Allaire f9e45b1676 relais : la face publique d'un site sans adresse fixe, et le site de reprise de TechnoLibre
Le site de TechnoLibre n'a qu'une adresse DHCP. Trois adresses fixes sont louees sur un VPS
(le relais), qui repond a l'ARP pour elles et les route en /32 dans un tunnel WireGuard que la
frontiere initie. Aucune traduction : l'adresse du client arrive intacte.

- underlay.py : `tunnel: wireguard` dispense de VLAN ; role d'hote `relais`.
- devis_opnsense.py : `opnsense_face_publique`. Les entrees publiques s'y posent avec
  reply-to ; les sorties des locataires du pool passent par le relais ; une redirection n'y
  vise plus `wanip`. Le devis de Chezlepro est identique au caractere pres.
- appliquer_opnsense.py : replyto et gateway transmis et dans l'identite (seulement s'ils
  existent) ; le NAT sortant en mode automatic arrete l'application au lieu de dupliquer.
- role serveur_relais, inventorie depuis la carte comme un hyperviseur ; cle privee dans la
  voute du site. Deploye, idempotent.
- site_inventaire.py : les hyperviseurs ne sont plus filtres sur 192.168.11. ; site-appliquer
  charge la voute designee par SETOPS_UNDERLAY ; voute.py n'exige plus d'un locataire un
  secret du site.
- prouver.py : P67 lit le plan par underlay.plan_site() ; P53 couvre la face publique.
- Tests : test_underlay_tunnel, test_face_publique_relais, test_mode_nat_sortant.

95 preuves (make verifier), make test passe. CHANGELOG 144 et 145.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:20:04 -04:00

71 lines
2.7 KiB
Python

#!/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())