feat(post-install): catalogue de profils — paquets, Docker officiel, partages, VM tools (tâche 2 SJ-9)
- mécanisme presetVars (variables fixes injectées au rendu, surchargées par le formulaire) - 6 profils : base_tools / network_tools / dev_git (listes de paquets, low), docker_official (dépôt officiel Debian, confirmation), sharing (Samba/NFS/mDNS, confirmation), vm_guest_tools (qemu/vmware) - 4 templates custom (install-package-groups, docker-official-debian, sharing, vm-guest-tools) émettant PKG_INSTALLED/SERVICE_ENABLED/ERR → réutilise buildPostInstallResult - l'UI post-install générique les expose automatiquement (manifeste → formulaire → run) tsc 0 · 104 tests · build OK · boot OK (8 profils servis). Clôt le volet moteur tâche 2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
validateProfileValues,
|
||||
maskSecretValues,
|
||||
buildPostInstallResult,
|
||||
previewProfile,
|
||||
type ProfileManifest,
|
||||
} from "./postInstall.js";
|
||||
|
||||
@@ -67,6 +68,26 @@ describe("maskSecretValues", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("profils SJ-9 (presetVars + sections)", () => {
|
||||
it("base_tools injecte la liste de paquets fixe", () => {
|
||||
expect(PROFILES.base_tools).toBeTruthy();
|
||||
const script = previewProfile("base_tools", {});
|
||||
expect(script).toContain("nano");
|
||||
expect(script).toContain("htop");
|
||||
});
|
||||
|
||||
it("sharing ne rend que les paquets cochés", () => {
|
||||
const script = previewProfile("sharing", { installSamba: true, installNfs: false, installMdns: true });
|
||||
expect(script).toContain("samba");
|
||||
expect(script).toContain("avahi-daemon");
|
||||
expect(script).not.toContain("nfs-kernel-server");
|
||||
});
|
||||
|
||||
it("docker_official exige une confirmation", () => {
|
||||
expect(PROFILES.docker_official!.requiresConfirmation).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildPostInstallResult", () => {
|
||||
const raw = [
|
||||
"===SU:CUSTOM_IDENTITY===",
|
||||
|
||||
@@ -31,6 +31,7 @@ export interface ProfileManifest {
|
||||
requiresConfirmation: boolean;
|
||||
template: string; // chemin relatif sous templates/
|
||||
fields: ProfileField[];
|
||||
presetVars?: Record<string, string | number | boolean>; // variables fixes (ex. liste de paquets)
|
||||
}
|
||||
|
||||
export const PROFILES: Record<string, ProfileManifest> = {
|
||||
@@ -63,6 +64,73 @@ export const PROFILES: Record<string, ProfileManifest> = {
|
||||
{ name: "rebootAfterInstall", type: "bool", required: false, label: "Reboot après application" },
|
||||
],
|
||||
},
|
||||
base_tools: {
|
||||
id: "base_tools",
|
||||
label: "Outils de base",
|
||||
description: "nano, less, bash-completion, tmux, screen, htop, iotop, ncdu, tree, rsync, unzip, zip, tar.",
|
||||
risk: "low",
|
||||
requiresConfirmation: false,
|
||||
template: "custom/install-package-groups.sh.tpl",
|
||||
fields: [],
|
||||
presetVars: { packages: "nano less bash-completion tmux screen htop iotop ncdu tree rsync unzip zip tar" },
|
||||
},
|
||||
network_tools: {
|
||||
id: "network_tools",
|
||||
label: "Outils réseau",
|
||||
description: "iproute2, iputils-ping, dnsutils, traceroute, tcpdump, nmap, mtr-tiny, lsof, netcat-openbsd.",
|
||||
risk: "low",
|
||||
requiresConfirmation: false,
|
||||
template: "custom/install-package-groups.sh.tpl",
|
||||
fields: [],
|
||||
presetVars: { packages: "iproute2 iputils-ping dnsutils traceroute tcpdump nmap mtr-tiny lsof netcat-openbsd" },
|
||||
},
|
||||
dev_git: {
|
||||
id: "dev_git",
|
||||
label: "Dev / Git",
|
||||
description: "git, curl, wget, jq, gnupg, lsb-release.",
|
||||
risk: "low",
|
||||
requiresConfirmation: false,
|
||||
template: "custom/install-package-groups.sh.tpl",
|
||||
fields: [],
|
||||
presetVars: { packages: "git curl wget jq gnupg lsb-release" },
|
||||
},
|
||||
docker_official: {
|
||||
id: "docker_official",
|
||||
label: "Docker (dépôt officiel)",
|
||||
description: "Docker Engine depuis le dépôt officiel Debian + plugin compose ; ajoute l'utilisateur au groupe docker.",
|
||||
risk: "medium",
|
||||
requiresConfirmation: true,
|
||||
template: "custom/docker-official-debian.sh.tpl",
|
||||
fields: [
|
||||
{ name: "dockerUser", type: "string", required: true, label: "Utilisateur docker", defaultFrom: "sshUser" },
|
||||
{ name: "composeRoot", type: "path", required: true, label: "Dossier Compose", default: "/home/gilles/docker" },
|
||||
{ name: "rebootAfterInstall", type: "bool", required: false, label: "Reboot après installation" },
|
||||
],
|
||||
},
|
||||
sharing: {
|
||||
id: "sharing",
|
||||
label: "Partage réseau",
|
||||
description: "Installe Samba / NFS / mDNS selon les cases cochées (configuration détaillée renvoyée à la tâche 4).",
|
||||
risk: "medium",
|
||||
requiresConfirmation: true,
|
||||
template: "custom/sharing.sh.tpl",
|
||||
fields: [
|
||||
{ name: "installSamba", type: "bool", required: false, label: "Samba" },
|
||||
{ name: "installNfs", type: "bool", required: false, label: "NFS" },
|
||||
{ name: "installMdns", type: "bool", required: false, label: "mDNS (avahi)" },
|
||||
],
|
||||
},
|
||||
vm_guest_tools: {
|
||||
id: "vm_guest_tools",
|
||||
label: "Outils invité VM",
|
||||
description: "Agent invité selon l'hyperviseur (qemu-guest-agent ou open-vm-tools).",
|
||||
risk: "low",
|
||||
requiresConfirmation: false,
|
||||
template: "custom/vm-guest-tools.sh.tpl",
|
||||
fields: [
|
||||
{ name: "guestAgent", type: "select", required: true, label: "Agent invité", default: "qemu-guest-agent", options: ["qemu-guest-agent", "open-vm-tools"] },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -156,14 +224,14 @@ function toTemplateVars(values: ProfileValues): TemplateVars {
|
||||
export function renderProfile(profileId: string, values: ProfileValues): string {
|
||||
const manifest = PROFILES[profileId];
|
||||
if (!manifest) throw new Error(`Profil inconnu : ${profileId}`);
|
||||
return renderTemplate(manifest.template, toTemplateVars(values));
|
||||
return renderTemplate(manifest.template, toTemplateVars({ ...manifest.presetVars, ...values }));
|
||||
}
|
||||
|
||||
/** Preview du script rendu avec masquage des secrets. */
|
||||
export function previewProfile(profileId: string, values: ProfileValues): string {
|
||||
const manifest = PROFILES[profileId];
|
||||
if (!manifest) throw new Error(`Profil inconnu : ${profileId}`);
|
||||
return renderTemplate(manifest.template, toTemplateVars(maskSecretValues(manifest, values)));
|
||||
return renderTemplate(manifest.template, toTemplateVars({ ...manifest.presetVars, ...maskSecretValues(manifest, values) }));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user