e6f4ae470b
- 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>
49 lines
2.8 KiB
Markdown
49 lines
2.8 KiB
Markdown
# 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.md` SJ-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) et `identity-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 types `string|hostname|ipv4|ipv4_cidr|ipv4_list|select|bool|int|path|secret`,
|
|
`default`/`defaultFrom`).
|
|
- `validateProfileValues` (requis + formats IPv4/CIDR/hostname) — TDD.
|
|
- `maskSecretValues` (champs `secret` → `********`) — TDD ; `previewProfile` masque avant rendu.
|
|
- `buildPostInstallResult` (parse → filesModified/packagesInstalled/networkChange/reboot/errors) — TDD.
|
|
- `renderProfile` / `runPostInstall` (valide puis SSH, statut ok/error).
|
|
- **`execute.ts`** : `RunActionOpts.profileId/values`, branche `post_install`
|
|
(archiveExecution + bloc `postInstall`).
|
|
- **`actionRequests.ts`** : `post_install` accepté ; payload transporte `profileId`/`values` ;
|
|
`approve` les repasse à `runAction`.
|
|
- **Routes** : `GET /api/profiles`, `POST /machines/:id/profiles/:id/preview`
|
|
(script masqué + validation), `POST /machines/:id/profiles/:id/run`
|
|
(→ `action_request` si `requiresConfirmation`, sinon exécution directe).
|
|
|
|
## Sécurité / invariants
|
|
|
|
- Aucune question interactive SSH ; échec contrôlé si décision manquante.
|
|
- Secrets jamais sérialisés : `previewProfile` masque, `variablesUsed` = non sensible only.
|
|
- `identity_network` (network_change) exige confirmation explicite via `action_request`.
|
|
- Reconnexion réseau : `OLD/NEW_ENDPOINT` + `RECONNECT_REQUIRED` remontés ; reboot via `reboot_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.
|