Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
"""Harnais de preuve Set-OPS : rejoue les preuves automatisables du registre.
|
|
|
|
|
|
|
|
|
|
`make prouver` enchaine les commandes de preuve du registre des affirmations
|
|
|
|
|
(`docs/audit/affirmations.md`) et produit un rapport horodate
|
|
|
|
|
`docs/audit/preuve-AAAA-MM-JJ.md` — rejouable, presentable comme piece justificative.
|
|
|
|
|
|
|
|
|
|
Ce script est un ORCHESTRATEUR MINCE : il ne reimplemente AUCUNE validation. Il
|
|
|
|
|
appelle l'outillage existant (les memes `scripts/*.py`, `ansible-lint`, `make syntaxe`
|
|
|
|
|
que `make verifier`) et met en forme les resultats. Ce n'est pas un framework de test
|
|
|
|
|
parallele : la logique de validation vit dans les scripts appeles.
|
|
|
|
|
|
|
|
|
|
Sortie : 0 si aucune preuve automatisable n'echoue (les preuves SAUTEES — ex. voute
|
|
|
|
|
requise absente — ne sont pas des echecs) ; 1 sinon.
|
|
|
|
|
|
|
|
|
|
Usage :
|
|
|
|
|
python3 scripts/prouver.py # execute + ecrit docs/audit/preuve-<date>.md
|
2026-07-20 21:03:20 -04:00
|
|
|
python3 scripts/prouver.py --verifier # preuves seules (verdict + code sortie), sans rapport
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import datetime as _dt
|
2026-07-20 20:47:36 -04:00
|
|
|
import json
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
import os
|
|
|
|
|
import subprocess
|
|
|
|
|
import sys
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
RACINE = Path(__file__).resolve().parents[1]
|
|
|
|
|
INSTANCE = Path(os.environ.get("SETOPS_INSTANCE", "instance"))
|
|
|
|
|
DOSSIER_AUDIT = RACINE / "docs" / "audit"
|
|
|
|
|
GROUPES = "playbooks/groupes"
|
|
|
|
|
DEPENDANCES = "docs/dependances-groupes.yml"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _inventaire() -> str:
|
|
|
|
|
"""Inventaire de l'instance : premier existant (principal > production > lab)."""
|
|
|
|
|
for nom in ("principal", "production", "lab"):
|
|
|
|
|
p = INSTANCE / "inventories" / nom / "hosts.yml"
|
|
|
|
|
if (RACINE / p).exists():
|
|
|
|
|
return str(p)
|
|
|
|
|
return str(INSTANCE / "inventories" / "principal" / "hosts.yml")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INV = _inventaire()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --- Preuves natives (petites verifications d'invariants, pas de logique metier) ---
|
|
|
|
|
|
|
|
|
|
def preuve_handlers() -> tuple[bool, str]:
|
|
|
|
|
"""Tout `notify` d'un role pointe vers un handler du meme role (AGENTS.md)."""
|
|
|
|
|
import glob
|
|
|
|
|
import yaml
|
|
|
|
|
|
|
|
|
|
problemes: list[str] = []
|
|
|
|
|
roles_dir = RACINE / "roles"
|
|
|
|
|
for role in sorted(p.name for p in roles_dir.iterdir() if p.is_dir()):
|
|
|
|
|
rp = roles_dir / role
|
|
|
|
|
handlers: set[str] = set()
|
|
|
|
|
for hf in glob.glob(str(rp / "handlers" / "*.yml")):
|
|
|
|
|
data = yaml.safe_load(Path(hf).read_text(encoding="utf-8")) or []
|
|
|
|
|
|
|
|
|
|
def collect(tasks):
|
|
|
|
|
for t in tasks or []:
|
|
|
|
|
if not isinstance(t, dict):
|
|
|
|
|
continue
|
|
|
|
|
if "name" in t:
|
|
|
|
|
handlers.add(t["name"])
|
|
|
|
|
if "listen" in t:
|
|
|
|
|
listen = t["listen"]
|
|
|
|
|
handlers.update(listen if isinstance(listen, list) else [listen])
|
|
|
|
|
for k in ("block", "rescue", "always"):
|
|
|
|
|
if k in t:
|
|
|
|
|
collect(t[k])
|
|
|
|
|
|
|
|
|
|
collect(data)
|
|
|
|
|
notifies: set[str] = set()
|
|
|
|
|
for tf in glob.glob(str(rp / "tasks" / "*.yml")):
|
|
|
|
|
data = yaml.safe_load(Path(tf).read_text(encoding="utf-8")) or []
|
|
|
|
|
|
|
|
|
|
def scan(tasks):
|
|
|
|
|
for t in tasks or []:
|
|
|
|
|
if not isinstance(t, dict):
|
|
|
|
|
continue
|
|
|
|
|
if "notify" in t:
|
|
|
|
|
n = t["notify"]
|
|
|
|
|
notifies.update(n if isinstance(n, list) else [n])
|
|
|
|
|
for k in ("block", "rescue", "always"):
|
|
|
|
|
if k in t:
|
|
|
|
|
scan(t[k])
|
|
|
|
|
|
|
|
|
|
scan(data)
|
|
|
|
|
manquants = notifies - handlers
|
|
|
|
|
if manquants:
|
|
|
|
|
problemes.append(f"{role}: notify sans handler -> {sorted(manquants)}")
|
|
|
|
|
if problemes:
|
|
|
|
|
return False, "; ".join(problemes)
|
|
|
|
|
return True, "Tout notify pointe vers un handler du meme role (49 roles)."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def preuve_runbooks() -> tuple[bool, str]:
|
|
|
|
|
"""Les runbooks / registres cites par les surfaces publiques existent."""
|
|
|
|
|
attendus = [
|
|
|
|
|
"docs/plan-et-generation.md", "docs/catalogue-services.md",
|
|
|
|
|
"docs/dependances-groupes.yml", "docs/dns-interne.md",
|
|
|
|
|
"docs/nomenclature-vm.md", "docs/config-proxmox.md", "docs/vm-lifecycle.md",
|
|
|
|
|
"docs/procedure-template-debian13-proxmox.md", "docs/positionnement.md",
|
|
|
|
|
"docs/bindings-conception.md", "docs/flux-conception.md",
|
|
|
|
|
"docs/couches-deploiement.yml", "docs/registre-flux.md",
|
|
|
|
|
"docs/carte-set-ops.md", "docs/runbooks-exploitation.md",
|
|
|
|
|
"exemples/vault.exemple.yml", "exemples/instance.exemple.yml",
|
|
|
|
|
]
|
|
|
|
|
manquants = [f for f in attendus if not (RACINE / f).exists()]
|
|
|
|
|
if manquants:
|
|
|
|
|
return False, "manquants : " + ", ".join(manquants)
|
|
|
|
|
return True, f"{len(attendus)}/{len(attendus)} runbooks/registres cites presents."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def preuve_structurels() -> tuple[bool, str]:
|
|
|
|
|
"""Invariants de structure/doctrine verifiables par le contenu du depot."""
|
|
|
|
|
echecs: list[str] = []
|
|
|
|
|
|
|
|
|
|
def lire(rel: str) -> str:
|
|
|
|
|
p = RACINE / rel
|
|
|
|
|
return p.read_text(encoding="utf-8") if p.exists() else ""
|
|
|
|
|
|
|
|
|
|
# AFF-015 : LICENSE present
|
|
|
|
|
if not (RACINE / "LICENSE").exists():
|
|
|
|
|
echecs.append("LICENSE absent")
|
|
|
|
|
# AFF-022 : modele socle en forme dossier (intrants charges, pas de shadowing)
|
|
|
|
|
if not (RACINE / "exemples/modeles/socle/inventories/production/group_vars/all/10-intrants.yml").exists():
|
|
|
|
|
echecs.append("socle: all/10-intrants.yml absent")
|
|
|
|
|
if (RACINE / "exemples/modeles/socle/inventories/production/group_vars/all.yml").exists():
|
|
|
|
|
echecs.append("socle: all.yml (forme fichier) masquerait all/")
|
|
|
|
|
# AFF-038 : pas de playbooks de couches paralleles
|
|
|
|
|
for couche in ("socle", "durcissement"):
|
|
|
|
|
if (RACINE / "playbooks" / couche).exists():
|
|
|
|
|
echecs.append(f"playbooks/{couche}/ ne doit pas exister")
|
|
|
|
|
# AFF-037 : SSH clef-only des la construction
|
|
|
|
|
if 'ssh_baseline_password_authentication: "no"' not in lire("roles/ssh_baseline/defaults/main.yml"):
|
|
|
|
|
echecs.append("ssh_baseline: PasswordAuthentication != no")
|
|
|
|
|
if "AuthenticationMethods publickey" not in lire("roles/ssh_baseline/templates/10-setops.conf.j2"):
|
|
|
|
|
echecs.append("ssh_baseline: AuthenticationMethods publickey absent")
|
|
|
|
|
# AFF-062 : nftables installe mais desactive par defaut
|
|
|
|
|
if "nftables_baseline_enabled: false" not in lire("roles/nftables_baseline/defaults/main.yml"):
|
|
|
|
|
echecs.append("nftables_baseline_enabled != false")
|
|
|
|
|
if echecs:
|
|
|
|
|
return False, "; ".join(echecs)
|
|
|
|
|
return True, "LICENSE, socle dossier, pas de couches paralleles, SSH clef-only, nftables off : OK."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def preuve_modele_socle() -> tuple[bool, str]:
|
|
|
|
|
"""Le modele public `socle` valide (registres) — garde contre une regression d'exemple."""
|
|
|
|
|
socle = "exemples/modeles/socle"
|
|
|
|
|
env = {**os.environ, "SETOPS_INSTANCE": socle}
|
|
|
|
|
for s in ("domaines", "serveurs", "applications", "bases_donnees"):
|
|
|
|
|
r = subprocess.run([sys.executable, f"scripts/{s}.py", "verifier"],
|
|
|
|
|
cwd=RACINE, env=env, capture_output=True, text=True)
|
|
|
|
|
if r.returncode != 0:
|
|
|
|
|
sortie = (r.stdout + r.stderr).strip().splitlines()
|
|
|
|
|
return False, f"{s}: {sortie[-1] if sortie else 'rc!=0'}"
|
|
|
|
|
return True, "Modele public socle : domaines/serveurs/applications/bases valides."
|
|
|
|
|
|
|
|
|
|
|
Adressage derive du seul seed index (rupture, mode compact retire)
Principe : les valeurs de configuration se derivent des intrants, elles ne se
reecrivent pas a la main. La nomenclature dupliquait ce qu'index determine deja
(supernet, sous-reseaux, passerelles, VLAN). Corrige en rupture nette.
- inventory_rules : source unique de derivation — supernet_de, base3_de,
sous_reseau_de, passerelle_de, vlan_de. Modele 6 zones encode une fois
(2e octet = 10+index, 3e octet zone = 15+categorie, VLAN = 1000+index*10+zone).
deriver_nomenclature ne lit plus aucun adressage stocke ; mode compact supprime.
- devis_reseau : importe ces helpers (fin de la duplication) ; decouvre les
tenants sur `index` present (filtre vmid_schema retire).
- GUI : `index` devient un INTRANT (section Reseau). Il vit dans la nomenclature
(plan reseau uniforme, contrairement aux intrants des modeles heterogenes) et
le GUI l'ecrit chirurgicalement (une ligne, sans reformater). Le miroir JS
derive le VLAN du seed (fin de la lecture de c.vlan stocke).
- socle public : nomenclature au format maigre.
Preuve P20 (preuve_nomenclature_derivee) : aucune nomenclature ne stocke
d'adressage — garde-fou permanent, teste en negatif.
Valide : DIFF VIDE sur les 3 instances (la derivation reproduit exactement
l'adressage stocke), 7 modeles valident, devis_reseau genere les memes VLAN
(1011-1016 derives), make verifier rc=0 CONFORME 20/20, node --check du GUI OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 02:58:15 -04:00
|
|
|
def preuve_nomenclature_derivee() -> tuple[bool, str]:
|
|
|
|
|
"""Aucune nomenclature ne STOCKE d'adressage : tout se derive du seed `index`.
|
|
|
|
|
|
|
|
|
|
Interdit `supernet` au niveau racine et `sous_reseau`/`passerelle`/`vlan` par zone.
|
|
|
|
|
Attrape toute rechute vers l'ecriture manuelle de l'adressage (rupture du 2026-07-23).
|
|
|
|
|
Portee : l'instance liee + tous les modeles decouverts (SETOPS_MODELES inclus).
|
|
|
|
|
"""
|
|
|
|
|
import yaml
|
|
|
|
|
sys.path.insert(0, str(RACINE / "scripts"))
|
|
|
|
|
import modeles as _mod
|
|
|
|
|
|
|
|
|
|
cibles = []
|
|
|
|
|
inst_nom = RACINE / INSTANCE / "plan" / "nomenclature.yml"
|
|
|
|
|
if inst_nom.exists():
|
|
|
|
|
cibles.append(inst_nom)
|
|
|
|
|
cibles += [m / "plan" / "nomenclature.yml" for m in _mod.decouvrir()
|
|
|
|
|
if (m / "plan" / "nomenclature.yml").exists()]
|
|
|
|
|
|
|
|
|
|
interdits_zone = {"sous_reseau", "passerelle", "vlan"}
|
|
|
|
|
fautes = []
|
|
|
|
|
for p in cibles:
|
|
|
|
|
n = yaml.safe_load(p.read_text(encoding="utf-8")) or {}
|
|
|
|
|
rel = p.relative_to(RACINE) if p.is_relative_to(RACINE) else p
|
|
|
|
|
if "supernet" in n:
|
|
|
|
|
fautes.append(f"{rel}: supernet stocke")
|
|
|
|
|
if "vmid_schema" in n:
|
|
|
|
|
fautes.append(f"{rel}: vmid_schema obsolete (mode compact retire)")
|
|
|
|
|
for z, c in (n.get("categories") or {}).items():
|
|
|
|
|
for k in interdits_zone & set(c or {}):
|
|
|
|
|
fautes.append(f"{rel}: categorie {z}.{k} stocke")
|
|
|
|
|
if fautes:
|
|
|
|
|
return False, f"{len(fautes)} champ(s) d'adressage stockes : " + " | ".join(fautes[:4])
|
|
|
|
|
return True, f"{len(cibles)} nomenclature(s) : adressage 100% derive du seed index."
|
|
|
|
|
|
|
|
|
|
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
def preuve_pas_lab_code_en_dur() -> tuple[bool, str]:
|
|
|
|
|
"""Aucun chemin `instance/inventories/lab/group_vars` code en dur (AFF-097).
|
|
|
|
|
|
|
|
|
|
On vise le vrai chemin (prefixe `instance/`) et on ignore les fichiers meta qui
|
|
|
|
|
*parlent* de l'audit (CHANGELOG, docs/audit) sans etre des chemins d'exploitation.
|
|
|
|
|
"""
|
|
|
|
|
r = subprocess.run(
|
|
|
|
|
["git", "grep", "-n", "instance/inventories/lab/group_vars", "--", "*.md", "*.yml"],
|
|
|
|
|
cwd=RACINE, capture_output=True, text=True,
|
|
|
|
|
)
|
|
|
|
|
exclus = ("docs/audit/", "CHANGELOG.md:")
|
|
|
|
|
lignes = [l for l in r.stdout.splitlines() if not l.startswith(exclus)]
|
|
|
|
|
if lignes:
|
|
|
|
|
return False, f"{len(lignes)} occurrence(s) : " + " | ".join(lignes[:3])
|
|
|
|
|
return True, "Aucun chemin instance/inventories/lab/group_vars code en dur."
|
|
|
|
|
|
|
|
|
|
|
2026-07-20 20:47:36 -04:00
|
|
|
def preuve_inventaire_ansible() -> tuple[bool, str]:
|
|
|
|
|
"""`ansible-inventory --list` : l'inventaire (voute dechiffree) se parse (AFF-030)."""
|
|
|
|
|
r = subprocess.run(["ansible-inventory", "-i", INV, "--list"],
|
|
|
|
|
cwd=RACINE, capture_output=True, text=True, timeout=600)
|
|
|
|
|
if r.returncode != 0:
|
|
|
|
|
sortie = (r.stdout + r.stderr).strip().splitlines()
|
|
|
|
|
return False, f"rc={r.returncode} : {sortie[-1] if sortie else ''}"
|
|
|
|
|
try:
|
|
|
|
|
data = json.loads(r.stdout)
|
|
|
|
|
except ValueError:
|
|
|
|
|
return True, "inventaire liste (JSON non parse)."
|
|
|
|
|
n_hotes = len((data.get("_meta") or {}).get("hostvars") or {})
|
|
|
|
|
n_groupes = len([k for k in data if k not in ("_meta", "all")])
|
|
|
|
|
return True, f"{n_hotes} hotes, {n_groupes} groupes (inventaire dechiffre et parse)."
|
|
|
|
|
|
|
|
|
|
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
# --- Registre des preuves : (id, titre, refs AFF, executeur) -----------------------
|
|
|
|
|
#
|
|
|
|
|
# executeur = liste de commandes argv (toutes doivent renvoyer 0), ou callable -> (ok, detail).
|
|
|
|
|
|
|
|
|
|
PREUVES: list[dict] = [
|
|
|
|
|
{"id": "P01", "titre": "Lint (ansible-lint)", "refs": ["AFF-006"],
|
|
|
|
|
"cmds": [["ansible-lint", "-q"]]},
|
|
|
|
|
{"id": "P02", "titre": "Tests unitaires (inventory_host)", "refs": [],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/tests/test_inventory_host.py"]]},
|
audit : les preuves réseau étaient accrochées à la mauvaise affirmation
P21, P23 et P24 renvoyaient à AFF-001 — « Set-OPS est un moteur Ansible
générique » — sans rapport avec la fédération, l'underlay ni la frontière.
P17, P19 et P20 n'avaient aucune référence. Une preuve accrochée à la
mauvaise affirmation passe au vert et n'atteste de rien de ce qu'on croit.
Ajouté §10 du registre : six affirmations (AFF-101..106) pour l'architecture
réseau et la fédération. La couverture du plan par le panneau est en 🟡, avec
ses exceptions nommées — listes de tables de l'underlay, ports physiques,
nœud de sortie.
Volontairement absente : la justesse des devis. Leur syntaxe dépend d'un
matériel que le dépôt ne possède pas ; six familles ont été confrontées au
commutateur réel, deux étaient fausses, mais c'est une vérification datée et
non une preuve rejouable. Le dépôt n'affirme pas que ses devis s'appliquent,
il affirme qu'ils dérivent.
Corrigé aussi : P03, P06, P12 et P13 portent maintenant les références que la
table leur attribuait déjà — la correspondance existait en double et seul le
document la tenait. Et la table attribuait AFF-030 (« inventaire complet ») à
P15, qui valide le modèle socle ; c'est P16 qui exécute
`ansible-inventory --list`.
35 affirmations référencées, aucune référence orpheline.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 09:36:30 -04:00
|
|
|
{"id": "P03", "titre": "Diff-vide du plan (inventaire genere)", "refs": ["AFF-001", "AFF-004", "AFF-030", "AFF-031", "AFF-032"],
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
"refs": ["AFF-001", "AFF-004", "AFF-030", "AFF-031", "AFF-032"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/instancier.py", "generer"],
|
|
|
|
|
[sys.executable, "scripts/instancier.py", "comparer"]]},
|
|
|
|
|
{"id": "P04", "titre": "Groupes <-> playbooks homonymes", "refs": ["AFF-008"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/inventory_host.py", "--inventaire", INV,
|
|
|
|
|
"verifier-playbooks", "--dossier-playbooks", GROUPES]]},
|
|
|
|
|
{"id": "P05", "titre": "Dependances causales de groupes", "refs": ["AFF-009", "AFF-084"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/inventory_host.py", "--inventaire", INV,
|
|
|
|
|
"--dependances", DEPENDANCES, "verifier-dependances",
|
|
|
|
|
"--dossier-playbooks", GROUPES]]},
|
audit : les preuves réseau étaient accrochées à la mauvaise affirmation
P21, P23 et P24 renvoyaient à AFF-001 — « Set-OPS est un moteur Ansible
générique » — sans rapport avec la fédération, l'underlay ni la frontière.
P17, P19 et P20 n'avaient aucune référence. Une preuve accrochée à la
mauvaise affirmation passe au vert et n'atteste de rien de ce qu'on croit.
Ajouté §10 du registre : six affirmations (AFF-101..106) pour l'architecture
réseau et la fédération. La couverture du plan par le panneau est en 🟡, avec
ses exceptions nommées — listes de tables de l'underlay, ports physiques,
nœud de sortie.
Volontairement absente : la justesse des devis. Leur syntaxe dépend d'un
matériel que le dépôt ne possède pas ; six familles ont été confrontées au
commutateur réel, deux étaient fausses, mais c'est une vérification datée et
non une preuve rejouable. Le dépôt n'affirme pas que ses devis s'appliquent,
il affirme qu'ils dérivent.
Corrigé aussi : P03, P06, P12 et P13 portent maintenant les références que la
table leur attribuait déjà — la correspondance existait en double et seul le
document la tenait. Et la table attribuait AFF-030 (« inventaire complet ») à
P15, qui valide le modèle socle ; c'est P16 qui exécute
`ansible-inventory --list`.
35 affirmations référencées, aucune référence orpheline.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 09:36:30 -04:00
|
|
|
{"id": "P06", "titre": "Validateurs de registres (serveurs/apps/bases/domaines)", "refs": ["AFF-003"],
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
"refs": ["AFF-003"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/serveurs.py", "verifier"],
|
|
|
|
|
[sys.executable, "scripts/applications.py", "verifier"],
|
|
|
|
|
[sys.executable, "scripts/bases_donnees.py", "verifier"],
|
|
|
|
|
[sys.executable, "scripts/domaines.py", "verifier"]]},
|
|
|
|
|
{"id": "P07", "titre": "GUI (node --check)", "refs": ["AFF-033"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/verifier_gui.py"]]},
|
|
|
|
|
{"id": "P08", "titre": "Orchestration (couches + graphe)", "refs": ["AFF-070"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/orchestrer.py", "verifier"]]},
|
|
|
|
|
{"id": "P09", "titre": "Flux reseau (schema + matrice)", "refs": ["AFF-071"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/resoudre_flux.py", "verifier"]]},
|
|
|
|
|
{"id": "P10", "titre": "Handlers <-> notify", "refs": ["AFF-034", "AFF-035"],
|
|
|
|
|
"func": preuve_handlers},
|
|
|
|
|
{"id": "P11", "titre": "Syntaxe des playbooks (--syntax-check)", "refs": ["AFF-083"],
|
|
|
|
|
"cmds": [["make", "--no-print-directory", "syntaxe"]]},
|
audit : les preuves réseau étaient accrochées à la mauvaise affirmation
P21, P23 et P24 renvoyaient à AFF-001 — « Set-OPS est un moteur Ansible
générique » — sans rapport avec la fédération, l'underlay ni la frontière.
P17, P19 et P20 n'avaient aucune référence. Une preuve accrochée à la
mauvaise affirmation passe au vert et n'atteste de rien de ce qu'on croit.
Ajouté §10 du registre : six affirmations (AFF-101..106) pour l'architecture
réseau et la fédération. La couverture du plan par le panneau est en 🟡, avec
ses exceptions nommées — listes de tables de l'underlay, ports physiques,
nœud de sortie.
Volontairement absente : la justesse des devis. Leur syntaxe dépend d'un
matériel que le dépôt ne possède pas ; six familles ont été confrontées au
commutateur réel, deux étaient fausses, mais c'est une vérification datée et
non une preuve rejouable. Le dépôt n'affirme pas que ses devis s'appliquent,
il affirme qu'ils dérivent.
Corrigé aussi : P03, P06, P12 et P13 portent maintenant les références que la
table leur attribuait déjà — la correspondance existait en double et seul le
document la tenait. Et la table attribuait AFF-030 (« inventaire complet ») à
P15, qui valide le modèle socle ; c'est P16 qui exécute
`ansible-inventory --list`.
35 affirmations référencées, aucune référence orpheline.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 09:36:30 -04:00
|
|
|
{"id": "P12", "titre": "Existence des runbooks cites", "refs": ["AFF-010", "AFF-011", "AFF-012"],
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
"refs": ["AFF-010", "AFF-011", "AFF-012", "AFF-083"], "func": preuve_runbooks},
|
audit : les preuves réseau étaient accrochées à la mauvaise affirmation
P21, P23 et P24 renvoyaient à AFF-001 — « Set-OPS est un moteur Ansible
générique » — sans rapport avec la fédération, l'underlay ni la frontière.
P17, P19 et P20 n'avaient aucune référence. Une preuve accrochée à la
mauvaise affirmation passe au vert et n'atteste de rien de ce qu'on croit.
Ajouté §10 du registre : six affirmations (AFF-101..106) pour l'architecture
réseau et la fédération. La couverture du plan par le panneau est en 🟡, avec
ses exceptions nommées — listes de tables de l'underlay, ports physiques,
nœud de sortie.
Volontairement absente : la justesse des devis. Leur syntaxe dépend d'un
matériel que le dépôt ne possède pas ; six familles ont été confrontées au
commutateur réel, deux étaient fausses, mais c'est une vérification datée et
non une preuve rejouable. Le dépôt n'affirme pas que ses devis s'appliquent,
il affirme qu'ils dérivent.
Corrigé aussi : P03, P06, P12 et P13 portent maintenant les références que la
table leur attribuait déjà — la correspondance existait en double et seul le
document la tenait. Et la table attribuait AFF-030 (« inventaire complet ») à
P15, qui valide le modèle socle ; c'est P16 qui exécute
`ansible-inventory --list`.
35 affirmations référencées, aucune référence orpheline.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 09:36:30 -04:00
|
|
|
{"id": "P13", "titre": "Invariants structurels/doctrinaux", "refs": ["AFF-015", "AFF-022", "AFF-037", "AFF-038", "AFF-062"],
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
"refs": ["AFF-015", "AFF-022", "AFF-037", "AFF-038", "AFF-062"], "func": preuve_structurels},
|
|
|
|
|
{"id": "P14", "titre": "Pas de chemin lab/ code en dur", "refs": ["AFF-097"],
|
|
|
|
|
"func": preuve_pas_lab_code_en_dur},
|
|
|
|
|
{"id": "P15", "titre": "Modele public socle valide", "refs": ["AFF-022", "AFF-099"],
|
|
|
|
|
"func": preuve_modele_socle},
|
audit : les preuves réseau étaient accrochées à la mauvaise affirmation
P21, P23 et P24 renvoyaient à AFF-001 — « Set-OPS est un moteur Ansible
générique » — sans rapport avec la fédération, l'underlay ni la frontière.
P17, P19 et P20 n'avaient aucune référence. Une preuve accrochée à la
mauvaise affirmation passe au vert et n'atteste de rien de ce qu'on croit.
Ajouté §10 du registre : six affirmations (AFF-101..106) pour l'architecture
réseau et la fédération. La couverture du plan par le panneau est en 🟡, avec
ses exceptions nommées — listes de tables de l'underlay, ports physiques,
nœud de sortie.
Volontairement absente : la justesse des devis. Leur syntaxe dépend d'un
matériel que le dépôt ne possède pas ; six familles ont été confrontées au
commutateur réel, deux étaient fausses, mais c'est une vérification datée et
non une preuve rejouable. Le dépôt n'affirme pas que ses devis s'appliquent,
il affirme qu'ils dérivent.
Corrigé aussi : P03, P06, P12 et P13 portent maintenant les références que la
table leur attribuait déjà — la correspondance existait en double et seul le
document la tenait. Et la table attribuait AFF-030 (« inventaire complet ») à
P15, qui valide le modèle socle ; c'est P16 qui exécute
`ansible-inventory --list`.
35 affirmations référencées, aucune référence orpheline.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 09:36:30 -04:00
|
|
|
{"id": "P17", "titre": "Tous les modeles valident (registres + underlay)", "refs": ["AFF-105"],
|
2026-07-22 21:32:42 -04:00
|
|
|
"refs": ["AFF-022", "AFF-099"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/modeles.py", "verifier"]]},
|
|
|
|
|
{"id": "P18", "titre": "Gabarit de voute complet", "refs": ["AFF-026"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/voute.py", "verifier"]]},
|
audit : les preuves réseau étaient accrochées à la mauvaise affirmation
P21, P23 et P24 renvoyaient à AFF-001 — « Set-OPS est un moteur Ansible
générique » — sans rapport avec la fédération, l'underlay ni la frontière.
P17, P19 et P20 n'avaient aucune référence. Une preuve accrochée à la
mauvaise affirmation passe au vert et n'atteste de rien de ce qu'on croit.
Ajouté §10 du registre : six affirmations (AFF-101..106) pour l'architecture
réseau et la fédération. La couverture du plan par le panneau est en 🟡, avec
ses exceptions nommées — listes de tables de l'underlay, ports physiques,
nœud de sortie.
Volontairement absente : la justesse des devis. Leur syntaxe dépend d'un
matériel que le dépôt ne possède pas ; six familles ont été confrontées au
commutateur réel, deux étaient fausses, mais c'est une vérification datée et
non une preuve rejouable. Le dépôt n'affirme pas que ses devis s'appliquent,
il affirme qu'ils dérivent.
Corrigé aussi : P03, P06, P12 et P13 portent maintenant les références que la
table leur attribuait déjà — la correspondance existait en double et seul le
document la tenait. Et la table attribuait AFF-030 (« inventaire complet ») à
P15, qui valide le modèle socle ; c'est P16 qui exécute
`ansible-inventory --list`.
35 affirmations référencées, aucune référence orpheline.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 09:36:30 -04:00
|
|
|
{"id": "P19", "titre": "Le GUI couvre le schema du plan", "refs": ["AFF-106"],
|
2026-07-22 21:32:42 -04:00
|
|
|
"refs": ["AFF-002", "AFF-095"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/couverture_gui.py", "verifier",
|
|
|
|
|
"--tolerer", "nomenclature"]]},
|
audit : les preuves réseau étaient accrochées à la mauvaise affirmation
P21, P23 et P24 renvoyaient à AFF-001 — « Set-OPS est un moteur Ansible
générique » — sans rapport avec la fédération, l'underlay ni la frontière.
P17, P19 et P20 n'avaient aucune référence. Une preuve accrochée à la
mauvaise affirmation passe au vert et n'atteste de rien de ce qu'on croit.
Ajouté §10 du registre : six affirmations (AFF-101..106) pour l'architecture
réseau et la fédération. La couverture du plan par le panneau est en 🟡, avec
ses exceptions nommées — listes de tables de l'underlay, ports physiques,
nœud de sortie.
Volontairement absente : la justesse des devis. Leur syntaxe dépend d'un
matériel que le dépôt ne possède pas ; six familles ont été confrontées au
commutateur réel, deux étaient fausses, mais c'est une vérification datée et
non une preuve rejouable. Le dépôt n'affirme pas que ses devis s'appliquent,
il affirme qu'ils dérivent.
Corrigé aussi : P03, P06, P12 et P13 portent maintenant les références que la
table leur attribuait déjà — la correspondance existait en double et seul le
document la tenait. Et la table attribuait AFF-030 (« inventaire complet ») à
P15, qui valide le modèle socle ; c'est P16 qui exécute
`ansible-inventory --list`.
35 affirmations référencées, aucune référence orpheline.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 09:36:30 -04:00
|
|
|
{"id": "P20", "titre": "Adressage 100% derive du seed (aucun stocke)", "refs": ["AFF-101"],
|
Adressage derive du seul seed index (rupture, mode compact retire)
Principe : les valeurs de configuration se derivent des intrants, elles ne se
reecrivent pas a la main. La nomenclature dupliquait ce qu'index determine deja
(supernet, sous-reseaux, passerelles, VLAN). Corrige en rupture nette.
- inventory_rules : source unique de derivation — supernet_de, base3_de,
sous_reseau_de, passerelle_de, vlan_de. Modele 6 zones encode une fois
(2e octet = 10+index, 3e octet zone = 15+categorie, VLAN = 1000+index*10+zone).
deriver_nomenclature ne lit plus aucun adressage stocke ; mode compact supprime.
- devis_reseau : importe ces helpers (fin de la duplication) ; decouvre les
tenants sur `index` present (filtre vmid_schema retire).
- GUI : `index` devient un INTRANT (section Reseau). Il vit dans la nomenclature
(plan reseau uniforme, contrairement aux intrants des modeles heterogenes) et
le GUI l'ecrit chirurgicalement (une ligne, sans reformater). Le miroir JS
derive le VLAN du seed (fin de la lecture de c.vlan stocke).
- socle public : nomenclature au format maigre.
Preuve P20 (preuve_nomenclature_derivee) : aucune nomenclature ne stocke
d'adressage — garde-fou permanent, teste en negatif.
Valide : DIFF VIDE sur les 3 instances (la derivation reproduit exactement
l'adressage stocke), 7 modeles valident, devis_reseau genere les memes VLAN
(1011-1016 derives), make verifier rc=0 CONFORME 20/20, node --check du GUI OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 02:58:15 -04:00
|
|
|
"refs": ["AFF-001", "AFF-003"], "func": preuve_nomenclature_derivee},
|
audit : les preuves réseau étaient accrochées à la mauvaise affirmation
P21, P23 et P24 renvoyaient à AFF-001 — « Set-OPS est un moteur Ansible
générique » — sans rapport avec la fédération, l'underlay ni la frontière.
P17, P19 et P20 n'avaient aucune référence. Une preuve accrochée à la
mauvaise affirmation passe au vert et n'atteste de rien de ce qu'on croit.
Ajouté §10 du registre : six affirmations (AFF-101..106) pour l'architecture
réseau et la fédération. La couverture du plan par le panneau est en 🟡, avec
ses exceptions nommées — listes de tables de l'underlay, ports physiques,
nœud de sortie.
Volontairement absente : la justesse des devis. Leur syntaxe dépend d'un
matériel que le dépôt ne possède pas ; six familles ont été confrontées au
commutateur réel, deux étaient fausses, mais c'est une vérification datée et
non une preuve rejouable. Le dépôt n'affirme pas que ses devis s'appliquent,
il affirme qu'ils dérivent.
Corrigé aussi : P03, P06, P12 et P13 portent maintenant les références que la
table leur attribuait déjà — la correspondance existait en double et seul le
document la tenait. Et la table attribuait AFF-030 (« inventaire complet ») à
P15, qui valide le modèle socle ; c'est P16 qui exécute
`ansible-inventory --list`.
35 affirmations référencées, aucune référence orpheline.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 09:36:30 -04:00
|
|
|
{"id": "P21", "titre": "Federation : aucun index en collision", "refs": ["AFF-102"],
|
2026-07-23 11:26:01 -04:00
|
|
|
"cmds": [[sys.executable, "scripts/instances.py", "--verifier"]]},
|
2026-07-23 15:49:16 -04:00
|
|
|
{"id": "P22", "titre": "Plan de recette a jour (genere du wiki)", "refs": ["AFF-002"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/plan_recette.py", "--verifier"]]},
|
audit : les preuves réseau étaient accrochées à la mauvaise affirmation
P21, P23 et P24 renvoyaient à AFF-001 — « Set-OPS est un moteur Ansible
générique » — sans rapport avec la fédération, l'underlay ni la frontière.
P17, P19 et P20 n'avaient aucune référence. Une preuve accrochée à la
mauvaise affirmation passe au vert et n'atteste de rien de ce qu'on croit.
Ajouté §10 du registre : six affirmations (AFF-101..106) pour l'architecture
réseau et la fédération. La couverture du plan par le panneau est en 🟡, avec
ses exceptions nommées — listes de tables de l'underlay, ports physiques,
nœud de sortie.
Volontairement absente : la justesse des devis. Leur syntaxe dépend d'un
matériel que le dépôt ne possède pas ; six familles ont été confrontées au
commutateur réel, deux étaient fausses, mais c'est une vérification datée et
non une preuve rejouable. Le dépôt n'affirme pas que ses devis s'appliquent,
il affirme qu'ils dérivent.
Corrigé aussi : P03, P06, P12 et P13 portent maintenant les références que la
table leur attribuait déjà — la correspondance existait en double et seul le
document la tenait. Et la table attribuait AFF-030 (« inventaire complet ») à
P15, qui valide le modèle socle ; c'est P16 qui exécute
`ansible-inventory --list`.
35 affirmations référencées, aucune référence orpheline.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 09:36:30 -04:00
|
|
|
{"id": "P23", "titre": "Underlay sans collision avec la plage tenant", "refs": ["AFF-103"],
|
2026-07-24 14:56:38 -04:00
|
|
|
"cmds": [[sys.executable, "scripts/underlay.py", "--verifier"]]},
|
pare-feu Proxmox : le filtrage est-ouest intra-tenant, dérivé (P25)
`make devis-proxmox-fw` : 34 groupes de sécurité, 40 règles, 2 tenants —
depuis les 57 flux intra-tenant que le registre connaissait déjà.
Défense en profondeur, pas remplacement : l'hyperviseur filtre puis l'hôte
destinataire filtre à nouveau. Coût de maintenance nul, les deux barrières
lisent le registre par les MÊMES fonctions — la duplication est dans
l'application, jamais dans la décision.
Un IPSet par rôle porte les membres, les groupes y renvoient : ajouter un
hôte à un rôle met à jour toutes les règles qui l'autorisent, en un endroit.
Garde ajoutée après coup : Proxmox limite un nom de groupe à 18 caractères.
Ma première version tronquait sans vérifier — deux rôles tronqués au même nom
auraient fusionné leurs règles, donnant à une VM les autorisations d'un rôle
qu'elle ne porte pas, silencieusement. Le préfixe porte maintenant l'index
plutôt que l'étiquette, et une garde échoue sur toute collision. Exercée.
Conséquence consignée : tout ce qui entre dans un tenant passant par la
frontière, le contrôleur Ansible aussi — l'OPNsense devient un prérequis de
déploiement, pas une étape parmi d'autres.
Preuves : 25 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 11:43:32 -04:00
|
|
|
{"id": "P25", "titre": "Pare-feu Proxmox : est-ouest intra-tenant derive", "refs": ["AFF-107"],
|
|
|
|
|
"cmds": [[sys.executable, "scripts/devis_proxmox_fw.py", "--verifier"]]},
|
audit : les preuves réseau étaient accrochées à la mauvaise affirmation
P21, P23 et P24 renvoyaient à AFF-001 — « Set-OPS est un moteur Ansible
générique » — sans rapport avec la fédération, l'underlay ni la frontière.
P17, P19 et P20 n'avaient aucune référence. Une preuve accrochée à la
mauvaise affirmation passe au vert et n'atteste de rien de ce qu'on croit.
Ajouté §10 du registre : six affirmations (AFF-101..106) pour l'architecture
réseau et la fédération. La couverture du plan par le panneau est en 🟡, avec
ses exceptions nommées — listes de tables de l'underlay, ports physiques,
nœud de sortie.
Volontairement absente : la justesse des devis. Leur syntaxe dépend d'un
matériel que le dépôt ne possède pas ; six familles ont été confrontées au
commutateur réel, deux étaient fausses, mais c'est une vérification datée et
non une preuve rejouable. Le dépôt n'affirme pas que ses devis s'appliquent,
il affirme qu'ils dérivent.
Corrigé aussi : P03, P06, P12 et P13 portent maintenant les références que la
table leur attribuait déjà — la correspondance existait en double et seul le
document la tenait. Et la table attribuait AFF-030 (« inventaire complet ») à
P15, qui valide le modèle socle ; c'est P16 qui exécute
`ansible-inventory --list`.
35 affirmations référencées, aucune référence orpheline.
Preuves : 24 OK, 0 échec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 09:36:30 -04:00
|
|
|
{"id": "P24", "titre": "Frontiere nord/sud : acces d'administration declare", "refs": ["AFF-104"],
|
frontière nord/sud : devis dérivé, lien de transit et les deux routes
La bordure devient un artefact dérivé, comme le devis switch — et le chemin
qui y mène est enfin déclaré.
`make devis-opnsense` (+ preuve P24) dérive la politique de bordure du
registre des flux : les flux `pair: externe`, que `resoudre_flux.py` saute
volontairement parce qu'ils relèvent de la frontière et non du pare-feu
d'hôte. Aucun port, aucune adresse, aucun nom d'hôte dans le générateur.
Le lien manquait dans tous les fichiers : le devis switch ne contenait pas
une seule `ip route`. Un réseau underlay portant `passerelle_sortie` le
déclare — il vit dans l'underlay et non dans un tenant parce que la
frontière route vers TOUS les supernets tenants par le même saut, donc il
ne peut dériver d'aucun `index`. `devis-reseau` en tire deux routes :
l'aller (sortie générale) et le retour vers l'administration, dont l'absence
a coûté la passe de déploiement du 2026-07-29 — la réponse revient au
pare-feu par une autre interface que celle où l'état a été créé, et se fait
jeter en silence.
Les réseaux d'administration viennent de l'intrant `nftables_admin_ssh` :
même source unique que la garde anti-lockout des nftables et l'alias
SETOPS_ADMIN. Les trois pare-feux et les routes ne peuvent plus diverger.
La frontière est réglable depuis la console (section « Frontière » du
panneau Intrants) ; les identifiants d'API restent interdits d'écriture par
le GUI et vivent dans la voûte.
Correctifs de la même passe :
- le panneau refusait d'enregistrer les intrants de la frontière : le
garde-fou confondait une référence de voûte `{{ vault_* }}` préservée
avec un secret soumis. Il regarde désormais la valeur, pas le nom.
- `supprimer_vm_debian.yml` ne chargeait que `proxmox.vault.yml` pour ses
secrets ; retirer ce reliquat aurait cassé `make detruire`. Aligné sur le
playbook de clonage, voûte unique en dernier.
- documentation : la voûte est unique, `proxmox.vault.yml` n'est qu'un
reliquat de compatibilité.
Preuves : 24 OK, 0 échec. Cas de rejet du validateur d'underlay exercés un
par un ; résolution du jeton Proxmox vérifiée en exécution réelle.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 19:32:04 -04:00
|
|
|
"cmds": [[sys.executable, "scripts/devis_opnsense.py", "--verifier"]]},
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _vault_requis_absent() -> bool:
|
|
|
|
|
"""Vrai si l'inventaire chiffre un group_vars et qu'aucun mot de passe n'est fourni."""
|
|
|
|
|
if os.environ.get("ANSIBLE_VAULT_PASSWORD_FILE"):
|
|
|
|
|
return False
|
|
|
|
|
gv = (RACINE / INV).parent / "group_vars"
|
|
|
|
|
if not gv.exists():
|
|
|
|
|
return False
|
|
|
|
|
for f in gv.rglob("*"):
|
|
|
|
|
if f.is_file():
|
|
|
|
|
try:
|
|
|
|
|
if f.read_text(encoding="utf-8", errors="ignore").startswith("$ANSIBLE_VAULT"):
|
|
|
|
|
return True
|
|
|
|
|
except OSError:
|
|
|
|
|
continue
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
2026-07-24 14:56:38 -04:00
|
|
|
def _underlay_absent() -> bool:
|
|
|
|
|
"""Vrai si aucun underlay.yml n'est defini (fabric non decrite : rien a prouver)."""
|
|
|
|
|
import underlay
|
|
|
|
|
return underlay.chemin() is None
|
|
|
|
|
|
|
|
|
|
|
frontière nord/sud : devis dérivé, lien de transit et les deux routes
La bordure devient un artefact dérivé, comme le devis switch — et le chemin
qui y mène est enfin déclaré.
`make devis-opnsense` (+ preuve P24) dérive la politique de bordure du
registre des flux : les flux `pair: externe`, que `resoudre_flux.py` saute
volontairement parce qu'ils relèvent de la frontière et non du pare-feu
d'hôte. Aucun port, aucune adresse, aucun nom d'hôte dans le générateur.
Le lien manquait dans tous les fichiers : le devis switch ne contenait pas
une seule `ip route`. Un réseau underlay portant `passerelle_sortie` le
déclare — il vit dans l'underlay et non dans un tenant parce que la
frontière route vers TOUS les supernets tenants par le même saut, donc il
ne peut dériver d'aucun `index`. `devis-reseau` en tire deux routes :
l'aller (sortie générale) et le retour vers l'administration, dont l'absence
a coûté la passe de déploiement du 2026-07-29 — la réponse revient au
pare-feu par une autre interface que celle où l'état a été créé, et se fait
jeter en silence.
Les réseaux d'administration viennent de l'intrant `nftables_admin_ssh` :
même source unique que la garde anti-lockout des nftables et l'alias
SETOPS_ADMIN. Les trois pare-feux et les routes ne peuvent plus diverger.
La frontière est réglable depuis la console (section « Frontière » du
panneau Intrants) ; les identifiants d'API restent interdits d'écriture par
le GUI et vivent dans la voûte.
Correctifs de la même passe :
- le panneau refusait d'enregistrer les intrants de la frontière : le
garde-fou confondait une référence de voûte `{{ vault_* }}` préservée
avec un secret soumis. Il regarde désormais la valeur, pas le nom.
- `supprimer_vm_debian.yml` ne chargeait que `proxmox.vault.yml` pour ses
secrets ; retirer ce reliquat aurait cassé `make detruire`. Aligné sur le
playbook de clonage, voûte unique en dernier.
- documentation : la voûte est unique, `proxmox.vault.yml` n'est qu'un
reliquat de compatibilité.
Preuves : 24 OK, 0 échec. Cas de rejet du validateur d'underlay exercés un
par un ; résolution du jeton Proxmox vérifiée en exécution réelle.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 19:32:04 -04:00
|
|
|
def _frontiere_absente() -> bool:
|
|
|
|
|
"""Vrai si aucune instance n'est active (depot public nu : aucune frontiere a prouver)."""
|
|
|
|
|
return not (RACINE / "instance").exists()
|
|
|
|
|
|
|
|
|
|
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
def _executer(preuve: dict) -> tuple[str, str]:
|
|
|
|
|
"""Renvoie (statut, detail). statut in {OK, ECHEC, SAUTE}."""
|
|
|
|
|
if "func" in preuve:
|
|
|
|
|
ok, detail = preuve["func"]()
|
|
|
|
|
return ("OK" if ok else "ECHEC"), detail
|
|
|
|
|
dernier = ""
|
|
|
|
|
for cmd in preuve["cmds"]:
|
|
|
|
|
r = subprocess.run(cmd, cwd=RACINE, capture_output=True, text=True, timeout=600)
|
|
|
|
|
sortie = [l for l in (r.stdout + r.stderr).strip().splitlines()
|
|
|
|
|
if l.strip() and not l.lstrip().startswith("[WARNING]")]
|
|
|
|
|
dernier = sortie[-1] if sortie else ""
|
|
|
|
|
if r.returncode != 0:
|
|
|
|
|
return "ECHEC", f"rc={r.returncode} : {dernier}"
|
|
|
|
|
return "OK", dernier
|
|
|
|
|
|
|
|
|
|
|
2026-07-20 21:03:20 -04:00
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
|
|
|
argv = sys.argv[1:] if argv is None else argv
|
|
|
|
|
# --verifier : execute les preuves (verdict + code de sortie) sans ecrire de rapport,
|
|
|
|
|
# pour un appel depuis `make verifier` (evite d'ecraser la piece justificative committee).
|
|
|
|
|
ecrire_rapport = "--verifier" not in argv
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
date = _dt.date.today().isoformat()
|
|
|
|
|
resultats: list[tuple[dict, str, str]] = []
|
|
|
|
|
|
|
|
|
|
# Preuve conditionnelle : inventaire Ansible complet (necessite la voute).
|
|
|
|
|
preuve_inv = {"id": "P16", "titre": "Inventaire Ansible complet (--list)",
|
2026-07-20 20:47:36 -04:00
|
|
|
"refs": ["AFF-030"], "func": preuve_inventaire_ansible}
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
liste = list(PREUVES)
|
|
|
|
|
if _vault_requis_absent():
|
|
|
|
|
resultats.append((preuve_inv, "SAUTE",
|
|
|
|
|
"Voute chiffree sans ANSIBLE_VAULT_PASSWORD_FILE (prerequis AFF-026)."))
|
|
|
|
|
else:
|
|
|
|
|
liste.append(preuve_inv)
|
|
|
|
|
|
2026-07-24 14:56:38 -04:00
|
|
|
# Preuve conditionnelle : underlay (fabric physique). Sautee si non definie.
|
|
|
|
|
if _underlay_absent():
|
|
|
|
|
p23 = next((p for p in liste if p["id"] == "P23"), None)
|
|
|
|
|
if p23:
|
|
|
|
|
liste.remove(p23)
|
|
|
|
|
resultats.append((p23, "SAUTE", "Aucun underlay.yml (fabric non definie) — rien a prouver."))
|
|
|
|
|
|
frontière nord/sud : devis dérivé, lien de transit et les deux routes
La bordure devient un artefact dérivé, comme le devis switch — et le chemin
qui y mène est enfin déclaré.
`make devis-opnsense` (+ preuve P24) dérive la politique de bordure du
registre des flux : les flux `pair: externe`, que `resoudre_flux.py` saute
volontairement parce qu'ils relèvent de la frontière et non du pare-feu
d'hôte. Aucun port, aucune adresse, aucun nom d'hôte dans le générateur.
Le lien manquait dans tous les fichiers : le devis switch ne contenait pas
une seule `ip route`. Un réseau underlay portant `passerelle_sortie` le
déclare — il vit dans l'underlay et non dans un tenant parce que la
frontière route vers TOUS les supernets tenants par le même saut, donc il
ne peut dériver d'aucun `index`. `devis-reseau` en tire deux routes :
l'aller (sortie générale) et le retour vers l'administration, dont l'absence
a coûté la passe de déploiement du 2026-07-29 — la réponse revient au
pare-feu par une autre interface que celle où l'état a été créé, et se fait
jeter en silence.
Les réseaux d'administration viennent de l'intrant `nftables_admin_ssh` :
même source unique que la garde anti-lockout des nftables et l'alias
SETOPS_ADMIN. Les trois pare-feux et les routes ne peuvent plus diverger.
La frontière est réglable depuis la console (section « Frontière » du
panneau Intrants) ; les identifiants d'API restent interdits d'écriture par
le GUI et vivent dans la voûte.
Correctifs de la même passe :
- le panneau refusait d'enregistrer les intrants de la frontière : le
garde-fou confondait une référence de voûte `{{ vault_* }}` préservée
avec un secret soumis. Il regarde désormais la valeur, pas le nom.
- `supprimer_vm_debian.yml` ne chargeait que `proxmox.vault.yml` pour ses
secrets ; retirer ce reliquat aurait cassé `make detruire`. Aligné sur le
playbook de clonage, voûte unique en dernier.
- documentation : la voûte est unique, `proxmox.vault.yml` n'est qu'un
reliquat de compatibilité.
Preuves : 24 OK, 0 échec. Cas de rejet du validateur d'underlay exercés un
par un ; résolution du jeton Proxmox vérifiée en exécution réelle.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 19:32:04 -04:00
|
|
|
# Preuve conditionnelle : frontiere nord/sud. Sautee sans instance active.
|
|
|
|
|
if _frontiere_absente():
|
|
|
|
|
p24 = next((p for p in liste if p["id"] == "P24"), None)
|
|
|
|
|
if p24:
|
|
|
|
|
liste.remove(p24)
|
|
|
|
|
resultats.append((p24, "SAUTE", "Aucune instance active — aucune frontiere a prouver."))
|
|
|
|
|
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
for preuve in liste:
|
|
|
|
|
statut, detail = _executer(preuve)
|
|
|
|
|
resultats.append((preuve, statut, detail))
|
|
|
|
|
|
2026-07-22 21:32:42 -04:00
|
|
|
# Tri : garder l'ordre d'execution (P01..P19) ; la preuve sautee a ete inseree tot.
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
resultats.sort(key=lambda r: r[0]["id"])
|
|
|
|
|
|
|
|
|
|
n_ok = sum(1 for _, s, _ in resultats if s == "OK")
|
|
|
|
|
n_echec = sum(1 for _, s, _ in resultats if s == "ECHEC")
|
|
|
|
|
n_saute = sum(1 for _, s, _ in resultats if s == "SAUTE")
|
|
|
|
|
conforme = n_echec == 0
|
2026-07-20 21:03:20 -04:00
|
|
|
print(f"{'CONFORME' if conforme else 'NON CONFORME'} : "
|
|
|
|
|
f"{n_ok} OK, {n_echec} echec, {n_saute} saute.")
|
|
|
|
|
if not ecrire_rapport:
|
|
|
|
|
return 0 if conforme else 1
|
|
|
|
|
|
Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.
- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
une commande de preuve et un statut (✅/🟡/❌/⚪).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
chemins de voûte faux, commandes make périmées) ; make verifier vert
(ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
corrigé (repli sur le répertoire existant, pas principal/).
make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00
|
|
|
icone = {"OK": "✅", "ECHEC": "❌", "SAUTE": "⚪"}
|
|
|
|
|
|
|
|
|
|
lignes = [
|
|
|
|
|
f"# Preuve de conformite — Set-OPS — {date}",
|
|
|
|
|
"",
|
|
|
|
|
"> 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).",
|
|
|
|
|
"",
|
|
|
|
|
f"- **Instance** : `{INSTANCE}` — inventaire `{INV}`",
|
|
|
|
|
f"- **Verdict** : {'✅ CONFORME' if conforme else '❌ NON CONFORME'} "
|
|
|
|
|
f"({n_ok} OK · {n_echec} echec · {n_saute} saute)",
|
|
|
|
|
"",
|
|
|
|
|
"## Preuves",
|
|
|
|
|
"",
|
|
|
|
|
"| # | Preuve | Affirmations | Statut | Detail |",
|
|
|
|
|
"|---|---|---|---|---|",
|
|
|
|
|
]
|
|
|
|
|
for preuve, statut, detail in resultats:
|
|
|
|
|
refs = ", ".join(preuve["refs"]) or "—"
|
|
|
|
|
det = detail.replace("|", "\\|")[:160]
|
|
|
|
|
lignes.append(f"| {preuve['id']} | {preuve['titre']} | {refs} | {icone[statut]} {statut} | {det} |")
|
|
|
|
|
|
|
|
|
|
lignes += [
|
|
|
|
|
"",
|
|
|
|
|
"## 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.",
|
|
|
|
|
"",
|
|
|
|
|
f"_Rapport genere le {date}._",
|
|
|
|
|
"",
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
DOSSIER_AUDIT.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
rapport = DOSSIER_AUDIT / f"preuve-{date}.md"
|
|
|
|
|
rapport.write_text("\n".join(lignes), encoding="utf-8")
|
|
|
|
|
print(f"Rapport : {rapport.relative_to(RACINE)}")
|
|
|
|
|
return 0 if conforme else 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2026-07-20 21:03:20 -04:00
|
|
|
raise SystemExit(main(sys.argv[1:]))
|