# CHANGELOG — Set-OPS ## 2026-07-01 ### Ajouté - **État RÉEL vs plan dans le GUI (sonde de vie + auto-actif).** Le badge `planifié`/ `actif` décrit l'*intention* du plan, pas l'existence de la VM — d'où la confusion « serveur planifié mais vivant ». Deux ajouts : - **Sonde de vie** : le GUI teste la joignabilité SSH de chaque hôte en arrière-plan (`/api/sondes`, en parallèle) et affiche un état réel — **● vivante** / **● injoignable** — sur les tuiles et dans le détail (« Plan : … · Réel : … »), distinct du plan. - **Auto-actif** : un hôte qu'on **matérialise** (clone `creer` réussi) ou qu'on **déploie** passe automatiquement `actif` dans le plan (matérialisé = actif), puis l'inventaire est **régénéré** pour que le changement se voie partout (en-tête inclus). - **Compteur « vivantes »** dans l'en-tête (depuis la sonde), à côté de actifs/planifiés. ### Corrigé - **nginx ne validait pas sur Debian 13 (`server_tokens` en double).** Debian 13 livre `server_tokens off;` **actif** dans `/etc/nginx/nginx.conf` (avant : commenté). Le drop-in `conf.d/99-setops.conf` du rôle le redéclarait → `nginx -t` échouait (« directive is duplicate ») et le déploiement plantait au handler de validation. Le rôle `serveur_nginx` neutralise désormais la ligne distro (le drop-in reste l'unique source). Trouvé en déployant nginx pour de vrai sur un hôte edge. - **Une voûte chiffrée cassait `instancier` / « Appliquer le plan ».** `ansible-inventory --list` (utilisé pour la comparaison sémantique du plan) tente de déchiffrer `group_vars/all/vault.yml` et échoue sans mot de passe (`exit 4`) — alors que l'opération est structurelle, sans secret. `instancier` utilise désormais automatiquement le fichier conventionnel `~/.config/setops-vault-pass` (si `ANSIBLE_VAULT_PASSWORD_FILE` n'est pas déjà défini). - **Secrets des rôles non câblés à la voûte (échafaudage manquant).** Les rôles à secrets déclaraient `serveur_X_password: ""` avec, en commentaire seulement, la variable de voûte attendue (`{{ vault_X }}`) — sans mapping réel. Résultat : remplir la voûte selon `vault.exemple.yml` ne suffisait pas, le secret restait vide et l'assertion « secrets requis » échouait. Les 12 secrets des 8 rôles (`serveur_step_ca`, `serveur_forgejo`, `serveur_grafana`, `serveur_keycloak`, `serveur_openldap`, `serveur_redis`, `client_ldap`, `client_pki`) pointent désormais vers leur variable de voûte : `serveur_X_password: "{{ vault_X | default('') }}"`. Chaque instance n'a plus qu'à remplir ses `vault_*` dans sa voûte chiffrée ; aucun mapping par instance. - **« Vérifier » (dry-run `--check`) échouait faussement sur un hôte frais.** Les tâches « démarrer service » et les handlers « redémarrer / recharger / valider » des rôles applicatifs touchent un paquet que `--check` n'installe pas réellement → le service (ou le fichier de zone/conf) n'existe pas encore → faux `fatal`, qui **bloquait le déploiement** (le dry-run doit réussir pour débloquer « Déployer »). Ajout de `when: not ansible_check_mode` sur ces tâches et handlers des 13 rôles `serveur_*` (29 gardes). En dry-run elles sont sautées ; en vrai déploiement, inchangées. - **Le bouton ⚙ « Appliquer le plan » du GUI refusait en silence** dès que le plan divergeait de l'inventaire (il appelait `instancier appliquer` **sans** `--force`). Résultat : après une édition (disque, état, auto-actif), l'inventaire n'était jamais régénéré et les compteurs restaient figés. Le clic « Appliquer » **est** l'intention explicite → le GUI force désormais (git reste le filet). - **Bouton « Pousser » dans le GUI — le flux devient 100 % cliquable.** Chaque objet du détail se matérialise sur son hôte, en streaming console (avec mot de passe vault + confirmation renforcée en prod) : - **Serveur** → `🖥 Pousser` clone la VM depuis le golden template (`make creer-vm`), disponible même sur un hôte planifié — comble le trou : le GUI ne clonait pas. - **Application** → `Pousser` déploie l'hôte porteur (`make deployer HOTE=`). - **Base** → `Pousser` déploie l'hôte du serveur de BD (crée la base). Nouveaux modes `creer` / `pousser` dans `executer_flux` + routes `/api/creer` et `/api/pousser`. Flux complet depuis l'interface : éditer → ⚙ Appliquer → 🖥 Pousser → Vérifier → Déployer. - **Premier déploiement RÉEL validé de bout en bout** (cluster asgard) : flux canonique plan-piloté clonant + durcissant + faisant tourner un PowerDNS qui résout. Voir les 3 correctifs ci-dessous. ## 2026-06-30 ### Ajouté - **Plancher de résolution `/etc/hosts` (indépendant du DNS).** Nouveau rôle de socle `hosts_statiques` (dans `serveur_debian`) : génère `/etc/hosts` sur **chaque** VM depuis l'inventaire (nom + FQDN interne → IP réelle). Tout l'écosystème se résout par nom **même serveur DNS éteint**, et le bootstrap ne dépend plus du DNS. PowerDNS devient une **commodité** (zone/externe/dynamique) ; `client_dns` est rendu tolérant (inerte si aucun DNS interne) et sa dépendance à `serveur_powerdns` passe **molle**. - **Adressage fédéré : index d'instance.** Le VMID n'est plus codé `9CSNN` en dur : il prend le préfixe d'un `index` déclaré en tête de `plan/nomenclature.yml` (`{index}{catégorie}{service}{séq}`). Convention : `supernet = 10.(10+index).0.0/16`, `VMID = index·CSNN`. Permet à N écosystèmes de **coexister/s'interconnecter** sans collision (Chezlepro=1 → `10.11`/`1xxxx`, Technolibre=2 → `10.12`/`2xxxx`). Sans index → `9CSNN` (rétro-compatible ; bacs à sable, plages ad-hoc `172.19.x`). Code mort retiré (`deriveServeur` JS). Voir `docs/multi-instances.md`. - **Doc `docs/multi-instances.md`** : cadrage « un moteur, N écosystèmes » — l'instance comme dépôt autonome, la bascule, l'isolation, et le socle multi-tenant. - **Bascule d'instance (`make instance-utiliser NOM=…`).** Repointe le symlink `instance` vers un autre dépôt d'instance (prod ↔ bac à sable) ; `make instance-courante` affiche l'instance montée. Permet d'exploiter plusieurs instances (séparation **par instance**) depuis un seul moteur. - **Identité des intrants relative à l'inventaire.** Le panneau « Intrants » lit/écrit l'identité dans `group_vars/all/10-intrants.yml` de l'inventaire monté (fichier réel pour une instance autonome, symlink vers une source partagée sinon — l'écriture suit le symlink). Fonctionne donc aussi bien pour une instance « par instance » que pour l'ancien partage lab/production. - **Inventaire d'instance neutre et configurable (`principal` / `SETOPS_INVENTAIRE`).** Le moteur (Makefile + `inventory_gui`, `instancier`, `config_proxmox`, `serveurs`, `applications`) ne code plus en dur `inventories/lab` / `inventories/production` : il vise **un inventaire par instance**, détecté de façon **rétro-compatible** (`principal` > `production` > `lab`) et surchargeable par `SETOPS_INVENTAIRE`. Les instances existantes (découpage lab/production) continuent de fonctionner à l'identique ; les nouvelles peuvent adopter `inventories/principal/`. Deuxième pierre de la séparation **par instance** (la 1re étant le drapeau `setops_production`). - **Garde-fou de prudence par instance (`setops_production`).** Le déploiement réel est désormais possible sur **toute instance** (un bac à sable déploie sur *son* infra lab — il est isolé **et** fonctionnel). Le drapeau `setops_production` dans `group_vars/all/` ne **bloque** plus rien : il marque la PRODUCTION pour exiger une **confirmation renforcée** au déploiement (bannière/badge rouge « PROD », bouton Déployer en rouge, re-saisie du nom d'hôte) ; un bac à sable (`false`) affiche « bac à sable » et déploie sans cette étape. Rétro-compatible (à défaut de drapeau, ancien repère « inventaire production »). Le GUI affiche toujours quel type d'instance est monté. ### Modifié - **Voûte de secrets unique par environnement.** Fini les voûtes éparpillées : tous les secrets de l'instance (token Proxmox + 17 `vault_*` pour PKI, LDAP/SSO, bases, forge, observabilité) vivent dans **un seul fichier chiffré**, `inventories//group_vars/all/vault.yml`. Gabarit committé `exemples/vault.exemple.yml`. `make config` (`config_proxmox.py`) écrit/édite désormais cette voûte (semée depuis le gabarit si absente). `.gitignore` durci (`**/vault.yml`). Docs mises à jour (config-proxmox.md avec étapes de migration, intrants-communs.md §H, QUICKSTART). Le GUI ne stocke toujours aucun secret. ### Corrigé - **Trois bugs trouvés au premier déploiement réel (cluster asgard).** - **Clonage/Makefile codaient `inventories/lab` en dur** (config Proxmox + voûte) — vestige du modèle env qui cassait les instances `principal`. Le playbook de clonage et le Makefile détectent maintenant l'inventaire (`lab` > `principal` > `production`). - **Redimensionnement disque non idempotent** : quand le disque dérivé du plan est plus petit que le golden template, Proxmox refuse (`shrinking disks is not supported`) et le clone échouait. Le resize est désormais **grow-only** (tolère le cas, la VM garde le disque du template — le dérivé est un minimum). - **PowerDNS refusait de démarrer** (`multiple backends 'bind'`) : le rôle redéclarait `launch+=bind` que le paquet `pdns-backend-bind` pose déjà. Le rôle ne déclare plus `launch` (seulement `bind-config`). - **`chezlepro_timezone` n'était appliqué nulle part.** Cet intrant de base global était défini mais aucun rôle ne s'en servait. Le rôle `chrony` (appliqué à tout hôte via `serveur_debian`) règle désormais le fuseau horaire à partir de `chezlepro_timezone` (`chrony_timezone` par défaut, vide = ne pas toucher). Les autres défauts globaux (nœud / stockage / pont Proxmox) étaient déjà réutilisés comme valeurs par défaut, surchargeables par hôte. ### Modifié - **Détail GUI : section « Groupes (dérivés) » retirée (redondante).** Depuis la fusion en atelier maître-détail, elle ne répétait que le socle (universel), les rôles des applications (déjà dans « Applications ici ») et les intégrations (déjà cochées). Son seul signal unique — le prérequis bloquant — est désormais nommé dans le pied (« Prérequis manquant : … ») ; le panneau Dépendances reste pour la vue d'ensemble. Code mort retiré (`renduGroupe`, `detailGroupe`, `titreGroupe`, CSS `.groupe*`). - **Nettoyage CSS/HTML du GUI** après la refonte : retrait des règles et éléments morts (`.message`, `.chips-filtre`/`.chip-f`, `.onglet*`, `.base-ligne`, `.bases-liste`, `.ch-grp*`/`.ch-fleche`/`.ch-roles`, `.champ-val`, divs `#message` et `#chips`). - **GUI refondu en atelier maître-détail unifié.** Toutes les vues suivent le même motif : tuiles à gauche, **détail + saisie à droite**, le panneau droit reflétant la sélection de la vue courante (fin du panneau « figé » au changement de vue). Les vues **Applications** et **Bases** passent de tableaux pleine largeur à ce motif ; la saisie se fait dans le panneau droit, avec **liens cliquables** entre objets (serveur → application → base). Le panneau droit est élargi (~38 %). - **Fusion Serveur/Hôte.** Les vues « Inventaire » (hôtes, lecture seule) et « Serveurs » (plan) faisaient doublon : elles sont fusionnées en **une seule vue Serveurs**. Sa tuile porte le statut de réconciliation (réconcilié / divergent / non instancié) ; son détail réunit l'**identité éditable** (plan), les **dérivés** (VMID/IP/VLAN), les **groupes**, les **applications et bases hébergées**, et **Vérifier/Déployer**. La navigation clavier (`1-3`, `j/k`, `v/d`, `/`) et le filtre opèrent désormais sur les serveurs. Un bandeau « Comment lire ce parc » explicite le modèle serveur·hôte·groupe·application·base. Code mort retiré (`carte`, `renduChaine`, `ONGLETS`, `champLecture`, sélection d'hôte, etc.). ### Ajouté - **Fluidité d'exploitation du GUI** (sans dépendance, stdlib pure) : - **Notifications empilées (toasts)** auto-effaçables au lieu d'une bannière unique écrasée ; les erreurs restent plus longtemps, les opérations longues mettent à jour leur propre toast. - **Durée d'exécution** affichée en direct dans la console (Vérifier / Déployer) et suivi vivant de « Appliquer le plan ». - **Navigation clavier** : `1-5` changent de vue, `j/k` parcourent les hôtes, `v`/`d` vérifient/déploient l'hôte sélectionné, `/` cible le filtre, `Ctrl+S` sauvegarde la vue éditable courante (ignorés pendant la saisie). - **Validation inline** des champs du plan (vue Serveurs) : nom `fonction-NN`, mémoire, cœurs, disque — liseré rouge et blocage avant l'envoi. - **Garde-fou anti-perte** : confirmation `beforeunload` si des éditions de plan ne sont pas sauvegardées. - Le bouton **Sauvegarder** de l'en-tête devient contextuel (sauve la vue éditable, désactivé en lecture seule) — fin de l'impasse 409 ; suppression du code mort. ### Ajouté - **Vue Serveurs : champs alimentés par les paramètres globaux.** À `+ Serveur`, **Nœud** et **Stockage** deviennent des listes déroulantes (catalogues `proxmox_noeuds` / `proxmox_stockages`, vide = défaut global) et **Intégrations** une rangée de cases à cocher des rôles `client_*` disponibles (au lieu d'une saisie texte). Les catalogues Nœuds / Stockages / Ponts sont de nouveaux intrants (classe « Catalogue ») éditables dans le panneau « Intrants de base » et stockés dans `group_vars/proxmox.yml` ; l'API expose `integrations_disponibles` (scan de `roles/client_*`). Le type `liste` (chaîne virgulée → liste YAML dédoublonnée) est ajouté au schéma des intrants. ### Supprimé - **Vue « Chaîne » du bandeau (redondante).** Son contenu (`renduChaine`) était déjà rendu, par hôte, dans l'onglet « Chaîne » du détail de la vue Inventaire ; la vue ne faisait que le répéter pour tous les hôtes à la fois, sans réseau/proxmox ni boutons d'opération. Retirée (bouton, rendu `dessinerArbre`, CSS `.arbre-*`) ; la chaîne reste consultable hôte par hôte. Raccourcis clavier ramenés à 1-4. ### Modifié - **Vue Inventaire (cartes) : détail converti en inspection lecture seule.** La vue affichait « généré depuis le plan (lecture seule) » tout en exposant une surface d'édition (+ Hôte, ✕, bascule actif/planifié, ✨ Proposer, champs et cases de groupes éditables) qui ne pouvait pas être persistée (l'inventaire est généré ; `/api/inventaire` renvoie 409). Ces contrôles orphelins sont retirés : nom, champs Réseau/Proxmox et groupes en lecture seule, état affiché en badge. **Vérifier / Déployer** et les onglets d'inspection sont conservés. L'édition reste dans les vues **Serveurs / Applications / Bases**. Code mort supprimé (`ajouterHote`, `supprimerHote`, `definir`, `definirNom`, `definirEtat`, `basculerGroupe`, `proposer`, `autoProposer`, `prochainSeqLibre`, `marquerModifie`, état `modifie`). - **Référence des paramètres de `make config`** (`docs/config-proxmox.md`). Explique un par un les 16 paramètres Proxmox non sensibles + les secrets API demandés par l'assistant : sens, valeur par défaut, quoi saisir, et quels champs sont des constantes vs des défauts surchargeables par hôte. Renvois ajoutés depuis `make help` et `QUICKSTART.md`. Comble un trou : ces invites n'étaient expliquées nulle part de façon pérenne (impératif « exploitable sans IA »). - **Panneau « Intrants de base » dans le GUI.** Un bouton ⚙ Intrants ouvre une fenêtre unique pour saisir les valeurs communes à tout l'écosystème, avec une distinction visible entre **constantes** (valeur unique, non surchargeable) et **défauts** (valeurs proposées, surchargeables dans les instances). Les secrets ne sont **jamais** saisis ni affichés ici (garde-fou `INTRANTS_CLES_INTERDITES` + filtrage par schéma) : ils restent dans le Vault Ansible, édités en CLI ; le panneau les liste seulement à titre informatif. Un changement de `domaine_interne` (clé de voûte) demande une confirmation explicite ; un `domaine_interne` vide est refusé côté serveur. La nomenclature reste en lecture seule (modifiable dans le plan). Voir `docs/intrants-communs.md` et `docs/intrants-base-gui-conception.md`. - **Source unique d'identité partagée.** `domaine_interne` et `chezlepro_timezone` vivent désormais dans `inventories/partage/intrants-identite.yml`, référencé par symlink depuis chaque environnement (`group_vars/all/10-intrants.yml`) — fin de la duplication lab/production. - **Info-bulles d'aide sur les champs du GUI.** Survoler la description d'un champ à saisir affiche une bulle avec des instructions sommaires. ## 2026-06-28 ### Ajouté - **Document de présentation de l'écosystème Chezlepro** (`docs/ecosysteme-chezlepro.md`). Description vulgarisée à destination client/partenaire : les piliers de l'écosystème souverain, le modèle reproductible (plan → génération → clonage → conformité), et un inventaire des **mesures de renforcement** réellement en place (SSH durci, fail2ban, sysctl, nftables, AppArmor, auditd, mises à jour automatiques, gestion des secrets, garde-fous destructifs, sécurité par l'architecture). Honnête sur le statut « défini/validé vs déployé ». ### Ajouté - **Dimensionnement dérivé des ressources VM.** Les cœurs/RAM/disque d'une VM sont désormais **estimés depuis les logiciels hébergés + le socle SE**, au lieu d'hériter des specs du golden template (CPU/RAM identiques pour toutes les VM auparavant). Chaque rôle déclare son empreinte (`roles//meta/empreinte.yml`) ; le générateur somme par hôte (marge + arrondis) et écrit `proxmox_coeurs`/ `proxmox_memoire`/`proxmox_disque_taille` ; le clonage passe `cores`/`memory` à Proxmox (`omit` si absent → aucune régression). Override par hôte possible dans le plan (`serveurs.yml`). Voir `docs/dimensionnement-ressources.md`. ### Corrigé - **`make instancier-appliquer FORCE=1` n'honorait pas `--force`.** La recette Makefile lançait `instancier.py appliquer` sans relayer `FORCE` ; le message « Utilise FORCE=1 » était donc trompeur (un changement de plan intentionnel restait bloqué). La recette passe désormais `$(if $(FORCE),--force)`. Trouvé en dogfooding. ## 2026-06-24 — Première publication publique Première mise à disposition publique de **Set-OPS**, moteur Ansible d'écosystèmes numériques souverains sur Proxmox — offert à la communauté québécoise par l'**Alliance Boréale**, à la Saint-Jean-Baptiste 2026. - **Moteur générique, piloté par un plan déclaratif** : on édite le plan (`instance/plan/*.yml`), l'inventaire Ansible se génère, les VM se clonent depuis un golden template Debian 13, les rôles s'appliquent par groupes. Tout passe par `make`, le GUI local et la documentation. - **Piliers d'un écosystème souverain** : socle Debian durci, AC/PKI interne, DNS interne, identité (LDAP + SSO), relais courriel, bases de données, observabilité, forge. - **Catalogue de modèles prêts à déployer** (`exemples/modeles/`) : un hébergeur copie un modèle, le renseigne à ses couleurs, et instancie. - **Souveraineté jusqu'au bout** : Set-OPS s'exploite entièrement à la main, sans aucune IA. Pour démarrer : **`QUICKSTART.md`**.