Files
system_update/docs/superpowers/plans/2026-06-05-tache2-sj5-docker-pull-check.md
T
gilles b1c81ba518 feat(docker): pull-check + comparaison déterministe par stack (tâche 2 SJ-5)
- template docker/pull-check.sh.tpl (pull sans up, inspect before/after)
- dockerPull: parseDockerPullCheck + buildDockerPullResult (TDD) — compare
  image id/digest/label OCI → services up_to_date|updates_available|error,
  changes operation=pulled ; erreurs registry nettoyées (URL/token/password)
- dockerDedupKey (digests prioritaires, fallback image ids) + DockerImageChange.dedupKey
- pullCheckStack: SSH + upsert docker_stack_services, refuse stack non enabled,
  refresh Docker séparé (hors refreshMachine, pas de pull auto)
- execute: runAction(opts.stackId), branche docker_pull_check, injection stackDir
  (corrige docker_inspect_current) ; route: allowlist Docker passifs + pull_check,
  destructives toujours hors API jusqu'à action_requests (SJ-6)

Pas de migration (schéma SJ-4 suffisant). tsc 0 erreur · 85 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 21:02:38 +02:00

3.4 KiB

Tâche 2 — SJ-5 : Docker pull-check + comparaison déterministe

Statut : implémenté (2026-06-05). tsc 0 erreur · 85 tests · build OK. Réf. design : docs/design/tache2/20-docker.md §4.3, 40-contrats-json.md §3/§6, 80-sous-jalons.md SJ-5.

Périmètre livré

Télécharger les images candidates d'un stack Compose sans démarrer de conteneur (docker compose pull), comparer avant/après par image ID + repo digest + label OCI, et persister l'état des services — sans toucher au flux jalon 1 et sans déclencher de pull automatique (action manuelle par stack, non incluse dans refreshMachine).

Composants

  • Template templates/docker/pull-check.sh.tpl — délimiteurs Mustache <% %> (<%stackDir%>), Go-templates {{.Id}} / {{join .RepoDigests ","}} préservés. Sections ===SU:DOCKER_INSPECT_BEFORE/PULL/INSPECT_AFTER=== + ===SU:EXIT=N===.
  • server/services/dockerPull.ts :
    • parseDockerPullCheck(raw) — lit BEFORE/AFTER (id, digest, version), code de sortie, et extrait les erreurs de pull nettoyées de tout secret (URLs, token/bearer/password).
    • buildDockerPullResult(stackName, raw) — comparaison déterministe → services (up_to_date | updates_available | error par image) + changes (operation:"pulled" uniquement pour les images modifiées) + status global + errors.
    • dockerDedupKey(image, fromDigest, toDigest, fromId?, toId?) — empreinte fonctionnelle (digests prioritaires, fallback image IDs), conforme 40 §6.
    • pullCheckStack(machineId, stackId, onData?) — orchestration SSH + upsert des services dans docker_stack_services (par stackId + serviceName), maj lastUpdateAt du stack et lastPullCheckAt des settings. Refuse un stack non enabled.
  • server/services/dockerPull.test.ts — 7 cas (parse, nettoyage secret registry, classement up_to_date/updates_available, change unique, status global, dédup).
  • Wiring :
    • runAction(machineId, action, opts?: { stackId }) — branche dédiée docker_pull_check (archivage report/log, ExecutionResult.docker.pull.changes + dedupKey, event).
    • Chemin générique : injection stackDir quand stackId fourni → corrige aussi docker_inspect_current (SJ-4 le déclarait sans orchestration par stack).
    • POST /:id/actions — allowlist élargie aux actions Docker passives/non-applicatives (docker_scan, docker_inspect_current, docker_pull_check) ; stackId requis pour les actions par-stack. Destructives (apply/down/prune agressif) toujours hors API jusqu'au socle action_requests (SJ-6).
  • shared/types.ts : DockerImageChange.dedupKey? (additif, pour mutualisation Hermes).

Pas de migration

Le schéma SJ-4 (docker_stack_services avec current/candidate_image_id|digest, version_label, status ; docker_settings.last_pull_check_at) couvrait déjà SJ-5.

Sécurité

  • docker compose pull sans up → aucun conteneur recréé (pré-check pur applicatif).
  • Erreurs registry (registry_auth_failed / pull_failed) nettoyées : ni URL, ni token, ni mot de passe ne remontent vers UI/MCP (test dédié).
  • Credentials registry (~/.docker/config.json) jamais lus ni renvoyés.

Reste pour SJ-6

docker_compose_apply (up -d --remove-orphans), docker_prune_images, docker_compose_down, table docker_image_events, et validation UI explicite via action_requests.