feat(engine): Adapter debian und Profil-Engine
Profile sind deklarative Schritte je Distributionsfamilie; der Adapter übersetzt sie in ein idempotentes Shell-Skript. Ein neuer Adapter (rhel, alpine) ist eine Datei und ein Eintrag in der Registry. Variablen werden typisiert geprüft, in run-Schritten jeder Wert für die Shell gequotet. SSH-Härtung läuft zuletzt, damit sich eine Provisionierung per SSH nicht selbst aussperrt. Geprüft mit shellcheck und echt in Containern (Debian 12/13, Ubuntu 22.04/24.04/26.04) inklusive zweitem Lauf. Dabei aufgefallen: frische Images haben keine Paketlisten – der Vorspann macht jetzt apt-get update. Closes #005 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { mkdtempSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { debianAdapter } from "@/engine/adapter/debian";
|
||||
import { katalogLaden } from "@/engine/katalog/laden";
|
||||
import { profileAufloesen } from "@/engine/profile/aufloesen";
|
||||
import { profileRendern } from "@/engine/profile/rendern";
|
||||
|
||||
/** shellcheck über Docker – läuft nur, wenn Docker und das Image da sind, und sagt das sonst. */
|
||||
function shellcheckVerfuegbar(): boolean {
|
||||
try {
|
||||
execFileSync("docker", ["image", "inspect", "koalaman/shellcheck:stable"], { stdio: "ignore" });
|
||||
return true;
|
||||
} catch {
|
||||
console.warn("shellcheck übersprungen: docker oder koalaman/shellcheck:stable fehlt");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
describe.runIf(shellcheckVerfuegbar())("shellcheck", () => {
|
||||
it("findet in den gerenderten Katalogprofilen nichts", async () => {
|
||||
const katalog = await katalogLaden("catalog");
|
||||
const profile = new Map(katalog.profile.map((p) => [p.eintrag.id, p.eintrag]));
|
||||
const ordner = mkdtempSync(join(tmpdir(), "pd-sc-"));
|
||||
for (const { eintrag: distro } of katalog.distributionen) {
|
||||
const aufgeloest = profileAufloesen(["docker", "zabbix-agent"], profile, "debian", {
|
||||
base: { fail2ban: true },
|
||||
"zabbix-agent": { server: "zbx" },
|
||||
});
|
||||
if (!aufgeloest.ok) throw new Error("Auflösung fehlgeschlagen");
|
||||
const { skript } = profileRendern(
|
||||
aufgeloest.profile,
|
||||
debianAdapter,
|
||||
{ os: distro.os, gast: { name: "g", benutzer: "u" } },
|
||||
[debianAdapter.benutzerAnlegen({ name: "u", sshSchluessel: ["ssh-ed25519 AAAA u"], sudo: true })],
|
||||
);
|
||||
writeFileSync(join(ordner, `${distro.id}.sh`), skript);
|
||||
}
|
||||
const ausgabe = (() => {
|
||||
try {
|
||||
execFileSync(
|
||||
"bash",
|
||||
["-c", `docker run --rm -v ${ordner}:/s:ro koalaman/shellcheck:stable -s bash /s/*.sh`],
|
||||
{ stdio: "pipe" },
|
||||
);
|
||||
return "";
|
||||
} catch (fehler) {
|
||||
return String((fehler as { stdout?: Buffer }).stdout ?? fehler);
|
||||
}
|
||||
})();
|
||||
expect(ausgabe).toBe("");
|
||||
}, 60_000);
|
||||
});
|
||||
Reference in New Issue
Block a user