Set-OPS-Public/docs/audit/README.md
Daniel Allaire ac85278366 preuve : P34 — chaque document declare son lecteur (D-74)
La refonte de ce matin posait une convention. Une convention qu'on n'outille
pas tient tant que quelqu'un y pense : c'est le raisonnement de D-70, applique
au corpus documentaire.

Etat de depart mesure : 2 documents sur 34 declaraient leur lecteur. Les 32
autres disaient leur SUJET — ce qui avait enfoui le runbook de reprise le plus
utile du depot au §6 de autorisation.md.

Les 38 le declarent desormais, lecteur determine document par document et non
colle au gabarit : l'exploitant (devis, migration de tenant, cycle de vie,
gabarit d'or), le mainteneur (conceptions, registres, carte), le lecteur
externe (ecosysteme-chezlepro), l'agent IA (MISE-A-JOUR-CODEX-CLAUDE).

Deux exemptions DERIVEES, pas listees — un chemin en dur aurait vieilli a la
premiere page ajoutee : un document qui s'annonce genere, et un fragment sans
titre. Les 13 exemptes verifies un par un ; aucun document ecrit a la main
n'est exempte par accident. La preuve ne lit que l'EN-TETE, ce qui empeche
frontiere-opnsense.md et plan-et-generation.md — qui parlent de generation
dans leur corps — d'etre exemptes a tort.

Eprouvee dans les deux sens. Elle a echoue seule des sa premiere execution en
nommant deux documents que mon inventaire avait manques (docs/audit/). Puis
test negatif delibere : declaration retiree de meta-classe.md -> ECHEC la
nommant ; restauree -> OK.

Ce qu'elle ne teste pas : que le lecteur declare soit le BON. Ca se juge en
revue ; elle garantit qu'on a du y penser.

P01–P34. Comptes perimes corriges au passage (AGENTS.md et devis-services.md
annoncaient encore 30 preuves).

Verifie : prouver.py 0 (34 OK), plan-recette inchange.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 07:53:04 -04:00

97 lines
6.9 KiB
Markdown

# Audit de conformité — mode d'emploi
> **Pour qui :** le **mainteneur** — comment le dispositif de preuve fonctionne, et comment l'étendre.
Ce dossier contient le dispositif qui garde Set-OPS **honnête** : il ne doit jamais
affirmer plus que ce qu'il prouve.
## Les pièces
| Fichier | Rôle |
|---|---|
| [`affirmations.md`](affirmations.md) | **Le registre** : chaque affirmation publique du dépôt (README, AGENTS, QUICKSTART, docs, wiki, aide `make`, GUI) tracée vers une commande de preuve et un statut (✅/🟡/❌/⚪), plus le **journal des traitements** (ce qui a été corrigé, quand, comment). |
| `scripts/prouver.py` | **Le harnais** : un orchestrateur mince qui **rejoue** les preuves automatisables du registre en appelant l'outillage existant (les mêmes scripts que `make verifier`). Il ne réimplémente aucune validation. |
| `preuve-AAAA-MM-JJ.md` | **La pièce justificative** : le rapport horodaté produit par `make prouver`. Rejouable et présentable (audit, certification, revue). |
| [`protocole-operateur-independant.md`](protocole-operateur-independant.md) | **L'épreuve humaine** : le protocole qui met AFF-002 (« exploitable sans IA ») à l'épreuve d'un sysadmin qui n'est pas l'auteur. Aucune commande locale ne peut prouver cette affirmation ; produit un rapport `operateur-independant-AAAA-MM-JJ.md`. |
## Produire une preuve
```bash
make prouver
```
Cela exécute chaque preuve et écrit `docs/audit/preuve-<date>.md`. La commande **sort en
erreur (rc≠0)** si une preuve automatisable échoue — utilisable en garde-fou (CI locale,
pré-commit). Une preuve **SAUTÉE** (⚪) n'est pas un échec.
### Prérequis Vault
La preuve `P15` (inventaire Ansible complet, `ansible-inventory --list`) déchiffre le
`group_vars` de l'instance. Sans `ANSIBLE_VAULT_PASSWORD_FILE`, elle est **automatiquement
sautée** (⚪) avec la mention du prérequis — le reste du harnais reste vert, car les
validateurs Python lisent le plan et l'inventaire directement, sans secret. Pour l'inclure :
```bash
export ANSIBLE_VAULT_PASSWORD_FILE=~/.config/setops-vault-pass
make prouver
```
## Ce que couvre `make prouver`
| # | Preuve | Ce qu'elle établit |
|---|---|---|
| P01 | Lint (`ansible-lint`) | 0 violation, profil `production`. |
| P02 | Tests unitaires | `inventory_host` — cas nominal + refus. |
| P03 | Diff-vide du plan | l'inventaire est **généré** depuis le plan (diff vide). |
| P04 | Groupes ↔ playbooks | chaque groupe opérationnel a son playbook homonyme. |
| P05 | Dépendances de groupes | graphe cohérent, aucune entrée orpheline. |
| P06 | Validateurs de registres | serveurs / applications / bases / domaines valides. |
| P07 | GUI | `node --check` du JS du GUI. |
| P08 | Orchestration | couches + graphe : aucun cycle, aucune arête en arrière. |
| P09 | Flux réseau | schéma + matrice d'audit cohérents. |
| P10 | Handlers ↔ notify | tout `notify` pointe vers un handler du même rôle. |
| P11 | Syntaxe | `--syntax-check` de tous les playbooks (via `make syntaxe`). |
| P12 | Runbooks cités | les fichiers `docs/` référencés existent. |
| P13 | Invariants structurels | LICENSE, socle en forme dossier, pas de couches parallèles, SSH clé-only, nftables désactivé par défaut. |
| P14 | Chemins d'inventaire | aucun `instance/inventories/lab/group_vars` codé en dur. |
| P15 | Modèle public `socle` | ses registres (domaines/serveurs/applications/bases) valident. |
| P16 | Inventaire Ansible (voûte) | `ansible-inventory --list` — sauté sans mot de passe Vault. |
| P17 | **Tous** les modèles d'instance | chaque modèle découvert valide (pas seulement `socle`). `SETOPS_MODELES=../Set-OPS-Modeles` inclut les modèles assemblés privés. |
| P18 | Gabarit de voûte complet | `vault.yml.example` couvre **exactement** les secrets que le plan exige (rôles actifs + bases + group_vars). |
| P19 | GUI couvre le plan | tout champ présent dans un plan réel est éditable par le GUI (nomenclature tolérée : le seed `index` est désormais un intrant ; l'adressage est dérivé, donc rien à éditer). |
| P20 | Adressage dérivé du seed | aucune nomenclature ne **stocke** d'adressage (supernet, sous-réseau, passerelle, VLAN) : tout se dérive du seul `index`. Attrape toute rechute vers l'écriture manuelle. |
| P21 | Fédération sans collision | aucune paire d'instances **fédérées** ne partage un `index` (mêmes VLAN/VMID sur le trunk). Le garde-fou du multi-instances ; vue avec `make instances`. |
| P22 | Plan de recette à jour | `docs/audit/plan-de-recette.md` (les 78 gestes manuels, générés des exercices du wiki) est **à jour** — il ne peut pas dériver du wiki. Régénérer : `make plan-recette`. |
| P23 | Underlay sans collision | la **fabric physique** (`underlay.yml` : mgmt/iSCSI/Ceph, cluster-global) n'empiète pas sur la plage tenant — VLAN < 1000 et sous-réseaux hors des supernets `10.(10+index).0.0/16`. Sautée si `underlay.yml` absent. Vue : `make underlay`. |
> **P17, P18, P19 ferment les angles morts du harnais** : il ne vérifiait qu'*une* instance
> et le seul modèle `socle`. P17 aurait attrapé l'hôte fantôme d'`integral` ; P18, les neuf
> secrets absents du gabarit Chezlepro ; P19, les champs `liens` / `websocket` que le GUI ne
> savait pas écrire. Chacune a une CLI dédiée (`scripts/modeles.py`, `voute.py`,
> `couverture_gui.py`) utilisable seule.
Le rapport relie chaque preuve aux **affirmations** qu'elle couvre (colonne « Affirmations »),
et liste à part les **déclarations d'intention** (⚪ invérifiables localement : AFF-036,
091, 096, 007) assumées comme intentions, jamais présentées comme prouvées.
## Ajouter une preuve
1. Ajouter (ou corriger) l'affirmation dans `affirmations.md` avec sa commande de preuve.
2. Ajouter une entrée à la liste `PREUVES` de `scripts/prouver.py` : soit une ou plusieurs
commandes (`cmds`, toutes doivent renvoyer 0), soit une fonction native `func` renvoyant
`(ok, détail)` pour un invariant simple. Renseigner `refs` avec les ID d'affirmations.
3. Ne **pas** réimplémenter de logique de validation : appeler l'outillage existant
(`scripts/*.py`, `ansible-lint`, cibles `make`). Le harnais orchestre, il ne valide pas.
## Rapport avec `make verifier`
`make verifier` **inclut désormais les preuves** : il enchaîne ses vérifications au fil de
l'eau (lint, tests, cohérence, syntaxe arrêt au premier échec) puis termine par
`python3 scripts/prouver.py --verifier` les preuves du registre **sans écrire de rapport**
(pour ne pas écraser la pièce justificative committée). Ainsi, `make verifier` échoue si une
preuve échoue.
`make prouver` (sans `--verifier`) reste le mode **pièce justificative** : il exécute tout,
**horodate** et **écrit** `docs/audit/preuve-<date>.md`. Les deux réutilisent le même
outillage. (Quelques vérifications se recouvrent entre les deux étapes coût assumé : la
sortie détaillée de `verifier` est conservée, et `prouver` ajoute les preuves manquantes.)