Files
florian.wildeandClaude Opus 5.5 cbeb0235f2 test(abgleich): Abgleich und Uebernahme im Browser (#021, #022)
Gebauter Stand mit Worker: fremder Key auf dem Testziel, Abgleich
zeigt ihn als unbekannt, Uebernahme in den Block mit Dry-Run, danach
keine offenen Abweichungen. Der Test raeumt einen Benutzer deploy aus
frueheren Laeufen weg - genau den hat der Abgleich zu Recht als von
Hand geaenderten Block gemeldet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 13:05:20 +02:00

75 lines
3.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { execFileSync } from "node:child_process";
import { expect, test } from "@playwright/test";
import "dotenv/config";
import { schluesselpaarErzeugen } from "../../src/lib/ssh/openssh";
/**
* Abgleich und Uebernahme im Browser (#021, #022), gebauter Stand + Worker, Testziel B:
* fremder Key → „Jetzt abgleichen“ zeigt ihn → übernehmen → Dry-Run → anwenden → synchron.
*/
const ROOT_PASSWORT = process.env["SSHKV_TEST_ROOT_PASSWORT"] || "sshkv-test";
const PORT_B = (process.env["SSHKV_TEST_ZIEL_B"] ?? "127.0.0.1:2222").split(":")[1] ?? "2222";
test.setTimeout(180_000);
function aufZielB(befehl: string): string {
return execFileSync(
"docker",
["compose", "-f", "docker-compose.test.yml", "exec", "-T", "ziel-b", "sh", "-c", befehl],
{
encoding: "utf8",
},
);
}
test.beforeAll(() => {
aufZielB(
"userdel -r sshkv 2>/dev/null; userdel -r deploy 2>/dev/null; rm -f /etc/sudoers.d/sshkv*; rm -rf /root/.ssh; true",
);
});
test("fremden Schlüssel finden und übernehmen", async ({ page }) => {
const name = `zz-e2e-${Date.now().toString(36)}`;
await page.goto("/anmelden");
await page.getByRole("link", { name: /Mit Mock-OIDC anmelden/ }).click();
await page.locator('button[data-rolle="admin"]').click();
await page.getByRole("button", { name: "Anmelden", exact: true }).click();
await page.goto("/hosts/neu");
await page.getByLabel("Name").fill(name);
await page.getByLabel("Adresse").fill("127.0.0.1");
await page.getByLabel("Port").fill(PORT_B);
await page.getByRole("button", { name: "Host anlegen" }).click();
await page.getByRole("button", { name: "Host-Key abrufen" }).click();
await page.getByRole("button", { name: "Fingerprint stimmt – vertrauen" }).click({ timeout: 30_000 });
await page.getByLabel("Passwort", { exact: true }).fill(ROOT_PASSWORT);
await page.getByRole("button", { name: "Zugang einrichten" }).click();
await expect(page.getByRole("button", { name: "Verbindung prüfen" })).toBeVisible({ timeout: 60_000 });
const fremd = await schluesselpaarErzeugen("ED25519", { kommentar: `${name}@laptop` });
aufZielB(`mkdir -p /root/.ssh && echo '${fremd.publicKeyZeile}' >> /root/.ssh/authorized_keys`);
await page.getByRole("button", { name: "Jetzt abgleichen" }).click();
await expect(page.getByText(/● Unbekannter Schlüssel/)).toBeVisible({ timeout: 30_000 });
await expect(page.getByText("unbekannt", { exact: true })).toBeVisible();
await page.screenshot({ path: "docs/anleitung/bilder/abgleich-desktop.png", fullPage: true });
await page.getByRole("button", { name: "Übernehmen", exact: true }).click();
const dialog = page.getByRole("dialog", { name: "Schlüssel übernehmen" });
await dialog.getByLabel("Zweck / Name").fill(`${name} Laptop`);
await dialog.getByRole("button", { name: "Übernehmen" }).click();
await expect(dialog).toBeHidden();
await page.getByRole("button", { name: "Dry-Run starten" }).click();
await expect(page.getByText(`root@${name}:/root/.ssh/authorized_keys`)).toBeVisible({ timeout: 30_000 });
await page.getByRole("button", { name: /Änderung anwenden/ }).click();
await expect(page.getByText("Ausgerollt.")).toBeVisible({ timeout: 60_000 });
expect(aufZielB("grep -c laptop /root/.ssh/authorized_keys").trim()).toBe("1");
await page.getByRole("button", { name: "Jetzt abgleichen" }).click();
await expect(page.getByText("Keine offenen Abweichungen.")).toBeVisible({ timeout: 30_000 });
await page.getByRole("button", { name: "Host archivieren" }).click();
await page.getByRole("dialog").getByRole("button", { name: "Archivieren", exact: true }).click();
});