journal : les cinq commits du 27 n'avaient pas d'entree
Some checks are pending
verifier / verifier (push) Waiting to run
Some checks are pending
verifier / verifier (push) Waiting to run
La regle 5 exige une entree de CHANGELOG par changement. Les cinq commits du 2026-08-27 n'en ont aucun : la session s'est interrompue avant. Trois entrees les couvrent — P52 (materialiser sans entrer chez le tenant), P51 (les quatre defauts de portabilite reveles par le runner, epinglage compris) et P50 (le devis de la frontiere sait refuser sans consigner). La carte comptait 28 pieces d'audit ; le rapport du jour en fait 29. P48 l'a vu, comme la veille — c'est exactement ce qu'on lui demande. make prouver : CONFORME, 52 OK, 0 echec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
This commit is contained in:
parent
6fe62f74e1
commit
35853ff5fb
3 changed files with 213 additions and 1 deletions
124
CHANGELOG.md
124
CHANGELOG.md
|
|
@ -1,5 +1,129 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-08-27 — P52 : matérialiser n'exige pas d'entrer chez le tenant
|
||||
|
||||
**52 preuves.** `creer-vm` confirmait son succès en attendant une réponse SSH. Le runner du
|
||||
SITE matérialise le terrain de **tous** les tenants, mais la frontière lui refuse d'entrer
|
||||
chez eux — c'est le sens même de leur isolation. La première VM qu'il a créée a donc été
|
||||
déclarée en échec après 600 secondes alors qu'elle tournait, avec l'adresse exacte que le
|
||||
plan lui destinait :
|
||||
|
||||
```
|
||||
Attente de SSH sur ops-01 ............ ECHEC: injoignable apres 600s.
|
||||
```
|
||||
|
||||
**La tentation était d'ouvrir le SSH du runner vers tous les tenants.** Ça aurait réparé la
|
||||
mesure en détruisant ce qu'elle protège : une machine capable d'entrer chez chaque locataire
|
||||
est précisément ce que cette architecture refuse d'avoir.
|
||||
|
||||
L'agent invité répond sans rien ouvrir — l'API des hyperviseurs est déjà le flux par lequel
|
||||
la VM vient d'être créée, donc qui peut la créer peut la voir naître — et il **prouve
|
||||
davantage**. « Quelque chose écoute sur le port 22 » ne dit ni quel système a démarré, ni si
|
||||
cloud-init a posé la bonne adresse. Sur `ops-01` :
|
||||
|
||||
```
|
||||
10.17.19.41 portee sur asgard — Debian GNU/Linux 13 (trixie) 6.12.101
|
||||
```
|
||||
|
||||
Ses échecs distinguent deux causes très différentes : « la machine démarre mais rapporte une
|
||||
**autre** adresse — cloud-init, ou le pont sur lequel elle est posée », et « introuvable sur
|
||||
la fabric ».
|
||||
|
||||
**Attendre la disponibilité a changé de main.** Guetter cloud-init et la libération de dpkg
|
||||
appartient à qui va **configurer** : `deployer` le fait désormais, là où il se contentait
|
||||
d'un `ping` unique. Il y gagne ce qu'il n'avait pas — attendre le verrou APT, faute de quoi
|
||||
la première couche échouait dessus. Contrepartie assumée : un nom d'hôte erroné patiente au
|
||||
lieu d'échouer vite ; échouer vite interdirait de chaîner création et déploiement, le geste
|
||||
central d'une reconstruction.
|
||||
|
||||
*Une preuve qui exige un pouvoir que l'architecture refuse ne mesure pas le système : elle
|
||||
mesure ce qu'il faudrait casser pour la satisfaire.*
|
||||
|
||||
## 2026-08-27 — P51 : quatre défauts de portabilité, révélés par le runner
|
||||
|
||||
**51 preuves.** Première matérialisation d'une VM de tenant depuis le runner du SITE. Elle a
|
||||
échoué quatre fois d'affilée, sur quatre dépendances que le moteur ne déclarait nulle part.
|
||||
Chacune fonctionnait chez le mainteneur pour une raison **différente**, et aucune de ces
|
||||
raisons n'existe sur une autre machine.
|
||||
|
||||
**1. Versions des collections.** `requirements.yml` les nommait sans les épingler. Le runner
|
||||
a reçu `community.general` 13.3.0 quand le poste porte la 10.3.0 — et la 11 a retiré les
|
||||
modules Proxmox de cette collection (ils vivent désormais dans `community.proxmox`).
|
||||
|
||||
```
|
||||
ERROR! couldn't resolve module/action 'community.general.proxmox_pool'
|
||||
```
|
||||
|
||||
*Une dépendance non épinglée n'est pas une dépendance, c'est un pari sur l'état d'Internet à
|
||||
la date du déploiement.*
|
||||
|
||||
**2. Installation en avant.** `ansible-galaxy` ne rétrograde pas : déclarer la 10.3.0 ne
|
||||
suffisait pas à défaire une 13.3.0 déjà posée. `--force`. Un poste peut être en **avance**,
|
||||
pas seulement en retard, et le dépôt doit faire autorité dans les deux sens.
|
||||
|
||||
**3. Emplacement.** Le `Makefile` pose `ANSIBLE_HOME ?= $(CURDIR)/.ansible` : sous `make`,
|
||||
Ansible ne lit **que** `<moteur>/.ansible/collections`. Le rôle déposait dans
|
||||
`<racine>/.ansible/collections` — à côté, jamais lu. Invisible chez le mainteneur, où les
|
||||
collections viennent du paquet système, toujours dans le chemin quel que soit `ANSIBLE_HOME`.
|
||||
Et le garde-fou d'installation suivait le **dépôt des archives** : changer la destination ne
|
||||
le déclenchait pas. Il mesure désormais la destination — même piège qu'au 2026-08-24, déplacé
|
||||
d'un cran.
|
||||
|
||||
**4. Bibliothèques Python.** Le venv recevait `ansible-core` et `pyyaml`, écrits en dur. Les
|
||||
modules Proxmox tournent `delegate_to: localhost` et exigent `proxmoxer` **sur le
|
||||
contrôleur**.
|
||||
|
||||
```
|
||||
La bibliotheque Python proxmoxer est absente
|
||||
```
|
||||
|
||||
Né d'ici : `requirements-python.txt`, avec sa frontière écrite — il ne déclare **que** ce qui
|
||||
tourne sur le contrôleur. `python-ldap` et `psycopg2` s'exécutent sur leurs cibles ; le poste
|
||||
du mainteneur ne les a pas et la flotte se déploie, ce qui prouve que la ligne est au bon
|
||||
endroit.
|
||||
|
||||
**P51** garde les trois faiblesses de cette famille : une dépendance utilisée sans être
|
||||
déclarée (le défaut du 2026-08-24, `ansible.posix`), une dépendance déclarée sans version, et
|
||||
`proxmoxer` absent alors que des playbooks Proxmox existent. La preuve ne lit que les fichiers
|
||||
de **tâches** : un `defaults/main.yml` porte `net.ipv4.ip_forward`, qu'un motif trop large
|
||||
prendrait pour un module.
|
||||
|
||||
**Résultat :** `ops-01` matérialisée par le runner du site. L'agent invité rapporte
|
||||
`eth0 10.17.19.41/24`, Debian 13 trixie — l'adressage dérivé du plan, appliqué.
|
||||
|
||||
**Migration connue, pas faite :** passer les quatre modules Proxmox à `community.proxmox`
|
||||
permettra de suivre `community.general` au-delà de la 11.
|
||||
|
||||
*Un seul exécutant masque ces écarts indéfiniment ; un second les révèle tous en une soirée.
|
||||
Même mécanique que le second tenant en août.*
|
||||
|
||||
## 2026-08-27 — P50 : le devis de la frontière sait refuser SANS consigner
|
||||
|
||||
**50 preuves.** L'outil ne savait qu'**autoriser** — `"action": "pass"` était en dur dans
|
||||
l'émetteur. Une règle de silence ne pouvait donc pas naître du dépôt, et j'en avais posé deux
|
||||
à la main sur le boîtier : exactement ce que ce projet refuse.
|
||||
|
||||
**Ce qui l'a motivé.** Le journal de la frontière écrivait 982 000 entrées par jour, dont
|
||||
82 % un balayage Internet contre le port VNC et le reste du bavardage de découverte du réseau
|
||||
local. Sa fenêtre utile était tombée à **quarante-quatre secondes**. J'y ai cherché la trace
|
||||
d'un flux du site vers les hyperviseurs, je n'ai rien trouvé, et j'en ai conclu à tort
|
||||
qu'aucune règle ne bloquait. **Un journal noyé ment aussi sûrement qu'un journal mort.**
|
||||
Mesuré après déclaration : ~20 700/jour.
|
||||
|
||||
Une règle de silence ne change **aucun** comportement : ce qu'elle vise était déjà refusé par
|
||||
le défaut. Elle ne supprime qu'une trace que personne ne lira.
|
||||
|
||||
**Trois pièces.** `cle_regle` accepte une action sans changer d'un octet la clé des règles
|
||||
`pass` déjà posées — l'ajout naïf d'un champ les aurait toutes détruites pour les recréer à
|
||||
l'identique, sur la frontière, en production ; le plan l'a confirmé : 7 à créer, 0 à retirer,
|
||||
121 inchangées. `_corps_regle` lit l'action, la consignation et la **séquence** depuis le
|
||||
devis : la séquence est ce qui rend un `block` sûr, puisque OPNsense évalue en `quick` et
|
||||
qu'un blocage large émis avant les `pass` fermerait courrier, web et accès distant.
|
||||
`devis_opnsense` lit `opnsense_silences` et en fabrique règles et alias, **motif compris** —
|
||||
une règle `block` muette sans raison écrite est indiscernable d'un oubli.
|
||||
|
||||
P50 garde ces deux dangers : un silence en séquence 1 échoue, un silence sans motif échoue.
|
||||
|
||||
## 2026-08-26 — P49 : le registre des flux avait dérivé sans bruit
|
||||
|
||||
**48 preuves.** `docs/registre-flux.md` est **généré** depuis les `roles/*/meta/flux.yml`,
|
||||
|
|
|
|||
88
docs/audit/preuve-2026-08-28.md
Normal file
88
docs/audit/preuve-2026-08-28.md
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Preuve de conformite — Set-OPS — 2026-08-28
|
||||
|
||||
> Genere par `make prouver` (`scripts/prouver.py`). **Rejouable** : relancer
|
||||
> reproduit ce rapport. Chaque preuve rejoue l'outillage existant du depot ;
|
||||
> aucune validation n'est reimplementee ici. Voir le mode d'emploi :
|
||||
> [`docs/audit/README.md`](README.md), et le registre trace :
|
||||
> [`docs/audit/affirmations.md`](affirmations.md).
|
||||
|
||||
- **Instance** : `instance` — inventaire `instance/inventories/principal/hosts.yml`
|
||||
- **Verdict** : ✅ CONFORME (52 OK · 0 echec · 0 saute)
|
||||
|
||||
## Preuves
|
||||
|
||||
| # | Preuve | Affirmations | Statut | Detail |
|
||||
|---|---|---|---|---|
|
||||
| P01 | Lint (ansible-lint) | AFF-006 | ✅ OK | [0m[0m |
|
||||
| P02 | Tests unitaires (inventory_host) | — | ✅ OK | >>> le verrou tient : aucune VM n'aurait ete touchee |
|
||||
| P03 | Diff-vide du plan — TOUTES les instances | AFF-001, AFF-004, AFF-030, AFF-031, AFF-032 | ✅ OK | 4 instance(s) verifiee(s) — OPS-Chezlepro-lab, OPS-Chezlepro, OPS-Technolibre, OPS-Patient0 : plan et inventaire applique coincident. |
|
||||
| P04 | Groupes <-> playbooks homonymes | AFF-008 | ✅ OK | |
|
||||
| P05 | Dependances causales de groupes | AFF-009, AFF-084 | ✅ OK | |
|
||||
| P06 | Validateurs de registres (serveurs/apps/bases/domaines) | AFF-003 | ✅ OK | Registre des domaines valide. |
|
||||
| P07 | GUI (node --check) | AFF-033 | ✅ OK | JS du GUI : syntaxe valide (node --check). |
|
||||
| P08 | Orchestration (couches + graphe) | AFF-070 | ✅ OK | Orchestration coherente : 37 groupes classes, aucun cycle, aucune arete en arriere. |
|
||||
| P09 | Flux reseau (schema + matrice) | AFF-071 | ✅ OK | Flux coherents : 35 rôles, 92 flux, schéma + matrice OK. |
|
||||
| P10 | Handlers <-> notify | AFF-034, AFF-035 | ✅ OK | Tout notify pointe vers un handler du meme role (49 roles). |
|
||||
| P11 | Syntaxe des playbooks (--syntax-check) | AFF-083 | ✅ OK | playbook: playbooks/proxmox/cloner_vm_debian.yml |
|
||||
| P12 | Existence des runbooks cites | AFF-010, AFF-011, AFF-012, AFF-083 | ✅ OK | 17/17 runbooks/registres cites presents. |
|
||||
| P13 | Invariants structurels/doctrinaux | AFF-015, AFF-022, AFF-037, AFF-038, AFF-062 | ✅ OK | LICENSE, socle dossier, pas de couches paralleles, SSH clef-only, nftables off : OK. |
|
||||
| P14 | Pas de chemin lab/ code en dur | AFF-097 | ✅ OK | Aucun chemin instance/inventories/lab/group_vars code en dur. |
|
||||
| P15 | Modele public socle valide | AFF-022, AFF-099 | ✅ OK | Modele public socle : domaines/serveurs/applications/bases valides. |
|
||||
| P16 | Inventaire Ansible complet (--list) | AFF-030 | ✅ OK | 15 hotes, 36 groupes (inventaire dechiffre et parse). |
|
||||
| P17 | Tous les modeles valident (registres + underlay) | AFF-022, AFF-099 | ✅ OK | Les 1 modele(s) decouvert(s) valident. |
|
||||
| P18 | Gabarit de voute complet | AFF-026 | ✅ OK | Gabarit de voute complet : 23 secret(s) exige(s), tous presents. Voute reelle : 25 cle(s), aucun manque. |
|
||||
| P19 | Le GUI couvre le schema du plan | AFF-002, AFF-095 | ✅ OK | GUI : les 28 champ(s) des plans reels sont editables (2 plan(s) inspecte(s)), registres toleres : nomenclature. |
|
||||
| P20 | Adressage 100% derive du seed (aucun stocke) | AFF-001, AFF-003 | ✅ OK | 2 nomenclature(s) : adressage 100% derive du seed index. |
|
||||
| P21 | Federation : aucun index en collision | AFF-102 | ✅ OK | Federation coherente : 3 instance(s) federee(s), aucun index en collision. |
|
||||
| P22 | Plan de recette a jour (genere du wiki) | AFF-002 | ✅ OK | Plan de recette à jour (22 sections). |
|
||||
| P23 | Underlay sans collision avec la plage tenant | AFF-103 | ✅ OK | Underlay conforme : 11 reseau(x), aucune collision avec la plage tenant. |
|
||||
| P24 | Frontiere nord/sud : acces d'administration declare | AFF-104 | ✅ OK | note : serveur_powerdns declare un port `derive` que le plan du site ne resout pas — aucune regle emise. |
|
||||
| P25 | Pare-feu Proxmox : est-ouest intra-tenant derive | AFF-107 | ✅ OK | CONFORME : pare-feu Proxmox, 3 tenant(s), 50 groupe(s), 79 regle(s). |
|
||||
| P26 | Integrations universelles : aucun hote laisse de cote | AFF-108 | ✅ OK | 15 hote(s) x 5 integration(s) universelle(s) : aucune lacune, aucune recopie (0 exemption(s) derivee(s) du service rendu). |
|
||||
| P27 | Propriete des intrants : hebergeur et tenant separes | AFF-109 | ✅ OK | 8 cle(s) de cluster chez l'hebergeur, aucune recopiee dans les group_vars du tenant. |
|
||||
| P28 | Pools Proxmox : un par tenant, sans collision | AFF-110 | ✅ OK | CONFORME : 3 pool(s) Proxmox, 35 VM placee(s), aucun nom ni VMID en collision. |
|
||||
| P29 | Authentification : chaque role declare sa position | AFF-111 | ✅ OK | 29 role(s) serveur declares (interne-sans-auth 2, ldap-direct 2, sans-auth-humaine 18, socle-identite 2, web-sso 5) ; 2 lacune(s) nommee(s) : serveur_loki, serv |
|
||||
| P30 | SDN EVPN : zones, VNets et sous-reseaux derives | AFF-112 | ✅ OK | CONFORME : SDN EVPN, 3 zone(s), 15 VNet(s), 15 sous-reseau(x), aucune collision. |
|
||||
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 51 scripts expliques et atteignables, 104 cibles make documentees, 61 roles avec README. |
|
||||
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 40 exigence(s) de role, toutes satisfaites (126 cle(s) declaree(s) par l'instance). |
|
||||
| P33 | Aucune collision de port entre roles co-localises | — | ✅ OK | CONFORME : 33 revendication(s) de port, aucune collision entre roles co-localises (38 groupes). |
|
||||
| P34 | Chaque document declare son lecteur | — | ✅ OK | 42 document(s) declarent leur lecteur (26 genere(s) exempte(s)). |
|
||||
| P35 | Toute application exigeant une base en a une au plan | — | ✅ OK | 5 application(s) exigeant une base l'ont toutes (4 entree(s) au registre). |
|
||||
| P36 | Tout detenteur d'etat porte une sauvegarde | — | ✅ OK | 9 hote(s) detiennent de l'etat, tous porteurs de `client_backup` (9 groupe(s) au catalogue). |
|
||||
| P37 | Le placement du tenant existe chez son hebergeur | — | ✅ OK | placement confronte a l'hebergeur monte (SITE-Chezlepro) : noeud, stockage, pont — tous offerts. |
|
||||
| P38 | Catalogue des services : la carte dit ce que le moteur fait | — | ✅ OK | Catalogue a jour : 36 role(s) serveur/client tous nommes, 37 groupe(s) cite(s) en table existent tous. |
|
||||
| P39 | Glossaire : tout mot employe est enseigne | — | ✅ OK | Glossaire complet : 81 terme(s) du jargon expliques, 15 lien(s) valides, 27 page(s) de wiki toutes atteignables. |
|
||||
| P40 | Parente : l'ecosysteme sait de quoi il descend | — | ✅ OK | Parente coherente : 4 depot(s), tous retrouves, tous porteurs d'un remote. |
|
||||
| P41 | Resolution d'instance : une seule, partagee | — | ✅ OK | Resolution unique : 47 script(s) passent par `inventory_rules`, 3 exemption(s) nommee(s). |
|
||||
| P42 | L'edge porte les noms qu'il publie | — | ✅ OK | 4 edge(s) emettent un certificat portant les noms publies (OPS-Chezlepro-lab/principal, OPS-Chezlepro/principal, OPS-Technolibre/principal, OPS-Patient0/product |
|
||||
| P43 | Frontiere : le devis voit les machines du site | — | ✅ OK | Devis de la frontiere : 5 machine(s) du plan retrouvees, 56 regle(s) du site. |
|
||||
| P44 | Integrations : le serveur avant ses clients | — | ✅ OK | 4 integration(s) appliquent leur serveur avant leurs clients. |
|
||||
| P45 | Pare-feu Proxmox : arme sur les VNet SDN, jamais ailleurs | — | ✅ OK | Le pare-feu Proxmox ne s'arme que sur un VNet SDN (4 cas evalues, dont un qui doit rendre VRAI). |
|
||||
| P46 | Plancher /etc/hosts : un seul role en decide | — | ✅ OK | Un seul maitre du plancher — roles/hosts_statiques/tasks/main.yml : manage_etc_hosts: false ; et le gabarit maitre est pose (roles/hosts_statiques/templates/hos |
|
||||
| P47 | Zones inverses : couvrir l'occupe, et rien de plus | — | ✅ OK | Les zones inverses couvrent l'occupe et rien de plus (5 cas evalues, dont un site a quatre zones et un tenant a une). |
|
||||
| P48 | La carte d'orientation designe ce qui existe, et compte juste | — | ✅ OK | La carte designe 84 chemin(s) qui existent, et ses 7 chiffres correspondent a la mesure. |
|
||||
| P49 | Registre des flux : la matrice d'audit est a jour | — | ✅ OK | Le registre des flux reproduit exactement ce que les `meta/flux.yml` declarent (110 lignes). |
|
||||
| P50 | Silences : un refus muet est declare, place en dernier, et motive | — | ✅ OK | 2 silence(s) declare(s), tous en sequence > 1 (la plus haute des 121 regles `pass`), tous non consignes et tous motives. |
|
||||
| P51 | Collections : toutes declarees, toutes epinglees | — | ✅ OK | 3 collection(s) et 2 bibliotheque(s) Python declarees et epinglees : ansible.posix==1.6.2, community.general==10.3.0, community.postgresql==3.10.2 |
|
||||
| P52 | Materialiser n'exige pas d'entrer dans le tenant | — | ✅ OK | `creer-vm` confirme par l'agent invite (API des hyperviseurs, deja utilisee pour creer), sans exiger d'entrer dans le tenant. |
|
||||
|
||||
## Couverture des affirmations ✅ du registre
|
||||
|
||||
Chaque affirmation ✅ automatisable est couverte par la preuve indiquee ci-dessus.
|
||||
Les ✅ **structurelles/doctrinales** non rejouables par une commande (ex. AFF-005
|
||||
`make`=aide, AFF-014 ciblage groupe, AFF-024 `instancier-appliquer`, AFF-051 autorite
|
||||
d'AGENTS.md, AFF-073/075 gardes `make`, AFF-090 wiki) ont ete verifiees a l'audit ;
|
||||
elles restent hors du harnais recurrent (rien d'executable a rejouer).
|
||||
|
||||
## Declarations d'intention (⚪ invérifiables localement — assumees)
|
||||
|
||||
Ces affirmations ne sont pas rejouables hors production ; elles sont **assumees**
|
||||
comme declarations d'intention, non comme preuves :
|
||||
|
||||
- **AFF-036** — « testables avec `--check` autant que possible » : verifiable seulement
|
||||
contre une flotte vivante.
|
||||
- **AFF-091** — contenu pedagogique du wiki : affirmations conceptuelles.
|
||||
- **AFF-096** — « GUI 100 % francais » : revue exhaustive des libelles rendus, non automatisee.
|
||||
- **AFF-007** — hote d'exemple `web-frontal-01` : placeholder assume.
|
||||
|
||||
_Rapport genere le 2026-08-28._
|
||||
|
|
@ -26,7 +26,7 @@ README de rôles). Cette page comble ces deux trous.
|
|||
| rôles | 61 | `roles/*/` |
|
||||
| README de rôles | 61 | `roles/*/README.md` — l'écart avec la ligne au-dessus est la dette |
|
||||
| documents | 38 | `docs/*.md` |
|
||||
| pièces d'audit | 28 | `docs/audit/*` |
|
||||
| pièces d'audit | 29 | `docs/audit/*` |
|
||||
| unités de wiki | 27 | `wiki/*.md` |
|
||||
| décisions en vigueur | 78 | lignes `\| **D-nn** \|` de `decisions-architecture.md` |
|
||||
| décisions renversées | 3 | lignes `\| **D-nn** —` du même document |
|
||||
|
|
|
|||
Loading…
Reference in a new issue