import { describe, it, expect } from "vitest"; import { PROFILES, validateProfileValues, maskSecretValues, buildPostInstallResult, type ProfileManifest, } from "./postInstall.js"; describe("validateProfileValues", () => { const identity = PROFILES.identity_network!; it("échoue si un champ requis manque", () => { const r = validateProfileValues(identity, { newHostname: "srv1" }); expect(r.ok).toBe(false); expect(r.errors.some((e) => e.field === "interfaceName")).toBe(true); }); it("échoue sur une IP/CIDR invalide", () => { const r = validateProfileValues(identity, { newHostname: "srv1", domain: "home", interfaceName: "eth0", staticAddress: "999.1.1.1/24", gateway: "10.0.0.1", dnsNameservers: "10.0.0.1", reconnectHost: "10.0.0.50", }); expect(r.ok).toBe(false); expect(r.errors.some((e) => e.field === "staticAddress")).toBe(true); }); it("passe avec des valeurs valides", () => { const r = validateProfileValues(identity, { newHostname: "srv1", domain: "home", interfaceName: "eth0", staticAddress: "10.0.0.50/22", gateway: "10.0.0.1", dnsNameservers: "10.0.0.1 10.0.0.10", reconnectHost: "10.0.0.50", }); expect(r.ok).toBe(true); expect(r.errors).toHaveLength(0); }); }); describe("maskSecretValues", () => { const manifest: ProfileManifest = { id: "x", label: "x", description: "", risk: "low", requiresConfirmation: false, template: "custom/bootstrap-root.sh.tpl", fields: [ { name: "user", type: "string", required: true }, { name: "token", type: "secret", required: true }, ], }; it("masque les champs secret et conserve les autres", () => { const masked = maskSecretValues(manifest, { user: "gilles", token: "s3cr3t-ABC" }); expect(masked.user).toBe("gilles"); expect(masked.token).toBe("********"); expect(JSON.stringify(masked)).not.toContain("s3cr3t"); }); }); describe("buildPostInstallResult", () => { const raw = [ "===SU:CUSTOM_IDENTITY===", "FILE_MODIFIED=/etc/hosts", "FILE_MODIFIED=/etc/network/interfaces", "OLD_ENDPOINT=10.0.0.99", "HOSTNAME_SET=srv1", "ERR=interface_not_found", "NEW_ENDPOINT=10.0.0.50", "RECONNECT_REQUIRED=1", "REBOOT_REQUESTED=1", "===SU:EXIT=0===", ].join("\n"); it("extrait fichiers modifiés, reboot, changement réseau et erreurs", () => { const r = buildPostInstallResult(raw, ["identity_network"], { newHostname: "srv1" }); expect(r.profilesRun).toEqual(["identity_network"]); expect(r.filesModified).toContain("/etc/hosts"); expect(r.filesModified).toContain("/etc/network/interfaces"); expect(r.rebootsRequested).toBe(true); expect(r.networkChange).toEqual({ oldEndpoint: "10.0.0.99", newEndpoint: "10.0.0.50", reconnectHost: "10.0.0.50" }); expect(r.errors?.some((e) => e.kind === "interface_not_found")).toBe(true); expect(r.variablesUsed.newHostname).toBe("srv1"); }); it("parse les paquets installés du bootstrap", () => { const boot = [ "===SU:CUSTOM_BOOTSTRAP===", "PKG_INSTALLED=sudo", "PKG_INSTALLED=curl", "GROUP_ADDED=sudo:gilles", "SUDO_OK=1", "===SU:EXIT=0===", ].join("\n"); const r = buildPostInstallResult(boot, ["bootstrap_root"], { operatorUser: "gilles" }); expect(r.packagesInstalled).toEqual(["sudo", "curl"]); expect(r.rebootsRequested).toBe(false); expect(r.errors ?? []).toHaveLength(0); }); });