- templates custom/bootstrap-root + identity-network (sortie structurée parsable, sauvegardes, échec contrôlé, jamais de coupure réseau sans reconnexion) - postInstall: registre de manifestes (champs typés + defaults/defaultFrom), validateProfileValues + maskSecretValues + buildPostInstallResult (TDD), renderProfile/previewProfile (masquage secrets), runPostInstall (SSH) - execute: RunActionOpts.profileId/values + branche post_install (bloc postInstall) - action_requests: post_install accepté, payload profileId/values transmis à approve - routes: GET /profiles, POST .../preview (script masqué + validation), POST .../run (action_request si requiresConfirmation, sinon direct) Champs = formulaire (pas de question SSH interactive) ; secrets jamais sérialisés ; identity_network exige confirmation. tsc 0 · 101 tests · build OK · boot OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2.8 KiB
Tâche 2 — SJ-8 : Post-install (moteur de profils + bootstrap + identité/réseau)
Statut : backend implémenté (2026-06-06). tsc 0 · 101 tests · build OK · boot OK. Réf. design :
docs/design/tache2/30-scripts-custom.md,40-contrats-json.md §4,80-sous-jalons.mdSJ-8. Non testé en live (post-install destructif : modifie sudo/réseau d'une vraie machine).
Périmètre livré
Moteur de profils post-install non interactif : tout choix devient un champ de
formulaire validé côté backend ; preview avec masquage des secrets ; exécution
SSH + parsing PostInstallResult ; confirmation explicite (action_request) pour les
profils à risque.
Composants
- Templates
templates/custom/bootstrap-root.sh.tpl(sudo + ca-certificates + curl, ajout groupe sudo) etidentity-network.sh.tpl(hostname + IP statique, sauvegarde des fichiers, jamais de coupure sans reconnexion planifiée). Sortie structurée parsable (PKG_INSTALLED=,FILE_MODIFIED=,OLD/NEW_ENDPOINT=,REBOOT_REQUESTED=1,ERR=). server/services/postInstall.ts:- registre
PROFILES(manifestes :id,label,risk,requiresConfirmation,fields[]avec typesstring|hostname|ipv4|ipv4_cidr|ipv4_list|select|bool|int|path|secret,default/defaultFrom). validateProfileValues(requis + formats IPv4/CIDR/hostname) — TDD.maskSecretValues(champssecret→********) — TDD ;previewProfilemasque avant rendu.buildPostInstallResult(parse → filesModified/packagesInstalled/networkChange/reboot/errors) — TDD.renderProfile/runPostInstall(valide puis SSH, statut ok/error).
- registre
execute.ts:RunActionOpts.profileId/values, branchepost_install(archiveExecution + blocpostInstall).actionRequests.ts:post_installaccepté ; payload transporteprofileId/values;approveles repasse àrunAction.- Routes :
GET /api/profiles,POST /machines/:id/profiles/:id/preview(script masqué + validation),POST /machines/:id/profiles/:id/run(→action_requestsirequiresConfirmation, sinon exécution directe).
Sécurité / invariants
- Aucune question interactive SSH ; échec contrôlé si décision manquante.
- Secrets jamais sérialisés :
previewProfilemasque,variablesUsed= non sensible only. identity_network(network_change) exige confirmation explicite viaaction_request.- Reconnexion réseau :
OLD/NEW_ENDPOINT+RECONNECT_REQUIREDremontés ; reboot viareboot_verified(futur).
Reste (SJ-9 + tâche 4)
SJ-9 : profils base_tools, network_tools, docker_official, sharing, vm_guest_tools
(+ install-package-groups). Persistance install_profiles/machine_profile_state/
script_variables_presets et catalogue détaillé = tâche 4. UI (formulaires de profils,
preview) = tâche 3.