# Audit de conformité — mode d'emploi 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-.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`. | > **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-.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.)