Set-OPS-Public/docs/audit/README.md
Daniel Allaire b1460a6dde Multi-instances : make instances (vue + collision) + preuve P21
La bascule d'instance existait deja (make instance-utiliser / instance-courante,
repointage du symlink). Manquaient la vue d'ensemble et le filet de securite.

- make instances (scripts/instances.py) : liste les instances de la federation
  (depots freres avec plan/nomenclature.yml), marque l'active (*), montre index,
  plage VLAN derivee, statut federe/local et production. Lecture seule.
- Detection de collision d'index entre instances FEDEREES (memes VLAN/VMID sur le
  trunk) : le piege exact vecu (prod + labo tous deux a l'index 1) est desormais
  crie. Mode --verifier -> rc=2 sur collision.
- Preuve P21 : cable ce garde-fou dans make prouver / make verifier. No-op quand
  moins de deux instances federees sont presentes (comme P17 sans SETOPS_MODELES).

Valide : make instances liste les 3 instances (labo LOCAL, Technolibre + Chezlepro
federees, index 2 et 13) ; detection testee en synthetique (deux federees meme
index -> collision ; labo federe:false -> coherent) ; make verifier rc=0
CONFORME 21/21.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 11:26:01 -04:00

93 lines
6.3 KiB
Markdown

# 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-<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`. |
> **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.)