Set-OPS-Public/docs/audit/plan-de-recette.md
Daniel Allaire 58015f56e0 Plan de recette (P22) : le pendant manuel de make prouver
Les 78 exercices « À toi de jouer » du wiki forment un plan de tests d'acceptation.
Formalisé sans dupliquer :

- scripts/plan_recette.py + make plan-recette : GÉNÈRE docs/audit/plan-de-recette.md
  depuis les exercices du wiki. Grille auto-contenue par unité, colonnes : ce qu'on
  éprouve · le geste · type (observe/casse-répare) · Preuve auto (le Pxx extrait du
  texte -> quels gestes manuels sont AUSSI gardés par la machine). Générée -> ne peut
  pas dériver du wiki.
- Preuve P22 : plan_recette.py --verifier échoue si le fichier committé est périmé.
  Le plan de recette devient auto-gardé.
- Honnêteté de couverture assumée : « — » = manuel seul ; pas d'exhaustivité au-delà
  des exercices du wiki.

Pendant humain de make prouver (le harnais prouve le moteur P01-P21, la recette valide
l'exploitation) ; checklist du protocole-operateur-independant (« exploitable sans IA »).

Validé : 78 gestes / 19 unités, 5 doublés d'un Pxx ; P22 détecte une dérive (testé) ;
make verifier -> CONFORME 22/22 (instance cohérente).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 15:49:16 -04:00

20 KiB
Raw Blame History

Plan de recette — tests d'acceptation manuels

GÉNÉRÉ depuis les exercices du wiki (wiki/*.md, section « ④ À toi de jouer ») par scripts/plan_recette.pyne pas éditer à la main ; régénérer avec make plan-recette. La preuve P22 échoue si ce fichier n'est plus à jour.

Ce plan est le pendant manuel de make prouver : là où le harnais prouve le moteur par machine (P01P21), ces gestes valident l'exploitation — ce qu'un humain fait, voit, casse et répare. Ensemble, ils couvrent les deux moitiés ; le côté humain est la preuve de l'affirmation « exploitable sans IA » (cf. protocole-operateur-independant.md).

78 gestes sur 19 unités · 18 en « casse-répare » · 5 doublés d'un garde-fou machine (colonne Preuve auto).

Honnêteté de couverture. La colonne Preuve auto n'est remplie que lorsqu'une preuve Pxx de make prouver couvre AUSSI le geste. Un « — » signifie manuel seul : aucune machine ne le garde, seul l'œil de l'opérateur le valide. Ce plan ne prétend pas à l'exhaustivité au-delà des exercices présents dans le wiki.

Autorisation & RBAC

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Sens le défaut Avant tout rôle, un nouvel utilisateur SSO est Viewer dans Grafana : il voit le dashboard Journaux de la flotte, mais pas l'icône Explore. 👁 observe
2 Donne Editor testmail a le rôle grafana-editor → déconnecte/reconnecte-le (Grafana applique le rôle à la connexion) → Explore apparaît. 👁 observe
3 Observe le claim Dans Keycloak (console admin) → Clients → grafana → Client scopesEvaluate pour testmail : le jeton contient "roles": ["grafana-editor"]. C'est ② en vrai. 👁 observe
4 Casse & répare Retire grafana-editor de testmail (ou renomme-le en grafana-viewer), reconnecte : Explore disparaît. Remets-le : il revient. Tu sens que c'est le rôle, pas l'identité, qui ouvre la porte. 🔨 casse-répare

Source : Autorisation & RBAC · § À toi de jouer.

Bases de données

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Liste les bases (sur data-sql-01) : « commande » 👁 observe
2 Vois l'isolation Chaque app a sa base et son compte — pas de compte partagé. 👁 observe
3 Suis une liaison Ouvre plan/bases-donnees.yml : l'entrée keycloak (serveur, base, propriétaire, secret) est exactement ce que le rôle serveur_keycloak va lire pour se connecter. 👁 observe
4 Casse & répare Change le mot de passe d'un compte dans PostgreSQL (garde l'ancien !) sans mettre à jour la voûte : l'app ne se connecte plus. Restaure : ça repart. Tu sens que la connexion = identité + secret cohérents des deux côtés. 🔨 casse-répare

Source : Bases de données · § À toi de jouer.

Cache

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Écris/lis avec authentification (sur data-sql-01) : « commande » 👁 observe
2 Teste le TTL : redis-cli -a … SET court 1 EX 5 puis GET court avant/après 5 s — il expire. 👁 observe
3 Vois la borne : redis-cli -a … CONFIG GET maxmemory et … maxmemory-policy (LRU). 👁 observe
4 Casse & répare Interroge sans mot de passe : redis-cli GET essai:1 → NOAUTH (refusé). Puis vide le cache (FLUSHALL) : rien ne casse dans l'écosystème — la vraie donnée est en base. Tu sens qu'un cache est jetable. 🔨 casse-répare

Source : Cache · § À toi de jouer.

Courriel (SMTP / IMAP)

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Envoie via la soumission :587 (client authentifié) : « commande » 235 Authentication successful puis 250 queued = ① en action. 👁 observe
2 Lis la boîte (le MDA) : doveadm search -u testmail mailbox INBOX all | wc -l sur infra-mail-01. 👁 observe
3 Casse & répare Coupe l'annuaire (arrête OpenLDAP), renvoie un courriel : Postfix rejette le destinataire (il ne peut plus valider en LDAP). Rallume OpenLDAP : ça repart. Tu sens la dépendance requise MTA → annuaire. 🔨 casse-répare

Source : Courriel (SMTP / IMAP) · § À toi de jouer.

DNS & résolution de noms

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Le plancher, sans DNS Sur un nœud : « commande » 👁 observe
2 Interroge l'autoritatif Demande à PowerDNS directement : « commande » 👁 observe
3 Vois les couches Compare getent hosts (plancher) et dig (DNS) : deux chemins, même IP. 👁 observe
4 Casse & répare Sur un nœud sans client_unbound, vide /etc/hosts de ses entrées chezlepro (garde une sauvegarde !) et coupe l'accès au DNS : la résolution interne échoue. Restaure /etc/hosts : ça remarche sans DNS. Tu viens de sentir pourquoi le planc… 🔨 casse-répare

Source : DNS & résolution de noms · § À toi de jouer.

Identité & SSO

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Vis le SSO Ouvre https://grafana.lab.chezlepro.internal → « Se connecter avec Chezlepro » → testmail. Puis ouvre Forgejo, puis Icinga : tu n'es reconnecté nulle part. 👁 observe
2 Observe le flux Rouvre Grafana en navigation privée, ouvre les outils dév (F12 → Réseau) : repère la redirection vers Keycloak, puis le retour avec un code=. C'est ① en action. 👁 observe
3 Interroge l'annuaire (la source de vérité) Sur un nœud avec ldap-utils : « commande » Tu vois l'entrée que Keycloak fédère — il ne l'a pas recopiée. 👁 observe
4 Casse & répare (la fédération) Dans la console admin Keycloak → User Federation → désactive le fournisseur LDAP. Reconnecte-toi : échec (l'IdP ne voit plus l'annuaire). Réactive : ça remarche. Tu viens de sentir la dépendance requise entre l'IdP et l'annuaire. 🔨 casse-répare

Source : Identité & SSO · § À toi de jouer.

Infra as Code & idempotence

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Sens l'idempotence Redéploie un rôle déjà en place (ex. via la GUI ou make deployer HOTE=…) : la 2ᵉ fois, changed=0. Rien à faire = rien n'est touché. 👁 observe
2 Le flux déclaratif Édite le plan (un serveur dans la GUI), ⚙ Appliquer le plan (instancier), puis Vérifier (dry-run) : tu prévisualises avant d'appliquer. 👁 observe
3 La réversibilité git diff / git checkout sur le plan : l'état est du code, donc annulable. 👁 observe
4 Casse & répare Modifie à la main un fichier géré par un rôle (ex. un .conf), puis redéploie : Ansible rétablit l'état voulu (le code gagne sur la dérive manuelle). Tu sens que la source de vérité, c'est le code. 🔨 casse-répare

Source : Infra as Code & idempotence · § À toi de jouer.

La preuve — prouver, pas affirmer

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Produis une preuve make prouver (voûte exportée). Lis docs/audit/preuve-.md : chaque preuve, son verdict, l'affirmation couverte. 👁 observe
2 Fais échouer une preuve — exprès Introduis un hôte fantôme : dans applications.yml, pointe une appli vers un hôte qui n'existe pas dans serveurs.yml. make prouver : P06 échoue, en nommant l'hôte. Corrige (ou via le de la GUI) : vert. 👁 observe P06
3 Une autre Remets de l'adressage dans une nomenclature (vlan: 42), make prouver : P20 échoue. Retire-le : vert. 👁 observe P20
4 Lis le registre Ouvre docs/audit/affirmations.md : trouve une affirmation (non prouvable localement) — vois comment elle est assumée comme intention, jamais présentée comme prouvée. 👁 observe
5 Comprends la valeur Demande-toi : quelle promesse est-ce que je fais sans preuve ? C'est exactement ce que ce registre force à regarder en face. 👁 observe

Source : La preuve — prouver, pas affirmer · § À toi de jouer.

Le GUI (console d'exploitation)

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Lance-la make inventaire-ui, ouvre l'URL affichée. Repère l'inventaire actif et l'état de la flotte (en haut), les onglets, « Appliquer le plan », « Sauvegarder ». 👁 observe
2 Édite → prévisualise Vue Serveurs, change la mémoire d'un hôte, Sauvegarder, Appliquer le plan, puis Vérifier (dry-run) : tu vois ce qui changerait avant d'agir. 👁 observe
3 Répare un hôte fantôme (l'erreur impossible) Si une appli pointe un hôte inexistant, ouvre la vue Applications, sélectionne-la : le « Hôte » ne montre que des hôtes réels. Choisis le bon, Sauvegarder, Appliquer. Tu ne peux pas re-saisir le fantôme. 👁 observe
4 Bascule d'instance Vue Réseau, bouton « Activer » sur une autre instance. Toutes les vues suivent, sans redémarrer. 👁 observe
5 Sens le garde-fou Essaie de sauvegarder un plan incohérent (ex. une base dont le consommateur n'existe pas) : la console refuse avec une raison. L'invalide ne passe pas. 👁 observe
6 Casse & répare Édite hosts.yml à la main, reviens dans la GUI, « Appliquer le plan » : ta modification est écrasée par le plan. La source de vérité, c'est le plan — pas l'inventaire. 🔨 casse-répare

Source : Le GUI (console d'exploitation) · § À toi de jouer.

Le plan & l'adressage dérivé

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Observe la dérivation Vue Serveurs de la GUI : chaque carte montre VMID · IP · VLAN. Aucun n'a été saisi — tous viennent du index. Note l'IP d'un hôte. 👁 observe
2 Change le seed, regarde tout suivre Panneau Intrants → Réseau, change index (ex. de 1 à 7), « Appliquer le plan ». Toutes les IP basculent de 10.11.x à 10.17.x, les VLAN de 101x à 107x — d'un seul chiffre. Puis remets ta valeur. 👁 observe
3 Sens la source unique make instancier (diff), puis make instancier-appliquer : « DIFF VIDE : le plan reproduit exactement l'inventaire » — le plan est la vérité. 👁 observe
4 Casse & répare Édite hosts.yml à la main (change une IP). Relance make instancier : il signale l'écart. Ré-applique : le plan écrase ta modification. Tu sens que hosts.yml n'est pas la vérité — le plan l'est. 🔨 casse-répare
5 Éprouve le garde-fou Ajoute une ligne supernet: 10.99.0.0/16 dans une nomenclature, puis make prouver : P20 échoue (« adressage stocké »). Retire-la : vert. La règle se prouve. 👁 observe P20

Source : Le plan & l'adressage dérivé · § À toi de jouer.

Liaisons (bindings)

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Lis une liaison Ouvre instance/plan/applications.yml : une app avec expose: (liaison app→domaine), et serveurs.yml : un nœud avec integrations: (liaison nœud→service). 👁 observe
2 Vois-la se résoudre Après make instancier, regarde l'inventaire généré : la cible est devenue une valeur concrète (FQDN, groupe) — le moteur a câblé. 👁 observe
3 Requise vs optionnelle Compare : retirer client_journal d'un nœud → aucun problème (optionnelle). Déclarer une base sans serveur → make instancier/la validation échoue (requise). Tu sens la différence de modalité. 👁 observe
4 Casse & répare Casse une liaison requise (ex. réfère une base à un serveur inexistant), relance l'instanciation : échec clair avant tout déploiement. Corrige : ça passe. Le moteur attrape le câblage manquant à ta place. 🔨 casse-répare

Source : Liaisons (bindings) · § À toi de jouer.

Multi-instance & fédération

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Vois la flotte make instances : l'active (★), les index, les VLAN, le statut fédéré/local. Repère qui est en production. 👁 observe
2 Bascule GUI, vue Réseau, bouton « Activer » sur une autre instance (ou make instance-utiliser NOM=…). Toutes les vues suivent — sans redémarrer. 👁 observe
3 Crée une instance make instance-modeles (les modèles dispo), puis make instance-creer NOM=OPS-Test MODELE=socle INDEX=4. Un écosystème neuf, en une commande. 👁 observe
4 Éprouve le garde-fou de collision Essaie de créer une instance avec un index déjà pris : refus avant toute copie. Puis make prouver → P21 veille sur la fédération. 👁 observe P21
5 Casse & répare Donne à deux instances fédérées le même index (édite une nomenclature), make instances : la bannière de collision s'allume ; make prouver : P21 échoue. Corrige l'index : tout redevient vert. 🔨 casse-répare P21
6 (Avancé) Promeus un produit Une instance qui tourne et se prouve peut devenir un modèle vendable : make model-creer MODE=instance SOURCE=OPS-… NOM=… — elle est généralisée (identité → exemple.*, secrets retirés) et validée. 👁 observe

Source : Multi-instance & fédération · § À toi de jouer.

Métriques & journaux

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Interroge les métriques (sur obs-01) — combien de nœuds scrapés, tous UP ? « commande » 👁 observe
2 Vois les journaux : curl -s http://localhost:3100/loki/api/v1/label/host/values → les nœuds qui expédient leurs logs. 👁 observe
3 Ouvre Grafana (https://grafana.lab.chezlepro.internal) — métriques et logs au même endroit. 👁 observe
4 Casse & répare Arrête prometheus-node-exporter sur un nœud : dans Prometheus, sa cible passe up=0 (DOWN). Redémarre : elle repasse UP. Tu sens que c'est l'agent qui nourrit le serveur (modèle pull). 🔨 casse-répare

Source : Métriques & journaux · § À toi de jouer.

PKI & confiance

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Regarde un certificat Sur un nœud avec client_pki : « commande » Repère le sujet (l'identité), l'émetteur (l'intermédiaire) et la validité. 👁 observe
2 Suis la chaîne de confiance « commande » OK = la racine valide bien le certificat du serveur. C'est ① en action. 👁 observe
3 Vois-le servir en vrai Le LDAPS d'OpenLDAP utilise ce certificat : « commande » 0 (ok) = confiance vérifiée. 👁 observe
4 Casse & répare Retire la racine du magasin système, refais un curl HTTPS interne : avertissement de certificat (plus de confiance). Réinstalle la racine : ça remarche. Tu viens de sentir pourquoi « faire confiance à la racine » est la clé de voûte. 🔨 casse-répare

Source : PKI & confiance · § À toi de jouer.

Reverse-proxy & TLS

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Route par nom Deux noms, un seul edge (192.168.15.21) : « commande » Change grafana en forge : même IP, backend différent. C'est le routage par SNI. 👁 observe
2 Vois la terminaison TLS Le certificat présenté est celui de l'edge (avec les SAN des exposés) : openssl s_client -connect 192.168.15.21:443 -servername grafana.lab… | openssl x509 -noout -text | grep -A1 'Subject Alternative'. 👁 observe
3 Casse & répare Arrête le backend (ex. systemctl stop grafana-server sur obs-01) et rouvre Grafana : l'edge répond 502 Bad Gateway (le proxy est là, le service non). Redémarre : ça remarche. Tu distingues le proxy de ce qu'il sert. 🔨 casse-répare

Source : Reverse-proxy & TLS · § À toi de jouer.

Sauvegardes (3-2-1)

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Lance une sauvegarde Sur un nœud avec client_backup : « commande » 👁 observe
2 Liste les instantanés (le dépôt vit hors-nœud) : « commande » 👁 observe
3 Restaure — le vrai test Restaure dans un dossier temporaire et compare : « commande » (sur infra-pki-01 ; ailleurs, compare le dump correspondant.) 👁 observe
4 Casse & répare Supprime un fichier de donnée (une copie de test !), restaure-le depuis l'instantané, vérifie qu'il est identique. Tu viens de sentir que la valeur d'une sauvegarde est la restauration, pas la sauvegarde. 🔨 casse-répare

Source : Sauvegardes (3-2-1) · § À toi de jouer.

Supervision & impact

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Ouvre Icinga Web 2 (https://icinga.lab.chezlepro.internal, via le SSO) : la liste des hôtes et services supervisés, avec leur état (vert/jaune/rouge). 👁 observe
2 Vois l'impact Menu Business Processes → « Supervision Chezlepro » : un processus qui agrège des checks (load, procs, ping…) en un état roulé. C'est l'impact, pas une case. 👁 observe
3 Casse & répare Provoque l'échec d'un check (ex. arrête un service surveillé) : l'état passe CRITICAL, et le processus BPM qui en dépend rougit (l'impact remonte). Répare : tout reverdit. Tu sens la différence entre mesurer et superviser/alerter. 🔨 casse-répare

Source : Supervision & impact · § À toi de jouer.

Sécurité & durcissement

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Constate les couches (sur n'importe quel nœud) : « commande » 👁 observe
2 Moindre privilège : PermitRootLogin est à no, l'accès se fait par le compte ansible + clé SSH. Vérifie : sshd -T | grep -E 'permitrootlogin|passwordauthentication'. 👁 observe
3 Casse & répare (avec prudence, en lab) Assouplis un réglage sysctl, observe, puis remets-le. Tu sens que chaque ligne de durcissement ferme une porte précise. 🔨 casse-répare

Source : Sécurité & durcissement · § À toi de jouer.

Virtualisation & clonage

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Regarde un clone Dans la GUI (make inventaire-ui), un serveur actif a été cloné du template (bouton « 🖥 Créer la VM »). Son VMID/IP sont dérivés de la nomenclature. 👁 observe
2 Vois l'identité cloud-init Sur un nœud : cloud-init query hostname, hostname -f, et l'agrandissement du disque racine (df -h /). 👁 observe
3 Sépare les deux couches cloud-init a posé l'identité ; tout le reste (paquets, services, durcissement) vient d'Ansible. Le template, lui, ne contient aucune donnée de clone. 👁 observe
4 Casse & répare (mentalement + lab) Supprime un nœud non critique et reclone-le depuis le template, puis redéploie : il revient à l'identique. Tu sens que la machine est reconstructible. 🔨 casse-répare

Source : Virtualisation & clonage · § À toi de jouer.