Cartographie complète (liste_taches/coherence_taches), briefs tacheN + gates validation_tacheN, design tâche 2 (docs/design/tache2/), specs/plans jalon 1-2 et tâche 1.9/2 (Phase 1, Phase 2, SJ-0→3). Validations consignées (1.9 ✅, 2-8 🟡). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8.4 KiB
90 — Les 8 questions d'investigation (§3) tranchées
Chaque question : MVP recommandé / alternatives / risques. Décisions autonomes argumentées, cohérentes avec l'existant et
tache1.9.md.
Q1 — JSON-in-shell vs parsing-in-TS
MVP recommandé : hybride à dominante parsing-TS. On conserve la convention actuelle (marqueurs ===SU:XXX=== + parsing dans server/services/). On enrichit avec des données semi-structurées produites par le shell uniquement quand le format est déjà stable et documenté : dpkg-query -W -f='${binary:Package}\t${Version}\t${Architecture}\n' (TSV), docker compose ps/images --format json, docker image inspect --format '...'. Pas de construction de gros JSON imbriqué à la main dans le shell.
- Pourquoi : (a) cohérence avec le jalon 1 (déjà en prod, parsing TS testé) ; (b) testabilité — les fixtures de sortie shell + tests TS sont faciles à maintenir ; (c) robustesse multi-OS — éviter le JSON bricolé en Bash (échappement fragile, comme on le voit dans
nas-opsavec la concaténation manuelle de chaînes JSON) ; (d) on tire parti des formats JSON natifs et documentés de Docker sans les réinventer. - Alternatives : (1) tout-JSON-in-shell façon
nas-ops— rejeté (échappement fragile, dur à tester, risque de casser sur des noms/versions exotiques) ; (2) tout-parsing-TS sur sortie brute uniquement — rejeté pour Docker où--format jsonest plus sûr que parser du texte libre. - Risques : double convention (TSV/clé=valeur + sections) à documenter clairement ; mitigé par un parseur central par section. Format
docker ... --format jsonvarie selon version de Compose — pin de la commande + fallback texte.
Q2 — Structure des profils OS
MVP recommandé : un fichier de template complet par profil, dans un dossier par OS, avec fallback base (templates/<osFamily>/<action>.sh.tpl → sinon templates/apt/<action>.sh.tpl). Résolution par convention de chemin (cf. 60-profils-os-machine.md §2).
- Pourquoi : lisibilité et audit Git (un script = un fichier complet, testable isolément) ; n'invalide pas Debian/Ubuntu (pas de dossier dédié ⇒ fallback
apt/, comportement jalon 1 intact). - Alternatives : (1) héritage par fragments/partials Mustache (DRY) — plus complexe à auditer, reporté ; (2) une matrice de variables dans un seul template géant avec
{{#proxmox}}…— rejeté (templates illisibles, logique métier noyée dans le rendu). - Risques : duplication partielle entre profils. Accepté au MVP (peu de profils) ; refactor en partials possible plus tard si la duplication devient coûteuse.
Q3 — Structure des profils machine
MVP recommandé : choix manuel à l'ajout (os_family + machine_kind) + action machine_probe non destructive proposant des corrections (jamais appliquées sans validation). Sources : /etc/os-release, uname -m/dpkg --print-architecture, systemd-detect-virt, présence /etc/pve, /proc/cpuinfo (RPi), lspci (GPU), ip addr (interface).
- Pourquoi : la détection auto seule est fragile (conteneurs imbriqués, distros dérivées, VM mal taguées). Le couple « défaut manuel + sonde de correction » est robuste et garde l'opérateur maître.
- Alternatives : (1) détection 100 % auto — rejetée (cas limites) ; (2) manuel sans sonde — perte de confort et risque d'erreur de profil.
- Risques : utilisateur choisit mal le profil ⇒
machine_probele signale ; correction nécessite validation. Persisté dansmachines+machine_hardware.
Q4 — Capture avant/après (diff réel)
MVP recommandé : snapshot dpkg complet avant ET après chaque action APT réelle via dpkg-query -W -f='${binary:Package}\t${Version}\t${Architecture}\n', diff calculé côté backend (clé package+arch). L'exit code APT ne suffit jamais.
- Pourquoi :
dpkg-queryreflète l'état réel installé (pas l'intention APT). Détecte les écarts entre simulation et réalité (paquet annoncé non installé, held back effectif). - Alternatives : (1) parser uniquement la sortie
apt-get(Setting up …) — moins fiable, dépend du locale et du verbeux ; (2) historique/var/log/dpkg.log— parsing daté fragile. Les deux gardés comme signaux secondaires, pas comme source de vérité. - Risques : sur de très gros parcs de paquets, deux
dpkg-queryajoutent quelques secondes — négligeable. Diff côté TS = testable par fixtures.
Q5 — Contrats JSON (extensions exactes)
MVP recommandé : extensions additives détaillées dans 40-contrats-json.md — unions élargies (OsFamily, AptProxyMode, ActionType, MachineKind), blocs optionnels docker/errors/reboot/postInstall + champs additifs sur apt, schemaVersion?. Types TS fournis. Un payload jalon 1 reste valide.
- Pourquoi : rétro-compatibilité stricte exigée par le gate (§3 de la validation). Champs optionnels + unions additives = zéro rupture.
- Alternatives : versionner par type séparé (
UpdateSnapshotV2) — rejeté (duplication, migration lourde) au profit deschemaVersionsur un type unique. - Risques : un type unique grossit ; mitigé par découpe en sous-interfaces (
AptSnapshotDetail,DockerSnapshot, etc.).
Q6 — Idempotence & opérations longues
MVP recommandé : différencier selon la durée et le risque.
-
Refresh/analyse, scan, inspect : synchrones et courts (comme le jalon 1).
-
Actions applicatives longues (
full-upgrade,docker apply) : généraliser l'exécution détachéenohup+ fichier exit-code sur la machine (survit à une coupure SSH), comme prévu au jalon 1 et inspiré delinux-update-dashboard. Le backend peut relire l'état/exit-code à la reconnexion plutôt que tout relancer. -
Reboot : mécanisme dédié
reboot_verified(boot_id avant/après + reconnexion + délai adaptatif). -
Idempotence : les détections sont rejouables sans effet de bord applicatif ;
pull-checkécrit dans le cache images mais ne démarre rien (rejouable).machine_locksévite la concurrence destructive. -
Alternatives : (1) tout synchrone — rejeté (un upgrade long meurt avec la session SSH) ; (2) file de jobs persistante dès le MVP — utile mais relève de la tâche 5 ; ici on pose le mécanisme
nohup+exit-code et on renvoie l'orchestration job à la tâche 5. -
Risques : suivi de progression d'une opération détachée = tailing du fichier de sortie distant + WebSocket ; à câbler proprement en implémentation (réutilise
outputHub).
Q7 — Sécurité Docker prune / scripts custom
MVP recommandé : barrière de validation côté webapp (action_requests) pour toute action destructive + nettoyage déterministe des secrets dans les erreurs. docker_prune_images -a, docker_compose_down, docker_compose_apply, suppressions APT, reboot, identity_network ⇒ confirmation explicite. Hermes propose, ne déclenche jamais. Credentials registry/sudo/tokens jamais lus ni renvoyés (cf. 70-securite.md).
- Pourquoi : respecte
CLAUDE.md(actions destructives validées, aucun secret vers LLM). La barrière unique (action_requests) centralise l'autorisation côté API. - Alternatives : validation par template (flag
requiresConfirmationdans le manifeste) — complémentaire, pas suffisant seul ; la décision d'autorisation reste côté API/route. - Risques : un script custom pourrait logger un secret ⇒ règle « pas de secret dans le corps du script » + filtre de nettoyage des lignes avant UI/MCP + revue Git des templates.
Q8 — Surface MCP
MVP recommandé : conserver la surface v1 (8 outils), sans nouvelle primitive d'exécution SSH. Les nouvelles capacités (Docker, post-install, APT détaillé) passent par run_action(actionType, params) filtré côté route, pas par de nouveaux outils. preview_template masque les secrets. run_action sur action destructive non validée renvoie un action_request en attente. Audit via mcp_audit_log.
- Pourquoi : surface petite = agents fiables et auditables ; le MCP reste une façade sans logique SSH ni secret.
- Alternatives : exposer un outil par action (
docker_apply,apt_upgrade…) — rejeté (explosion de surface, duplication d'autorisation). - Risques :
run_actiongénérique doit valider strictementactionType/paramscôté API (liste blanche) ; sinon risque d'action non prévue. Mitigé par la table d'autorisation etaction_requests.