From 29148831bf5aea9a3437d71355c10b7690c7eba4 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Tue, 18 Aug 2026 14:02:21 -0400 Subject: [PATCH] CHANGELOG : les trois entrees manquantes des 13 et 14 aout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regle 5 — « rien n'est pret sans l'entree CHANGELOG correspondante ». Trois commits etaient passes sans la leur, dont le plus instructif de la serie. - 2026-08-14, la PORTEE de la frontiere : `underlay.tenants`, le defaut silencieux qui aurait pose trente objets de Chezlepro sur la frontiere de Technolibre. La note dit aussi ce qui n'est PAS corrige : `devis_sdn` et `devis_reseau` partent du meme `decouvrir()`. - 2026-08-13, le formulaire encode : `hasPost()`, le `{"result":"failed"}` NU, et la regle qui reste vraie quelle que soit la version — un refus sans validation n'est pas un refus, c'est une absence. Le point ouvert (re-eprouver apres mise a jour) est ecrit. - 2026-08-13, le runbook d'implantation sur un site neuf : les six phases, et surtout ce que lui seul porte (adressage cible d'emblee, le piege `make flux`, le site a un noeud). Aucun code touche. make test 0 ; prouver 37/37 (invocation directe). Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f0830f..b0f86ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,144 @@ # CHANGELOG — Set-OPS +## 2026-08-14 — Une frontière ne police que les tenants de **son** site + +Premier `make frontiere-plan` sur le second site. Le devis voulait poser sur la frontière +de Technolibre les règles **et** les routes de **Chezlepro** : trente objets de plus, dont +six routes vers des sous-réseaux `10.17.x` qui n'existent pas là-bas. + +### Le défaut est de portée, et il est silencieux + +Les devis partaient de `devis_reseau.decouvrir()`, qui rend **toute la fédération** — tout +dossier frère portant une nomenclature avec un index. C'était juste tant qu'il n'y avait +qu'un site : l'hébergeur unique portait bien tous les tenants. Dès le second, c'est faux. + +Et rien ne l'aurait dit. Le boîtier aurait **accepté** ces trente objets ; aucun n'aurait +jamais correspondu à un paquet ; aucune erreur, aucun avertissement. Une politique qui a +l'air complète et ne protège rien — encore le **chèque vert sur un périmètre vide**. + +### Le correctif : l'hébergeur nomme ce qu'il porte + +```yaml +underlay: + tenants: [OPS-Technolibre] # les tenants HÉBERGÉS ici, pas la fédération +``` + +`devis_opnsense` s'y limite (`underlay.tenants_du_site()`). **Clé absente = ancien +comportement**, toute la fédération : un site unique n'a rien à déclarer, c'est le second +qui doit se nommer. Un nom déclaré qu'aucun dossier frère ne fournit est **signalé**, pas +ignoré silencieusement ; et si le filtre ne retient aucun tenant connu, le devis refuse +plutôt que de rendre une politique vide. + +**Même hypothèse ailleurs, non corrigée** : `devis_sdn` et `devis_reseau` partent du même +`decouvrir()`. À traiter le jour où ils serviront sur un second site — dit ici pour ne pas +le redécouvrir. + +### Au passage, un défaut du document écrit la veille + +Le squelette d'`underlay.yml` d'[`implanter-un-tenant-sur-un-site.md`](docs/implanter-un-tenant-sur-un-site.md) +omettait `index`. Sans cette clé, `make underlay` refuse le réseau de gestion en le prenant +pour le supernet d'un **autre** site : message déroutant, cause triviale. Trouvé en s'en +servant, moins de vingt-quatre heures après l'avoir écrit. + +`prouver` 37/37, `make test` 0. + +> **Ce qui marche avec un seul écosystème n'est pas prouvé.** Comme les six défauts moteur +> qu'avait révélés le second tenant, celui-ci n'existait que parce qu'un second **site** +> existe enfin. Une hypothèse implicite ne se voit qu'au moment où elle cesse d'être vraie. + + +## 2026-08-13 — La frontière poste en formulaire encodé : `hasPost()` et le `failed` nu + +Mesuré sur un OPNsense **24.7** (version ancienne, mise à jour depuis) : **toute écriture** +du moteur y échouait. Alias, règles, NAT, routes — `make frontiere-appliquer` n'aurait rien +posé sur ce boîtier. Ce n'est donc pas un défaut universel du moteur : il écrit correctement +sur la frontière de Chezlepro, plus récente. C'est un problème de **compatibilité**, et le +correctif vaut surtout comme garantie de **portabilité** — le jour où l'on arrive sur un +site dont on ne choisit pas le firmware, ce qui est exactement le cas. + +### Le symptôme mérite d'être retenu, lui, quelle que soit la version + +Le contrôleur d'OPNsense lit ses champs avec `hasPost()`. Si le corps arrive en +`application/json` et que le boîtier ne le décompose pas en variables de POST, ce test est +**faux** : + +``` +HTTP 200 {"result":"failed"} ← nu : aucune redirection, aucune validation +``` + +Le contrôleur ne dit pas quel champ manque, **parce que de son point de vue il n'y avait +aucun champ**. + +Trois fausses pistes avant la bonne : valeur invalide (un corps **vide** échouait pareil), +racine de payload erronée (elle était juste), privilèges de la clé (la lecture passait). Ce +qui a tranché : *un corps vide aurait dû produire des validations.* Leur absence disait que +le contrôleur n'avait rien reçu. + +### Le correctif + +`Frontiere` poste désormais `racine[champ]=valeur` — la forme que poste **l'interface web +elle-même**. Aucune version d'OPNsense ne la refuse, alors que le JSON dépend du boîtier. +Tous les corps du moteur sont des dicts plats de chaînes (alias, `rule`, `route`) : un seul +niveau d'imbrication suffit. + +**Éprouvé sur le boîtier, dans les deux sens** : `addItem` d'un alias sonde → `saved`, +`delItem` → `deleted`, aucune trace laissée, lecture intacte (11 alias). **Reste ouvert** : +ré-éprouver après la mise à jour, pour vérifier que le formulaire reste bon sur la version +récente. + +> **Un `failed` sans validation n'est pas un refus, c'est une absence.** Quand un contrôleur +> ne nomme aucun champ fautif, cesser de chercher le mauvais champ : il n'a rien reçu. + + +## 2026-08-13 — Implanter un tenant sur un site neuf : le runbook de l'intervention + +Le dépôt couvrait déjà « l'hébergeur prépare son matériel » et « un tenant **vivant** change +d'hébergeur, sans coupure ». Il manquait le troisième cas, qui est celui qu'on s'apprête à +faire : un tenant dont le plan existe déjà **prend corps sur un site qui n'a jamais rien +porté**. Rien à migrer, rien à interrompre — donc ni la séquence de gel/bascule de +`migration-tenant.md`, ni le bootstrap du QUICKSTART. + +[`docs/implanter-un-tenant-sur-un-site.md`](docs/implanter-un-tenant-sur-un-site.md), +**six phases**, chacune fermée par une commande qui **interroge le système** : + +``` +0 bureau index du site = index du tenant, dépôt hébergeur, gabarit, voûte +1 reconnaître make underlay, make placement-plan +2 frontière make frontiere-plan +3 gabarit convertir en template — un clone de VM vivante en ferait 14 copies +4 composer les DEUX symlinks (D-80) + les 4 valeurs de placement +5 matérialiser make sdn-appliquer, puis make reconstruire +6 recette devis, restauration éprouvée, supervision +``` + +### Ce que le runbook porte et qu'aucun autre document ne dit + +- **Un site neuf se bâtit d'emblée dans l'adressage cible** (D-77/D-78). Le site historique + est encore en `10.0.x` et migrera par les runbooks §6 ; sur un site vierge, la cible ne + coûte rien. Deux sites en `10.0.0.0/24` rendraient la **reprise mutuelle impossible** : + deux plans de gestion identiques ne peuvent pas s'atteindre. +- **L'ordre de `reconstruire`, ligne à ligne**, dont le piège `make flux` : sans lui, + nftables tombe en `policy drop` **sans aucune règle** — la flotte monte, SSH répond, et + tout le reste est mur (trouvé le 2026-08-10). +- **Un site à un seul nœud** : ce nœud est aussi nœud de sortie, aucun pont ne peut être + partiel, aucune haute disponibilité. À dire, pas à laisser supposer. +- **PVE 9 n'a jamais été éprouvé ici** : tout écart est inconnu jusqu'à mesure. +- **« Ce qui n'est PAS fait en repartant »** — resserrer le compte d'API, le lien + inter-sites, le gabarit des deux côtés, la voûte hors de son propre site. + +**En annexe**, les squelettes d'`underlay.yml` et de `proxmox-hebergeur.yml` pour un site à +un nœud, à remplir depuis la **reconnaissance** et jamais de mémoire — c'est en recopiant +des listes chez chaque tenant qu'elles avaient divergé. + +Sixième porte dans la table de routage du README. Les 21 cibles `make` citées ont été +vérifiées comme existantes. `prouver` 37/37 (dont P34 : 40 documents déclarent leur +lecteur), `make test` 0. + +> **La règle qui commande tout l'ordre du document** : *rien n'est fait tant que ce n'est +> pas mesuré sur place.* Une valeur transmise par courriel, une liste relevée dans +> l'interface web, un `vmbr` cité de mémoire — chacun des trois a déjà produit une panne ici. + + ## 2026-08-13 — La machine d'épreuve jetable existait, et n'était écrite nulle part L'exploitant a découvert par hasard, en creusant l'intrant « pont réseau », qu'on peut