import { expect, test, type Page } from "@playwright/test"; import "dotenv/config"; import { schluesselpaarErzeugen } from "../../src/lib/ssh/openssh"; /** * Schluessel im gebauten Stand mit laufendem Worker (#012–#014). Testdaten heissen zz-e2e-… * und bleiben liegen (Schluessel werden nicht geloescht, nur spaeter widerrufen). */ test.setTimeout(90_000); async function oidcAnmelden(page: Page, rolle: "admin" | "operator" | "reader") { await page.goto("/anmelden"); await page.getByRole("link", { name: /Mit Mock-OIDC anmelden/ }).click(); await page.locator(`button[data-rolle="${rolle}"]`).click(); await page.getByRole("button", { name: "Anmelden", exact: true }).click(); await expect(page.getByRole("heading", { name: "Übersicht" })).toBeVisible(); } function eindeutig(): string { return `zz-e2e-${Date.now().toString(36)}`; } test("Operator erzeugt einen Schlüssel und landet im Detail", async ({ page }) => { const name = `${eindeutig()} Backup`; await oidcAnmelden(page, "operator"); await page.goto("/schluessel/neu"); await page.getByLabel("Zweck").fill(name); await page.getByLabel("Tags").fill("e2e"); await page.getByRole("button", { name: "Schlüssel erzeugen" }).click(); await expect(page.getByRole("heading", { name })).toBeVisible({ timeout: 30_000 }); await expect(page).toHaveURL(/\/schluessel\/[^/]+$/); await expect(page.getByText("verschlüsselt gespeichert")).toBeVisible(); await expect(page.getByText("ed25519", { exact: true })).toBeVisible(); await expect(page.getByLabel("Public Key", { exact: true })).toContainText("ssh-ed25519 AAAA"); await expect(page.getByLabel("Public Key", { exact: true })).toContainText( `sshkv:${name.toLowerCase().replace(/ /g, "-")}`, ); await page.goto(`/schluessel?q=${encodeURIComponent(name)}`); await expect(page.getByRole("link", { name })).toBeVisible(); }); test("Public Key importieren, Duplikat wird erkannt", async ({ page }) => { const name = `${eindeutig()} Laptop`; const paar = await schluesselpaarErzeugen("ED25519", { kommentar: "e2e@laptop" }); await oidcAnmelden(page, "operator"); await page.goto("/schluessel/neu"); await page.getByRole("radio", { name: "Importieren" }).click(); await page.getByLabel("Zweck").fill(name); await page.getByLabel("Public Key").fill(paar.publicKeyZeile); await page.locator(`input[name="kategorie"][value="PERSON"]`).check(); await page.getByRole("button", { name: "Schlüssel importieren" }).click(); await expect(page.getByRole("heading", { name })).toBeVisible(); await expect(page.getByText("nicht gespeichert (Personen-Key)")).toBeVisible(); await expect(page.getByText(paar.fingerprint)).toBeVisible(); await page.goto("/schluessel/neu"); await page.getByRole("radio", { name: "Importieren" }).click(); await page.getByLabel("Zweck").fill(`${name} nochmal`); await page.getByLabel("Public Key").fill(paar.publicKeyZeile); await page.getByRole("button", { name: "Schlüssel importieren" }).click(); await expect(page.getByRole("alert").first()).toContainText(`bereits verwaltet: „${name}“`); }); test("Leser sieht Schlüssel, darf aber keine anlegen", async ({ page }) => { await oidcAnmelden(page, "reader"); await page.goto("/schluessel"); await expect(page.getByRole("heading", { name: "Schlüssel", exact: true })).toBeVisible(); await expect(page.getByRole("link", { name: "Schlüssel anlegen" })).toHaveCount(0); await page.goto("/schluessel/neu"); await expect(page).toHaveURL(/\/kein-zugriff/); }); test("Leser hinterlegt einen eigenen Public Key und entfernt ihn wieder", async ({ page }) => { const name = `${eindeutig()} Laptop`; const paar = await schluesselpaarErzeugen("ED25519", { kommentar: "reader@laptop" }); await oidcAnmelden(page, "reader"); await page.getByRole("link", { name: "Meine Schlüssel" }).first().click(); await expect(page.getByRole("heading", { name: "Meine Schlüssel" })).toBeVisible(); await expect(page.getByText(/Wirksam erst, wenn ein Operator oder Admin/).first()).toBeVisible(); await page.getByLabel("Bezeichnung").fill(name); await page.getByLabel("Public Key").fill(paar.publicKeyZeile); await page.getByRole("button", { name: "Hinterlegen" }).click(); await expect(page.getByText(`Hinterlegt: ${paar.fingerprint}`)).toBeVisible(); const eintrag = page.locator("li", { hasText: name }); await expect(eintrag.getByText("noch nicht zugewiesen")).toBeVisible(); await eintrag.getByRole("button", { name: `${name} entfernen` }).click(); await page.getByRole("dialog").getByRole("button", { name: "Entfernen", exact: true }).click(); await expect(page.locator("li", { hasText: name })).toHaveCount(0); });