From a47cae4082d1e7fe140767037e38ececedde4323 Mon Sep 17 00:00:00 2001 From: Florian Wilde Date: Mon, 12 Oct 2026 13:05:12 +0200 Subject: [PATCH] feat(zuweisungen): Matrix Schluessel x Host mit CSV-Export (#025) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bisher liess sich nur je Schluessel oder je Host nachsehen, wo ein Key verwaltet ist. Die Matrix zeigt das auf einen Blick, loest Hostgruppen-Zuweisungen je Mitglied auf (P vs. P·G) und macht nicht synchrone Zustaende ohne Farbe erkennbar. Die Matrix plant nur: Zuweisen und Entfernen laufen ueber die vorhandenen Aktionen, ausgerollt wird weiter per Dry-Run auf der Schluesselseite. Der Aufbau ist eine reine Funktion in src/lib, damit Seite und CSV-Export garantiert dasselbe zeigen und die Gruppenaufloesung ohne Datenbank testbar ist. Der CSV-Export entschaerft Formelbeginne, weil Schluesselnamen frei waehlbar sind und Excel sie sonst ausfuehren wuerde. Co-Authored-By: Claude Opus 5.5 --- docs/anleitung/bilder/zuweisungen-desktop.png | Bin 0 -> 87850 bytes docs/anleitung/bilder/zuweisungen-mobil.png | Bin 0 -> 84752 bytes docs/issues/025-zuweisungsmatrix.md | 35 +- scripts/screenshots.ts | 3 + src/app/(app)/zuweisungen/page.tsx | 164 ++++++++- src/app/api/zuweisungen.csv/route.ts | 26 ++ .../ausrollen/PublicZuweisenFormular.tsx | 5 +- .../ausrollen/VerwendungsZustand.tsx | 4 +- src/components/zuweisungen/ZellenDialog.tsx | 189 +++++++++++ .../zuweisungen/Zuweisungsmatrix.tsx | 274 +++++++++++++++ src/lib/csv.ts | 37 +++ src/lib/zuweisungsmatrix.ts | 311 ++++++++++++++++++ src/server/queries/zuweisungen.ts | 69 ++++ tests/e2e/zuweisungen.spec.ts | 147 +++++++++ tests/zuweisungen.test.ts | 150 +++++++++ tests/zuweisungsmatrix.test.ts | 210 ++++++++++++ 16 files changed, 1608 insertions(+), 16 deletions(-) create mode 100644 docs/anleitung/bilder/zuweisungen-desktop.png create mode 100644 docs/anleitung/bilder/zuweisungen-mobil.png create mode 100644 src/app/api/zuweisungen.csv/route.ts create mode 100644 src/components/zuweisungen/ZellenDialog.tsx create mode 100644 src/components/zuweisungen/Zuweisungsmatrix.tsx create mode 100644 src/lib/csv.ts create mode 100644 src/lib/zuweisungsmatrix.ts create mode 100644 src/server/queries/zuweisungen.ts create mode 100644 tests/e2e/zuweisungen.spec.ts create mode 100644 tests/zuweisungen.test.ts create mode 100644 tests/zuweisungsmatrix.test.ts diff --git a/docs/anleitung/bilder/zuweisungen-desktop.png b/docs/anleitung/bilder/zuweisungen-desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..cd469a7eb260e74e70236533fb9d55fbe581f0c1 GIT binary patch literal 87850 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 F{{xRkM<@UQ literal 0 HcmV?d00001 diff --git a/docs/anleitung/bilder/zuweisungen-mobil.png b/docs/anleitung/bilder/zuweisungen-mobil.png new file mode 100644 index 0000000000000000000000000000000000000000..05cf34e521a2c607d36b904fc9526db19fc21a29 GIT binary patch literal 84752 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 literal 0 HcmV?d00001 diff --git a/docs/issues/025-zuweisungsmatrix.md b/docs/issues/025-zuweisungsmatrix.md index ca824e8..22f0864 100644 --- a/docs/issues/025-zuweisungsmatrix.md +++ b/docs/issues/025-zuweisungsmatrix.md @@ -1,19 +1,46 @@ # #025 Zuweisungsmatrix -**Status:** offen +**Status:** erledigt **Meilenstein:** v0.4.0 **Labels:** ui -**Geschätzt:** 2 h **Tatsächlich:** – +**Geschätzt:** 2 h **Tatsächlich:** 0,5 h ## Ziel Matrix Schlüssel × Host. ## Aufgaben -- [ ] wird zu Beginn der Phase verfeinert +- [x] `/zuweisungen` ersetzt die Platzhalterseite: Matrix aktive Schlüssel (Zeilen) × nicht archivierte Hosts (Spalten), jede Rolle darf lesen +- [x] Zelle: „P“ direkt, „P·G“ über Hostgruppe, „K“ Private Key; Zustand als Punkt + Kurztext, voller Text in `title` und für Screenreader; Zielbenutzer mono +- [x] Filter per GET: Hostgruppe, Kategorie, Person, Suche über Schlüssel- und Hostnamen, „nur Zeilen/Spalten mit Zuweisungen“ +- [x] Eigener Scrollbereich mit sticky Kopfzeile und erster Spalte; unter `md` eine Liste je Schlüssel +- [x] Zell-Dialog: Verwendungen mit Zustand, Optionen/Pfad, Links zu Schlüssel und Host; „Public Key zuweisen“ (vorhandenes Formular mit Vorauswahl) und „Entfernen“ für `publicKeyAusrollen`; Link „Zum Dry-Run“ +- [x] Kopf: Zähler (Schlüssel, Hosts, Zuweisungen, nicht synchron) und CSV-Export `/api/zuweisungen.csv` +- [x] Reine Matrix-Funktion in `src/lib/zuweisungsmatrix.ts`, CSV-Helfer in `src/lib/csv.ts`, Query in `src/server/queries/zuweisungen.ts` +- [x] Tests: `tests/zuweisungsmatrix.test.ts` (rein), `tests/zuweisungen.test.ts` (Query + CSV-Route), E2E `tests/e2e/zuweisungen.spec.ts` +- [x] Screenshots `zuweisungen-desktop.png` / `zuweisungen-mobil.png` ## Akzeptanzkriterien -- [ ] wird zu Beginn der Phase verfeinert +- [x] Gruppen-Zuweisungen erscheinen auf jedem Mitglied und sind von direkten unterscheidbar +- [x] Zustand nie nur über Farbe +- [x] Seite scrollt bei 390 px nicht horizontal (Screenshot-Skript prüft das) +- [x] Leser sehen die Matrix, aber weder Zuweisen noch Entfernen +- [x] CSV mit den Spalten Schlüssel, Fingerprint, Host, Zielbenutzer, Art, Über Gruppe, Optionen, Zustand; Formelbeginne `= + - @` mit `'` entschärft +- [x] Route Handler prüft `rechtErforderlich("lesen")` selbst (`tests/zugang.test.ts` grün) ## Abhängigkeiten #016 ## Notizen / Entscheidungen +- Die Matrix plant nur: Zuweisen und Entfernen nutzen die vorhandenen Aktionen, ausgerollt wird + weiter über den Dry-Run der Schlüsselseite (`AusrollenPanel`). +- Suche: trifft der Begriff Schlüssel, werden die Zeilen eingeschränkt; trifft er Hosts, die + Spalten; trifft er beides, beides. So zeigt „srv-pve“ alle Schlüssel auf diesen Hosts statt + einer leeren Matrix. +- Zähler „Zuweisungen“ zählt Zelleneinträge, eine Gruppen-Zuweisung also einmal je Mitglied – + dasselbe, was der CSV-Export als Zeilen liefert. „Nicht synchron“ ist alles außer `AUSGEROLLT`. +- Zellenzustand ist der dringendste der Einträge (Fehler > Drift > entfernen > geplant > synchron). +- CSV: Semikolon, UTF-8-BOM und CRLF für ein deutsches Excel; bei Private Keys steht der Pfad + als „Pfad: …“ in der Spalte Optionen. Der Export nimmt dieselben Filter wie die Seite. +- Deployment-Keys erscheinen als Zeilen, sind aber nicht zuweisbar (verwaltet sshkv selbst). +- Entfernen einer Gruppen-Zuweisung aus einer Zelle gilt für die ganze Gruppe; der Dialog sagt das. +- `PublicZuweisenFormular` hat eine optionale `vorauswahl`; `VerwendungsZustand` exportiert seine + Darstellungstabelle (`ZUSTAND_ANZEIGE`), damit die Zelle dieselben Punkte nutzt. diff --git a/scripts/screenshots.ts b/scripts/screenshots.ts index 9028777..d691d4f 100644 --- a/scripts/screenshots.ts +++ b/scripts/screenshots.ts @@ -39,6 +39,9 @@ const SEITEN: { name: string; pfad: string; oeffentlich?: boolean; folgen?: stri { name: "meine-schluessel", pfad: "/meine-schluessel" }, { name: "hosts", pfad: "/hosts" }, { name: "host-detail", pfad: "/hosts", folgen: 'main table a[href^="/hosts/"]' }, + // Matrix Schluessel × Host (#025): die Seite darf auf 390 px nicht seitwaerts scrollen – + // nur der Matrix-Container. „belegt=1“, damit das Bild Zellen zeigt statt leerer Zeilen. + { name: "zuweisungen", pfad: "/zuweisungen?belegt=1" }, { name: "vorlagen", pfad: "/vorlagen" }, // Die eingebaute „Deployment-Zugang“ zeigt Platzhalter, Laufzeit und Benutzer-Anlegen (#019). { diff --git a/src/app/(app)/zuweisungen/page.tsx b/src/app/(app)/zuweisungen/page.tsx index 4860295..c5425a7 100644 --- a/src/app/(app)/zuweisungen/page.tsx +++ b/src/app/(app)/zuweisungen/page.tsx @@ -1,18 +1,164 @@ +import { Download, Network, Search } from "lucide-react"; import type { Metadata } from "next"; -import { Platzhalterseite } from "@/components/huelle/Platzhalterseite"; +import { Zuweisungsmatrix } from "@/components/zuweisungen/Zuweisungsmatrix"; +import { Button, buttonKlassen } from "@/components/ui/Button"; +import { Ankreuzfeld, Auswahlliste, Feld } from "@/components/ui/Feld"; +import { Kennzahl } from "@/components/ui/Kennzahl"; +import { Leerzustand } from "@/components/ui/Leerzustand"; +import { Seitenkopf } from "@/components/ui/Seitenkopf"; +import { KATEGORIE_TEXT } from "@/lib/schluessel"; +import { matrixFilterAus, matrixFilterQuery } from "@/lib/zuweisungsmatrix"; +import { darf } from "@/server/auth/rechte"; import { sitzungErforderlich } from "@/server/auth/sitzungspflicht"; +import { zielAuswahl } from "@/server/queries/ziele"; +import { zuweisungsMatrix } from "@/server/queries/zuweisungen"; export const metadata: Metadata = { title: "Zuweisungen" }; -export default async function Zuweisungen() { +type Suchparameter = Promise>; + +/** + * Zuweisungsmatrix Schluessel × Host (#025). Filter per GET, damit Links und der CSV-Export + * denselben Ausschnitt zeigen. Die Matrix plant nur – ausgerollt wird ueber den Dry-Run. + */ +export default async function Zuweisungen({ searchParams }: { searchParams: Suchparameter }) { // Jede Seite prueft selbst; die Huelle ist nur das zweite Netz (CLAUDE.md). - await sitzungErforderlich(); + const { benutzer } = await sitzungErforderlich("lesen", "/zuweisungen"); + const filter = matrixFilterAus(await searchParams); + const darfZuweisen = darf(benutzer.rolle, "publicKeyAusrollen"); + const [{ matrix, gruppen, personen }, auswahl] = await Promise.all([ + zuweisungsMatrix(filter), + darfZuweisen ? zielAuswahl() : Promise.resolve(undefined), + ]); + const gefiltert = Boolean( + filter.gruppeId || filter.kategorie || filter.personId || filter.q || filter.nurBelegt, + ); + const { zaehler } = matrix; + const leer = matrix.zeilen.length === 0 || matrix.spalten.length === 0; + return ( - +
+ + + CSV exportieren + + } + /> + +
+ + + + 0 ? "messing" : "neutral"} + hinweis="geplant, Drift, entfernen, Fehler" + /> +
+ +
+ + + + {gruppen.map((g) => ( + + ))} + + + + {Object.entries(KATEGORIE_TEXT).map(([wert, text]) => ( + + ))} + + + + {personen.map((p) => ( + + ))} + +
+ +
+ + {gefiltert && ( + + )} +
+
+ + + {leer ? ( + gefiltert ? ( + } + titel="Keine Treffer" + text="Kein Schlüssel und kein Host passen zu Suche und Filter." + aktion={} + /> + ) : ( + } + titel="Noch nichts zuzuordnen" + text="Die Matrix braucht mindestens einen aktiven Schlüssel und einen Host." + /> + ) + ) : ( +
+

+ P Public Key direkt ·{" "} + P·G über Hostgruppe ·{" "} + K Private Key · ●{" "} + synchron · ○ geplant oder wird entfernt ·{" "} + ● Drift oder Fehler +

+ +
+ )} +
); } diff --git a/src/app/api/zuweisungen.csv/route.ts b/src/app/api/zuweisungen.csv/route.ts new file mode 100644 index 0000000..2990570 --- /dev/null +++ b/src/app/api/zuweisungen.csv/route.ts @@ -0,0 +1,26 @@ +import { NextResponse } from "next/server"; +import { matrixCsv, matrixFilterAus } from "@/lib/zuweisungsmatrix"; +import { RechteFehler, rechtErforderlich } from "@/server/auth/sitzungspflicht"; +import { zuweisungsMatrix } from "@/server/queries/zuweisungen"; + +/** + * Zuweisungsmatrix als CSV (#025) mit denselben Filtern wie die Seite. Jede Rolle darf lesen; + * der Handler prueft das selbst, der Proxy laesst ohne Cookie ohnehin niemanden durch. + */ +export async function GET(anfrage: Request) { + try { + await rechtErforderlich("lesen"); + } catch (fehler) { + if (fehler instanceof RechteFehler) return NextResponse.json({ fehler: fehler.message }, { status: 403 }); + throw fehler; + } + const filter = matrixFilterAus(Object.fromEntries(new URL(anfrage.url).searchParams)); + const { matrix } = await zuweisungsMatrix(filter); + return new NextResponse(matrixCsv(matrix), { + headers: { + "Content-Type": "text/csv; charset=utf-8", + "Content-Disposition": 'attachment; filename="sshkv-zuweisungen.csv"', + "Cache-Control": "no-store", + }, + }); +} diff --git a/src/components/ausrollen/PublicZuweisenFormular.tsx b/src/components/ausrollen/PublicZuweisenFormular.tsx index 2ff5080..dbcdc79 100644 --- a/src/components/ausrollen/PublicZuweisenFormular.tsx +++ b/src/components/ausrollen/PublicZuweisenFormular.tsx @@ -14,10 +14,13 @@ export function PublicZuweisenFormular({ schluesselId, auswahl, beiErfolg, + vorauswahl, }: { schluesselId: string; auswahl: ZielAuswahl; beiErfolg?: () => void; + /** Vorausgewaehltes Ziel als „host:“ oder „gruppe:“, z. B. aus der Matrix (#025). */ + vorauswahl?: string; }) { const { zustand, absenden, laeuft } = useFormularAktion(async (vorher, formular) => { const ergebnis = await publicZuweisenAktion(vorher, formular); @@ -28,7 +31,7 @@ export function PublicZuweisenFormular({
- + diff --git a/src/components/ausrollen/VerwendungsZustand.tsx b/src/components/ausrollen/VerwendungsZustand.tsx index 16d6b10..2f69ec9 100644 --- a/src/components/ausrollen/VerwendungsZustand.tsx +++ b/src/components/ausrollen/VerwendungsZustand.tsx @@ -2,7 +2,7 @@ import type { VerwendungsZustand as Zustand } from "@/generated/prisma/enums"; import { clsx } from "clsx"; /** Zustand einer Verwendung – immer Punkt und Text, nie nur Farbe (#016). */ -const ANZEIGE: Record = { +export const ZUSTAND_ANZEIGE: Record = { GEPLANT: { text: "noch nicht ausgerollt", klasse: "text-accent", punkt: "○" }, AUSGEROLLT: { text: "synchron", klasse: "text-ok", punkt: "●" }, ABWEICHUNG: { text: "Drift", klasse: "text-danger", punkt: "●" }, @@ -12,7 +12,7 @@ const ANZEIGE: Record }; export function VerwendungsZustand({ zustand, className }: { zustand: Zustand; className?: string }) { - const anzeige = ANZEIGE[zustand]; + const anzeige = ZUSTAND_ANZEIGE[zustand]; return ( void; +}) { + const dialog = useRef(null); + const router = useRouter(); + // Nach erfolgreichem Zuweisen ein frisches Formular – sonst schickt ein zweiter Klick + // dieselbe Zuweisung noch einmal und erntet „bereits zugewiesen“. + const [formularNr, setFormularNr] = useState(0); + + useEffect(() => { + const element = dialog.current; + if (element && !element.open) element.showModal(); + }, []); + + const titel = host ? `${schluessel.name} auf ${host.name}` : schluessel.name; + const vorauswahl = host && auswahl?.hosts.some((h) => h.id === host.id) ? `host:${host.id}` : undefined; + const eintraege = zelle?.eintraege ?? []; + + return ( + +
+
+

{schluessel.name}

+

+ {host ? ( + <> + auf {host.name} + + ) : ( + "Einem Host oder einer Hostgruppe zuweisen" + )} +

+
+ +
+ +
+ + Zum Schlüssel + + {host && ( + + Zum Host + + )} +
+ + {host && ( +
+ {eintraege.length === 0 ? ( +

+ Auf diesem Host ist der Schlüssel nicht zugewiesen. +

+ ) : ( + eintraege.map((e) => ( + +
+

+ {KENNUNG_TEXT[e.kennung]} + {e.gruppe && <> „{e.gruppe.name}“} +

+

+ Zielbenutzer {e.zielbenutzer} +

+ {e.art === "public" ? ( +

+ Optionen {e.optionen ?? "–"} +

+ ) : ( +

+ Pfad {e.pfad} +

+ )} + + {e.gruppe && darfZuweisen && ( +

+ Entfernen gilt für alle Hosts der Gruppe „{e.gruppe.name}“. +

+ )} +
+ +
+ )) + )} +
+ )} + + {darfZuweisen && auswahl && ( +
+

Public Key zuweisen

+ { + setFormularNr((n) => n + 1); + router.refresh(); + }} + /> +
+ )} + + {darfZuweisen && ( +
+

+ Zuweisen und Entfernen ändern auf dem Host noch nichts – erst der Dry-Run auf der Schlüsselseite + zeigt und schreibt die Änderung. +

+ +
+ )} +
+ ); +} diff --git a/src/components/zuweisungen/Zuweisungsmatrix.tsx b/src/components/zuweisungen/Zuweisungsmatrix.tsx new file mode 100644 index 0000000..842fd4e --- /dev/null +++ b/src/components/zuweisungen/Zuweisungsmatrix.tsx @@ -0,0 +1,274 @@ +"use client"; + +import { clsx } from "clsx"; +import { Plus } from "lucide-react"; +import Link from "next/link"; +import { useState } from "react"; +import { ZUSTAND_ANZEIGE } from "@/components/ausrollen/VerwendungsZustand"; +import { Button } from "@/components/ui/Button"; +import { + KENNUNG_TEXT, + ZUSTAND_KURZ, + ZUSTAND_TEXT, + zellenSchluessel, + type MatrixHost, + type MatrixSchluessel, + type Zelle, +} from "@/lib/zuweisungsmatrix"; +import type { ZielAuswahl } from "@/server/queries/ziele"; +import { ZellenDialog, type ZellenAuswahl } from "./ZellenDialog"; + +/** + * Matrix Schluessel × Host (#025). Ab md eine Tabelle mit eigenem Scrollbereich – die Seite + * selbst scrollt nie seitwaerts –, darunter eine Liste je Schluessel, weil auf 390 px keine + * zweite Spalte neben den Schluesselnamen passt. + */ +export type MatrixProps = { + zeilen: readonly MatrixSchluessel[]; + spalten: readonly MatrixHost[]; + /** Nur belegte Zellen, Schluessel `${schluesselId}:${hostId}`. */ + zellen: Readonly>; + darfZuweisen: boolean; + darfPrivatEntfernen: boolean; + auswahl?: ZielAuswahl; +}; + +/** Langtext fuer title und Screenreader: Art, Gruppe, Benutzer und Zustand je Eintrag. */ +function zellenText(zelle: Zelle): string { + return zelle.eintraege + .map( + (e) => + `${KENNUNG_TEXT[e.kennung]}${e.gruppe ? ` ${e.gruppe.name}` : ""}, Benutzer ${e.zielbenutzer}, ${ZUSTAND_TEXT[e.zustand]}`, + ) + .join("; "); +} + +function zielbenutzerKurz(zelle: Zelle): string { + const [erster, ...rest] = zelle.zielbenutzer; + return rest.length > 0 ? `${erster} +${rest.length}` : (erster ?? ""); +} + +export function Zuweisungsmatrix({ + zeilen, + spalten, + zellen, + darfZuweisen, + darfPrivatEntfernen, + auswahl, +}: MatrixProps) { + const [offen, setOffen] = useState(); + const zuweisbar = (s: MatrixSchluessel) => darfZuweisen && !!auswahl && s.kategorie !== "DEPLOYMENT"; + + const schluessel = offen ? zeilen.find((s) => s.id === offen.schluesselId) : undefined; + const host = offen?.hostId ? spalten.find((h) => h.id === offen.hostId) : undefined; + const zelle = offen?.hostId ? zellen[zellenSchluessel(offen.schluesselId, offen.hostId)] : undefined; + + return ( + <> + {/* Desktop: Kopfzeile und erste Spalte bleiben beim Scrollen stehen. Der Scrollbereich + braucht eine eigene Hoehe, sonst klebt die Kopfzeile am Container statt am Fenster. */} +
+ + + + + + {spalten.map((h) => ( + + ))} + + + + {zeilen.map((s) => ( + + + {spalten.map((h) => { + const z = zellen[zellenSchluessel(s.id, h.id)]; + return ( + + ); + })} + + ))} + +
+ Zuweisungen: Schlüssel in den Zeilen, Hosts in den Spalten. Eine Zelle öffnet die Details. +
+ Schlüssel + + + {h.name} + +
+ + {s.name} + + {s.person && {s.person.name}} + + {z ? ( + setOffen({ schluesselId: s.id, hostId: h.id })} + /> + ) : zuweisbar(s) ? ( + + ) : ( + + · + nicht zugewiesen + + )} +
+
+ + {/* Telefon: je Schluessel nur die Hosts, auf denen er verwaltet ist. */} +
    + {zeilen.map((s) => { + const belegt = spalten.flatMap((h) => { + const z = zellen[zellenSchluessel(s.id, h.id)]; + return z ? [{ host: h, zelle: z }] : []; + }); + return ( +
  • +
    +
    + + {s.name} + + + {belegt.length === 1 ? "1 Host" : `${belegt.length} Hosts`} + {s.person && <> · {s.person.name}} + +
    + {zuweisbar(s) && ( + + )} +
    + {belegt.length > 0 && ( +
      + {belegt.map(({ host: h, zelle: z }) => { + const anzeige = ZUSTAND_ANZEIGE[z.zustand]; + return ( +
    • + +
    • + ); + })} +
    + )} +
  • + ); + })} +
+ + {offen && schluessel && ( + setOffen(undefined)} + /> + )} + + ); +} + +function BelegteZelle({ + zelle, + schluessel, + host, + oeffnen, +}: { + zelle: Zelle; + schluessel: MatrixSchluessel; + host: MatrixHost; + oeffnen: () => void; +}) { + const anzeige = ZUSTAND_ANZEIGE[zelle.zustand]; + const text = zellenText(zelle); + return ( + + ); +} diff --git a/src/lib/csv.ts b/src/lib/csv.ts new file mode 100644 index 0000000..4454968 --- /dev/null +++ b/src/lib/csv.ts @@ -0,0 +1,37 @@ +/** + * CSV fuer Excel (#025). Framework-frei, damit spaetere Exporte (Protokoll, Phase 5) dieselben + * Regeln nutzen. + * + * - Semikolon als Trenner und UTF-8-BOM: ein deutsches Excel oeffnet die Datei sonst als eine + * Spalte mit kaputten Umlauten. + * - Jeder Wert in Anfuehrungszeichen, damit Kommas in `authorized_keys`-Optionen und + * Zeilenumbrueche nichts verschieben. + * - Formel-Injektion: Excel und LibreOffice werten Zellen, die mit `= + - @` (oder Tab/CR) + * beginnen, als Formel aus – ein Schluesselname wie `=HYPERLINK(…)` wuerde beim Oeffnen + * ausgefuehrt. Ein vorangestelltes `'` macht daraus Text (OWASP „CSV Injection“). + */ +export const CSV_BOM = ""; +export const CSV_TRENNER = ";"; + +const FORMELBEGINN = /^[=+\-@\t\r]/; + +export function csvEntschaerfen(wert: string): string { + return FORMELBEGINN.test(wert) ? `'${wert}` : wert; +} + +export function csvWert(wert: string | number | null | undefined): string { + const text = csvEntschaerfen(wert == null ? "" : String(wert)); + return `"${text.replace(/"/g, '""')}"`; +} + +export function csvZeile(werte: readonly (string | number | null | undefined)[]): string { + return werte.map(csvWert).join(CSV_TRENNER); +} + +/** Ganze Datei: BOM, Kopfzeile, Datenzeilen, CRLF wie Excel selbst. */ +export function csvDatei( + kopf: readonly string[], + zeilen: readonly (readonly (string | number | null | undefined)[])[], +): string { + return CSV_BOM + [kopf, ...zeilen].map(csvZeile).join("\r\n") + "\r\n"; +} diff --git a/src/lib/zuweisungsmatrix.ts b/src/lib/zuweisungsmatrix.ts new file mode 100644 index 0000000..e0e2268 --- /dev/null +++ b/src/lib/zuweisungsmatrix.ts @@ -0,0 +1,311 @@ +import { csvDatei } from "@/lib/csv"; + +/** + * Zuweisungsmatrix Schluessel × Host (#025). Rein: bekommt die Zeilen aus der Datenbank und + * baut daraus Matrix, Zaehler und CSV – so laesst sich die Gruppenaufloesung ohne Datenbank + * testen, und Seite und CSV-Export sehen garantiert dasselbe. + */ + +export type MatrixZustand = + "GEPLANT" | "AUSGEROLLT" | "ABWEICHUNG" | "ENTFERNEN" | "ENTFERNT" | "FEHLGESCHLAGEN"; +export type MatrixKategorie = "PERSON" | "DIENST" | "DEPLOYMENT"; + +export type MatrixSchluessel = { + readonly id: string; + readonly name: string; + readonly fingerprint: string; + readonly kategorie: MatrixKategorie; + readonly person: { readonly id: string; readonly name: string } | null; +}; + +export type MatrixHost = { + readonly id: string; + readonly name: string; + readonly gruppenIds: readonly string[]; +}; + +export type MatrixGruppe = { readonly id: string; readonly name: string }; + +export type PublicZeile = { + readonly id: string; + readonly schluesselId: string; + readonly hostId: string | null; + readonly hostgruppeId: string | null; + readonly zielbenutzer: string; + readonly optionen: string | null; + readonly zustand: MatrixZustand; +}; + +export type PrivatZeile = { + readonly id: string; + readonly schluesselId: string; + readonly hostId: string; + readonly zielbenutzer: string; + readonly pfad: string; + readonly zustand: MatrixZustand; +}; + +export type MatrixDaten = { + readonly schluessel: readonly MatrixSchluessel[]; + readonly hosts: readonly MatrixHost[]; + readonly gruppen: readonly MatrixGruppe[]; + readonly oeffentlich: readonly PublicZeile[]; + readonly privat: readonly PrivatZeile[]; +}; + +export type MatrixFilter = { + readonly gruppeId?: string; + readonly kategorie?: string; + readonly personId?: string; + readonly q?: string; + /** Nur Zeilen und Spalten, in denen mindestens eine Zuweisung steht. */ + readonly nurBelegt?: boolean; +}; + +/** „P“ direkt, „P·G“ ueber eine Hostgruppe, „K“ Private Key – Kurzformen fuer die Zelle. */ +export type Kennung = "P" | "P·G" | "K"; + +export type ZellenEintrag = { + readonly verwendungId: string; + readonly art: "public" | "privat"; + readonly kennung: Kennung; + readonly gruppe: MatrixGruppe | null; + readonly zielbenutzer: string; + readonly optionen: string | null; + readonly pfad: string | null; + readonly zustand: MatrixZustand; +}; + +export type Zelle = { + readonly schluesselId: string; + readonly hostId: string; + readonly eintraege: readonly ZellenEintrag[]; + /** Der dringendste Zustand der Eintraege – er bestimmt Punkt und Kurztext. */ + readonly zustand: MatrixZustand; + readonly kennungen: readonly Kennung[]; + readonly zielbenutzer: readonly string[]; +}; + +export type Matrix = { + readonly zeilen: readonly MatrixSchluessel[]; + readonly spalten: readonly MatrixHost[]; + /** Schluessel `${schluesselId}:${hostId}`; leere Zellen fehlen. */ + readonly zellen: ReadonlyMap; + readonly zaehler: { + readonly schluessel: number; + readonly hosts: number; + readonly zuweisungen: number; + readonly nichtSynchron: number; + }; +}; + +export const ZUSTAND_TEXT: Record = { + GEPLANT: "noch nicht ausgerollt", + AUSGEROLLT: "synchron", + ABWEICHUNG: "Drift", + ENTFERNEN: "wird entfernt", + ENTFERNT: "entfernt", + FEHLGESCHLAGEN: "fehlgeschlagen", +}; + +/** Kurztext fuer die enge Zelle; der volle Text steht in `title` und fuer Screenreader. */ +export const ZUSTAND_KURZ: Record = { + GEPLANT: "geplant", + AUSGEROLLT: "sync", + ABWEICHUNG: "Drift", + ENTFERNEN: "entf.", + ENTFERNT: "entfernt", + FEHLGESCHLAGEN: "Fehler", +}; + +export const KENNUNG_TEXT: Record = { + P: "Public Key direkt", + "P·G": "Public Key über Hostgruppe", + K: "Private Key", +}; + +/** Was zuerst ins Auge fallen muss: Fehler und Drift vor offener Arbeit vor „alles gut“. */ +const DRINGLICHKEIT: Record = { + FEHLGESCHLAGEN: 5, + ABWEICHUNG: 4, + ENTFERNEN: 3, + GEPLANT: 2, + AUSGEROLLT: 1, + ENTFERNT: 0, +}; + +export function zellenSchluessel(schluesselId: string, hostId: string): string { + return `${schluesselId}:${hostId}`; +} + +function enthaelt(text: string, q: string): boolean { + return text.toLowerCase().includes(q); +} + +const KENNUNG_REIHENFOLGE: readonly Kennung[] = ["P", "P·G", "K"]; + +export function matrixAufbauen(daten: MatrixDaten, filter: MatrixFilter = {}): Matrix { + const gruppen = new Map(daten.gruppen.map((g) => [g.id, g])); + const hostsJeGruppe = new Map(); + for (const h of daten.hosts) { + for (const g of h.gruppenIds) hostsJeGruppe.set(g, [...(hostsJeGruppe.get(g) ?? []), h.id]); + } + + // Alle Eintraege je Zelle sammeln – Gruppen-Verwendungen fuer jedes Mitglied einzeln. + const sammel = new Map(); + const hinzu = (schluesselId: string, hostId: string, eintrag: ZellenEintrag) => { + const k = zellenSchluessel(schluesselId, hostId); + sammel.set(k, [...(sammel.get(k) ?? []), eintrag]); + }; + for (const v of daten.oeffentlich) { + if (v.zustand === "ENTFERNT") continue; + const gruppe = v.hostgruppeId ? (gruppen.get(v.hostgruppeId) ?? null) : null; + const ziele = v.hostId ? [v.hostId] : v.hostgruppeId ? (hostsJeGruppe.get(v.hostgruppeId) ?? []) : []; + for (const hostId of ziele) { + hinzu(v.schluesselId, hostId, { + verwendungId: v.id, + art: "public", + kennung: v.hostId ? "P" : "P·G", + gruppe: v.hostId ? null : gruppe, + zielbenutzer: v.zielbenutzer, + optionen: v.optionen, + pfad: null, + zustand: v.zustand, + }); + } + } + for (const v of daten.privat) { + if (v.zustand === "ENTFERNT") continue; + hinzu(v.schluesselId, v.hostId, { + verwendungId: v.id, + art: "privat", + kennung: "K", + gruppe: null, + zielbenutzer: v.zielbenutzer, + optionen: null, + pfad: v.pfad, + zustand: v.zustand, + }); + } + + // Filter: Schluessel-Merkmale schraenken Zeilen ein, die Hostgruppe die Spalten. + const q = filter.q?.trim().toLowerCase() ?? ""; + let zeilen = daten.schluessel.filter( + (s) => + (!filter.kategorie || s.kategorie === filter.kategorie) && + (!filter.personId || s.person?.id === filter.personId), + ); + let spalten = daten.hosts.filter((h) => !filter.gruppeId || h.gruppenIds.includes(filter.gruppeId)); + if (q) { + // Eine Suche trifft Schluessel- oder Hostnamen: wer „srv-pve“ sucht, will alle Schluessel + // auf diesen Hosts sehen, nicht eine leere Matrix, weil kein Schluessel so heisst. + const zeilenTreffer = zeilen.filter((s) => enthaelt(s.name, q) || enthaelt(s.fingerprint, q)); + const spaltenTreffer = spalten.filter((h) => enthaelt(h.name, q)); + zeilen = zeilenTreffer.length > 0 || spaltenTreffer.length === 0 ? zeilenTreffer : zeilen; + spalten = spaltenTreffer.length > 0 || zeilenTreffer.length === 0 ? spaltenTreffer : spalten; + } + if (filter.nurBelegt) { + const belegt = (s: string, h: string) => sammel.has(zellenSchluessel(s, h)); + zeilen = zeilen.filter((s) => spalten.some((h) => belegt(s.id, h.id))); + spalten = spalten.filter((h) => zeilen.some((s) => belegt(s.id, h.id))); + } + + const zellen = new Map(); + let zuweisungen = 0; + let nichtSynchron = 0; + for (const s of zeilen) { + for (const h of spalten) { + const k = zellenSchluessel(s.id, h.id); + const eintraege = sammel.get(k); + if (!eintraege) continue; + eintraege.sort( + (a, b) => + KENNUNG_REIHENFOLGE.indexOf(a.kennung) - KENNUNG_REIHENFOLGE.indexOf(b.kennung) || + a.zielbenutzer.localeCompare(b.zielbenutzer), + ); + zuweisungen += eintraege.length; + nichtSynchron += eintraege.filter((e) => e.zustand !== "AUSGEROLLT").length; + zellen.set(k, { + schluesselId: s.id, + hostId: h.id, + eintraege, + zustand: eintraege.reduce( + (schlimmster, e) => + DRINGLICHKEIT[e.zustand] > DRINGLICHKEIT[schlimmster] ? e.zustand : schlimmster, + "ENTFERNT", + ), + kennungen: KENNUNG_REIHENFOLGE.filter((kennung) => eintraege.some((e) => e.kennung === kennung)), + zielbenutzer: [...new Set(eintraege.map((e) => e.zielbenutzer))], + }); + } + } + + return { + zeilen, + spalten, + zellen, + zaehler: { schluessel: zeilen.length, hosts: spalten.length, zuweisungen, nichtSynchron }, + }; +} + +/** Filter aus GET-Parametern; Unbekanntes faellt weg statt einen Fehler zu werfen. */ +export function matrixFilterAus(parameter: Record): MatrixFilter { + const einzeln = (name: string) => { + const wert = parameter[name]; + return ((Array.isArray(wert) ? wert[0] : wert) ?? "").trim().slice(0, 200); + }; + const kategorie = einzeln("kategorie"); + return { + gruppeId: einzeln("gruppe"), + kategorie: ["PERSON", "DIENST", "DEPLOYMENT"].includes(kategorie) ? kategorie : "", + personId: einzeln("person"), + q: einzeln("q"), + nurBelegt: einzeln("belegt") === "1", + }; +} + +/** Dieselben Filter als Query-String, z. B. fuer den CSV-Link. */ +export function matrixFilterQuery(filter: MatrixFilter): string { + const p = new URLSearchParams(); + if (filter.gruppeId) p.set("gruppe", filter.gruppeId); + if (filter.kategorie) p.set("kategorie", filter.kategorie); + if (filter.personId) p.set("person", filter.personId); + if (filter.q) p.set("q", filter.q); + if (filter.nurBelegt) p.set("belegt", "1"); + const text = p.toString(); + return text ? `?${text}` : ""; +} + +export const CSV_KOPF = [ + "Schlüssel", + "Fingerprint", + "Host", + "Zielbenutzer", + "Art", + "Über Gruppe", + "Optionen", + "Zustand", +] as const; + +/** Eine Zeile je Zelleneintrag – Gruppen-Zuweisungen also einmal je Mitglied (#025). */ +export function matrixCsv(matrix: Matrix): string { + const zeilen: string[][] = []; + for (const s of matrix.zeilen) { + for (const h of matrix.spalten) { + const zelle = matrix.zellen.get(zellenSchluessel(s.id, h.id)); + for (const e of zelle?.eintraege ?? []) { + zeilen.push([ + s.name, + s.fingerprint, + h.name, + e.zielbenutzer, + e.art === "public" ? "Public Key" : "Private Key", + e.gruppe?.name ?? "", + e.art === "public" ? (e.optionen ?? "") : `Pfad: ${e.pfad ?? ""}`, + ZUSTAND_TEXT[e.zustand], + ]); + } + } + } + return csvDatei(CSV_KOPF, zeilen); +} diff --git a/src/server/queries/zuweisungen.ts b/src/server/queries/zuweisungen.ts new file mode 100644 index 0000000..ef22224 --- /dev/null +++ b/src/server/queries/zuweisungen.ts @@ -0,0 +1,69 @@ +import { prisma } from "@/lib/db"; +import { matrixAufbauen, type MatrixDaten, type MatrixFilter } from "@/lib/zuweisungsmatrix"; + +/** + * Lesemodell der Zuweisungsmatrix (#025). Jede angemeldete Rolle darf es sehen – wie die + * Verwendungen auf Schluessel- und Hostseite auch. + * + * Feste `select`-Listen ohne Chiffrat-Felder (CLAUDE.md). Nur aktive Schluessel und nicht + * archivierte Hosts: widerrufene oder rotierte Keys haben keine Zukunft auf einem Host, und + * ein archivierter Host wird nicht mehr abgeglichen. + */ +export async function zuweisungsDaten(): Promise { + const nichtEntfernt = { zustand: { not: "ENTFERNT" as const } }; + const [schluessel, hosts, gruppen, oeffentlich, privat] = await Promise.all([ + prisma.schluessel.findMany({ + where: { status: "AKTIV" }, + select: { + id: true, + name: true, + fingerprint: true, + kategorie: true, + person: { select: { id: true, name: true } }, + }, + orderBy: [{ name: "asc" }, { id: "asc" }], + }), + prisma.host.findMany({ + where: { archiviertAm: null }, + select: { id: true, name: true, gruppen: { select: { hostgruppeId: true } } }, + orderBy: { name: "asc" }, + }), + prisma.hostgruppe.findMany({ select: { id: true, name: true }, orderBy: { name: "asc" } }), + prisma.publicVerwendung.findMany({ + where: { ...nichtEntfernt, schluessel: { status: "AKTIV" } }, + select: { + id: true, + schluesselId: true, + hostId: true, + hostgruppeId: true, + zielbenutzer: true, + optionen: true, + zustand: true, + }, + orderBy: { angelegtAm: "asc" }, + }), + prisma.privateVerwendung.findMany({ + where: { ...nichtEntfernt, schluessel: { status: "AKTIV" } }, + select: { id: true, schluesselId: true, hostId: true, zielbenutzer: true, pfad: true, zustand: true }, + orderBy: { angelegtAm: "asc" }, + }), + ]); + return { + schluessel, + hosts: hosts.map((h) => ({ id: h.id, name: h.name, gruppenIds: h.gruppen.map((g) => g.hostgruppeId) })), + gruppen, + oeffentlich, + privat, + }; +} + +export async function zuweisungsMatrix(filter: MatrixFilter = {}) { + const daten = await zuweisungsDaten(); + // Personen fuer den Filter: nur die, denen ein aktiver Schluessel gehoert. + const personen = [ + ...new Map( + daten.schluessel.flatMap((s) => (s.person ? [[s.person.id, s.person] as const] : [])), + ).values(), + ].sort((a, b) => a.name.localeCompare(b.name, "de")); + return { matrix: matrixAufbauen(daten, filter), gruppen: daten.gruppen, personen }; +} diff --git a/tests/e2e/zuweisungen.spec.ts b/tests/e2e/zuweisungen.spec.ts new file mode 100644 index 0000000..232d52c --- /dev/null +++ b/tests/e2e/zuweisungen.spec.ts @@ -0,0 +1,147 @@ +import { randomUUID } from "node:crypto"; +import { expect, test, type Page } from "@playwright/test"; +import pg from "pg"; +import "dotenv/config"; + +/** + * Zuweisungsmatrix (#025) im gebauten Stand. Kein Worker und kein SSH-Ziel noetig: die Matrix + * zeigt und plant nur. Schluessel, Hosts und Hostgruppe legt der Test direkt in der + * Entwicklungsdatenbank an (Praefix zz-e2e) und raeumt sie am Ende wieder weg. + */ +const name = `zz-e2e-mx${Date.now().toString(36)}`; +const ids = { + schluessel: randomUUID(), + gruppe: randomUUID(), + h1: randomUUID(), + h2: randomUUID(), + h3: randomUUID(), +}; + +async function datenbank(arbeit: (client: pg.Client) => Promise): Promise { + const client = new pg.Client({ connectionString: process.env["DATABASE_URL"] }); + await client.connect(); + try { + return await arbeit(client); + } finally { + await client.end(); + } +} + +async function anmelden(page: Page, rolle: "admin" | "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(); +} + +test.beforeAll(async () => { + await datenbank(async (client) => { + for (const [id, nr] of [ + [ids.h1, 1], + [ids.h2, 2], + [ids.h3, 3], + ] as const) { + await client.query(`INSERT INTO "Host" ("id","name","adresse","geaendertAm") VALUES ($1,$2,$3,now())`, [ + id, + `${name}-h${nr}`, + `10.99.0.${nr}`, + ]); + } + await client.query(`INSERT INTO "Hostgruppe" ("id","name") VALUES ($1,$2)`, [ids.gruppe, `${name}-g`]); + await client.query(`INSERT INTO "HostgruppeMitglied" ("hostId","hostgruppeId") VALUES ($1,$3),($2,$3)`, [ + ids.h1, + ids.h2, + ids.gruppe, + ]); + await client.query( + `INSERT INTO "Schluessel" ("id","name","slug","typ","kategorie","publicKey","fingerprint","kommentar","geaendertAm") + VALUES ($1,$2,$3,'ED25519','DIENST','ssh-ed25519 AAAA zz-e2e',$4,'zz-e2e',now())`, + [ids.schluessel, `${name} Backup`, name, `SHA256:${name}`], + ); + await client.query( + `INSERT INTO "PublicVerwendung" ("id","schluesselId","hostgruppeId","zielbenutzer","optionen") + VALUES ($1,$2,$3,'root','restrict')`, + [randomUUID(), ids.schluessel, ids.gruppe], + ); + }); +}); + +test.afterAll(async () => { + await datenbank(async (client) => { + // Verwendungen und Mitgliedschaften haengen per Cascade daran. + await client.query(`DELETE FROM "Schluessel" WHERE "id" = $1`, [ids.schluessel]); + await client.query(`DELETE FROM "Hostgruppe" WHERE "id" = $1`, [ids.gruppe]); + await client.query(`DELETE FROM "Host" WHERE "id" = ANY($1)`, [[ids.h1, ids.h2, ids.h3]]); + }); +}); + +test("Matrix zeigt Gruppen-Zuweisung, filtert, weist zu und exportiert", async ({ page }) => { + await anmelden(page, "admin"); + // Die Suche trifft Schluessel und Hosts dieses Tests – fremde Daten bleiben draussen. + await page.goto(`/zuweisungen?q=${name}`); + const matrix = page.locator("table"); + await expect(matrix.getByRole("columnheader", { name: `${name}-h3` })).toBeVisible(); + + // Gruppen-Zuweisung erscheint auf beiden Mitgliedern als „P·G“ mit Zustand. + for (const nr of [1, 2]) { + const zelle = matrix.getByRole("button", { + name: `${name} Backup auf ${name}-h${nr}: Public Key über Hostgruppe ${name}-g, Benutzer root, noch nicht ausgerollt`, + }); + await expect(zelle).toBeVisible(); + await expect(zelle).toContainText("P·G"); + } + + // Filter Hostgruppe: der dritte Host gehoert nicht dazu und verschwindet. + await page.getByLabel("Hostgruppe").selectOption({ label: `${name}-g` }); + await page.getByRole("button", { name: "Filtern" }).click(); + await expect(page).toHaveURL(/gruppe=/); + await expect(matrix.getByRole("columnheader", { name: `${name}-h1` })).toBeVisible(); + await expect(matrix.getByRole("columnheader", { name: `${name}-h3` })).toHaveCount(0); + + // Leere Zelle auf h3 → Dialog mit vorausgewaehltem Host → zuweisen. + await page.goto(`/zuweisungen?q=${name}`); + await matrix.getByRole("button", { name: new RegExp(`auf ${name}-h3: nicht zugewiesen`) }).click(); + const dialog = page.getByRole("dialog"); + await expect(dialog.getByLabel("Ziel", { exact: true })).toHaveValue(`host:${ids.h3}`); + await dialog.getByLabel("Zielbenutzer").fill("deploy"); + await dialog.getByRole("button", { name: "Zuweisen" }).click(); + await expect(dialog.getByText("Public Key direkt")).toBeVisible(); + await expect(dialog.getByRole("link", { name: "Zum Dry-Run" })).toBeVisible(); + const angelegt = await datenbank((client) => + client.query( + `SELECT "zielbenutzer" FROM "PublicVerwendung" WHERE "schluesselId" = $1 AND "hostId" = $2`, + [ids.schluessel, ids.h3], + ), + ); + expect(angelegt.rows).toEqual([{ zielbenutzer: "deploy" }]); + await dialog.getByRole("button", { name: "Schließen" }).click(); + await expect( + matrix.getByRole("button", { name: new RegExp(`auf ${name}-h3: Public Key direkt`) }), + ).toBeVisible(); + + // CSV mit derselben Sitzung: Gruppen-Zeile je Mitglied und die neue direkte Zuweisung. + const csv = await page.request.get(`/api/zuweisungen.csv?q=${name}`); + expect(csv.status()).toBe(200); + const text = await csv.text(); + expect(text).toContain( + `"${name} Backup";"SHA256:${name}";"${name}-h2";"root";"Public Key";"${name}-g";"restrict";"noch nicht ausgerollt"`, + ); + expect(text).toContain(`"${name}-h3";"deploy";"Public Key";""`); +}); + +test("Leser sieht die Matrix, aber keinen Zuweisen-Knopf", async ({ page }) => { + await anmelden(page, "reader"); + await page.goto(`/zuweisungen?q=${name}`); + const matrix = page.locator("table"); + await matrix + .getByRole("button", { name: new RegExp(`auf ${name}-h1: Public Key über Hostgruppe`) }) + .click(); + const dialog = page.getByRole("dialog"); + await expect(dialog.getByText("Public Key über Hostgruppe")).toBeVisible(); + await expect(dialog.getByRole("button", { name: "Zuweisen" })).toHaveCount(0); + await expect(dialog.getByRole("button", { name: "Zuweisung entfernen" })).toHaveCount(0); + await dialog.getByRole("button", { name: "Schließen" }).click(); + // Leere Zellen sind fuer Leser keine Knoepfe. + await expect(matrix.getByRole("button", { name: /nicht zugewiesen/ })).toHaveCount(0); +}); diff --git a/tests/zuweisungen.test.ts b/tests/zuweisungen.test.ts new file mode 100644 index 0000000..47004b0 --- /dev/null +++ b/tests/zuweisungen.test.ts @@ -0,0 +1,150 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { prisma } from "@/lib/db"; +import { zellenSchluessel } from "@/lib/zuweisungsmatrix"; +import { zuweisungsDaten, zuweisungsMatrix } from "@/server/queries/zuweisungen"; +import { datenbankLeeren } from "./hilfen/db"; + +/** + * Zuweisungsmatrix (#025) gegen die Testdatenbank: Query und CSV-Route. Die Sitzung wird fuer + * die Route nachgebildet – geprueft wird, dass der Handler das Recht selbst verlangt. + */ +const recht = vi.hoisted(() => ({ erlaubt: true })); +vi.mock("@/server/auth/sitzungspflicht", async (original) => { + const echt = await original(); + return { + ...echt, + rechtErforderlich: vi.fn(async () => { + if (!recht.erlaubt) throw new echt.RechteFehler("Nicht angemeldet."); + return { benutzer: { id: "b", rolle: "LESER" } }; + }), + }; +}); + +let zaehler = 0; +async function schluesselAnlegen(daten: { + name: string; + status?: "AKTIV" | "WIDERRUFEN"; + mitPrivat?: boolean; +}) { + zaehler += 1; + return prisma.schluessel.create({ + data: { + name: daten.name, + slug: `test-${zaehler}`, + typ: "ED25519", + kategorie: "DIENST", + status: daten.status ?? "AKTIV", + publicKey: "ssh-ed25519 AAAA test", + fingerprint: `SHA256:test${zaehler}`, + kommentar: "test", + ...(daten.mitPrivat + ? { privatVerschluesselt: Buffer.from("x"), dekVerschluesselt: Buffer.from("y"), masterKeyVersion: 1 } + : {}), + }, + }); +} + +let ids: Record; + +beforeEach(async () => { + await datenbankLeeren(); + recht.erlaubt = true; + zaehler = 0; + const gruppe = await prisma.hostgruppe.create({ data: { name: "pve" } }); + const [pve1, pve2, alt] = await Promise.all([ + prisma.host.create({ data: { name: "srv-pve01", adresse: "10.0.0.1" } }), + prisma.host.create({ data: { name: "srv-pve02", adresse: "10.0.0.2" } }), + prisma.host.create({ data: { name: "srv-alt", adresse: "10.0.0.3", archiviertAm: new Date() } }), + ]); + await prisma.hostgruppeMitglied.createMany({ + data: [pve1, pve2, alt].map((h) => ({ hostId: h.id, hostgruppeId: gruppe.id })), + }); + const backup = await schluesselAnlegen({ name: "Backup", mitPrivat: true }); + const formel = await schluesselAnlegen({ name: "=1+1" }); + const widerrufen = await schluesselAnlegen({ name: "Alt", status: "WIDERRUFEN" }); + await prisma.publicVerwendung.createMany({ + data: [ + { schluesselId: backup.id, hostgruppeId: gruppe.id, zielbenutzer: "root", optionen: "restrict" }, + { schluesselId: formel.id, hostId: pve1.id, zielbenutzer: "deploy", zustand: "AUSGEROLLT" }, + { schluesselId: formel.id, hostId: pve2.id, zielbenutzer: "root", zustand: "ENTFERNT" }, + { schluesselId: widerrufen.id, hostId: pve1.id, zielbenutzer: "root" }, + ], + }); + await prisma.privateVerwendung.create({ + data: { schluesselId: backup.id, hostId: pve2.id, zielbenutzer: "backup", pfad: "~/.ssh/id_backup" }, + }); + ids = { + gruppe: gruppe.id, + pve1: pve1.id, + pve2: pve2.id, + alt: alt.id, + backup: backup.id, + formel: formel.id, + }; +}); + +describe("zuweisungsDaten", () => { + it("liest nur aktive Schluessel, nicht archivierte Hosts und keine entfernten Verwendungen", async () => { + const daten = await zuweisungsDaten(); + expect(daten.schluessel.map((s) => s.name)).toEqual(["=1+1", "Backup"]); + expect(daten.hosts.map((h) => h.name)).toEqual(["srv-pve01", "srv-pve02"]); + expect(daten.hosts[0]!.gruppenIds).toEqual([ids["gruppe"]]); + expect(daten.oeffentlich).toHaveLength(2); + expect(daten.privat).toHaveLength(1); + }); + + it("liefert nie Chiffrat-Felder", async () => { + const text = JSON.stringify(await zuweisungsDaten()); + for (const feld of ["privatVerschluesselt", "dekVerschluesselt", "masterKeyVersion", "publicKey"]) { + expect(text).not.toContain(feld); + } + }); +}); + +describe("zuweisungsMatrix", () => { + it("loest die Gruppe auf die nicht archivierten Mitglieder auf", async () => { + const { matrix, gruppen } = await zuweisungsMatrix(); + expect(gruppen.map((g) => g.name)).toEqual(["pve"]); + expect(matrix.zellen.get(zellenSchluessel(ids["backup"]!, ids["pve1"]!))?.kennungen).toEqual(["P·G"]); + expect(matrix.zellen.get(zellenSchluessel(ids["backup"]!, ids["pve2"]!))?.kennungen).toEqual([ + "P·G", + "K", + ]); + expect(matrix.zellen.has(zellenSchluessel(ids["backup"]!, ids["alt"]!))).toBe(false); + expect(matrix.zaehler).toEqual({ schluessel: 2, hosts: 2, zuweisungen: 4, nichtSynchron: 3 }); + }); +}); + +describe("GET /api/zuweisungen.csv", () => { + async function abrufen(query = "") { + const { GET } = await import("@/app/api/zuweisungen.csv/route"); + return GET(new Request(`http://localhost/api/zuweisungen.csv${query}`)); + } + + it("verweigert ohne Recht", async () => { + recht.erlaubt = false; + const antwort = await abrufen(); + expect(antwort.status).toBe(403); + }); + + it("liefert die Matrix als Excel-sichere CSV", async () => { + const antwort = await abrufen(); + expect(antwort.status).toBe(200); + expect(antwort.headers.get("content-type")).toContain("text/csv"); + expect(antwort.headers.get("content-disposition")).toContain("sshkv-zuweisungen.csv"); + const text = await antwort.text(); + // Response.text() entfernt die BOM nicht immer – beides zulassen. + const zeilen = text.replace(/^/, "").trimEnd().split("\r\n"); + expect(zeilen).toHaveLength(1 + 4); + expect(zeilen).toContain( + '"Backup";"SHA256:test1";"srv-pve01";"root";"Public Key";"pve";"restrict";"noch nicht ausgerollt"', + ); + expect(zeilen).toContain(`"'=1+1";"SHA256:test2";"srv-pve01";"deploy";"Public Key";"";"";"synchron"`); + }); + + it("wendet die Filter der Seite an", async () => { + const text = await (await abrufen("?q=srv-pve02")).text(); + expect(text).toContain("srv-pve02"); + expect(text).not.toContain("srv-pve01"); + }); +}); diff --git a/tests/zuweisungsmatrix.test.ts b/tests/zuweisungsmatrix.test.ts new file mode 100644 index 0000000..b00dd89 --- /dev/null +++ b/tests/zuweisungsmatrix.test.ts @@ -0,0 +1,210 @@ +import { describe, expect, it } from "vitest"; +import { csvEntschaerfen, csvZeile } from "@/lib/csv"; +import { + matrixAufbauen, + matrixCsv, + matrixFilterAus, + matrixFilterQuery, + zellenSchluessel, + type MatrixDaten, + type PublicZeile, +} from "@/lib/zuweisungsmatrix"; + +/** Zuweisungsmatrix (#025): reine Funktion, Gruppenaufloesung, Filter, CSV. */ + +const backup = { + id: "s-backup", + name: "Backup pve", + fingerprint: "SHA256:backup", + kategorie: "DIENST" as const, + person: null, +}; +const anna = { + id: "s-anna", + name: "Anna Laptop", + fingerprint: "SHA256:anna", + kategorie: "PERSON" as const, + person: { id: "p-anna", name: "Anna" }, +}; +const leer = { + id: "s-leer", + name: "Unbenutzt", + fingerprint: "SHA256:leer", + kategorie: "DIENST" as const, + person: null, +}; + +const public_ = ( + abweichung: Partial & Pick, +): PublicZeile => ({ + hostId: null, + hostgruppeId: null, + zielbenutzer: "root", + optionen: null, + zustand: "AUSGEROLLT", + ...abweichung, +}); + +const DATEN: MatrixDaten = { + schluessel: [anna, backup, leer], + hosts: [ + { id: "h-pve1", name: "srv-pve01", gruppenIds: ["g-pve"] }, + { id: "h-pve2", name: "srv-pve02", gruppenIds: ["g-pve"] }, + { id: "h-web", name: "srv-web01", gruppenIds: [] }, + ], + gruppen: [{ id: "g-pve", name: "pve" }], + oeffentlich: [ + public_({ id: "v-gruppe", schluesselId: "s-backup", hostgruppeId: "g-pve", optionen: "restrict" }), + public_({ + id: "v-direkt", + schluesselId: "s-anna", + hostId: "h-pve1", + zielbenutzer: "anna", + zustand: "GEPLANT", + }), + public_({ + id: "v-direkt2", + schluesselId: "s-anna", + hostId: "h-pve1", + zielbenutzer: "root", + zustand: "ABWEICHUNG", + }), + public_({ id: "v-weg", schluesselId: "s-anna", hostId: "h-web", zustand: "ENTFERNT" }), + ], + privat: [ + { + id: "k-1", + schluesselId: "s-backup", + hostId: "h-web", + zielbenutzer: "backup", + pfad: "~/.ssh/id_backup", + zustand: "FEHLGESCHLAGEN", + }, + ], +}; + +describe("matrixAufbauen", () => { + it("loest Gruppen-Zuweisungen je Mitglied auf und kennzeichnet sie", () => { + const m = matrixAufbauen(DATEN); + for (const host of ["h-pve1", "h-pve2"]) { + const zelle = m.zellen.get(zellenSchluessel("s-backup", host))!; + expect(zelle.kennungen).toEqual(["P·G"]); + expect(zelle.eintraege[0]).toMatchObject({ + verwendungId: "v-gruppe", + gruppe: { name: "pve" }, + optionen: "restrict", + }); + } + }); + + it("unterscheidet direkt, Gruppe und Private Key", () => { + const m = matrixAufbauen(DATEN); + expect(m.zellen.get(zellenSchluessel("s-anna", "h-pve1"))!.kennungen).toEqual(["P"]); + const privat = m.zellen.get(zellenSchluessel("s-backup", "h-web"))!; + expect(privat.kennungen).toEqual(["K"]); + expect(privat.eintraege[0]).toMatchObject({ art: "privat", pfad: "~/.ssh/id_backup" }); + }); + + it("zeigt den dringendsten Zustand und alle Zielbenutzer", () => { + const zelle = matrixAufbauen(DATEN).zellen.get(zellenSchluessel("s-anna", "h-pve1"))!; + expect(zelle.zustand).toBe("ABWEICHUNG"); + expect(zelle.zielbenutzer).toEqual(["anna", "root"]); + }); + + it("laesst entfernte Verwendungen weg", () => { + expect(matrixAufbauen(DATEN).zellen.has(zellenSchluessel("s-anna", "h-web"))).toBe(false); + }); + + it("zaehlt Zuweisungen je Host und die nicht synchronen", () => { + expect(matrixAufbauen(DATEN).zaehler).toEqual({ + schluessel: 3, + hosts: 3, + zuweisungen: 5, + nichtSynchron: 3, + }); + }); + + it("filtert Spalten nach Hostgruppe und Zeilen nach Kategorie und Person", () => { + expect(matrixAufbauen(DATEN, { gruppeId: "g-pve" }).spalten.map((h) => h.id)).toEqual([ + "h-pve1", + "h-pve2", + ]); + expect(matrixAufbauen(DATEN, { kategorie: "PERSON" }).zeilen.map((s) => s.id)).toEqual(["s-anna"]); + expect(matrixAufbauen(DATEN, { personId: "p-anna" }).zeilen.map((s) => s.id)).toEqual(["s-anna"]); + }); + + it("sucht in Schluessel- und Hostnamen", () => { + const nachSchluessel = matrixAufbauen(DATEN, { q: "backup" }); + expect(nachSchluessel.zeilen.map((s) => s.id)).toEqual(["s-backup"]); + expect(nachSchluessel.spalten).toHaveLength(3); + + const nachHost = matrixAufbauen(DATEN, { q: "WEB01" }); + expect(nachHost.zeilen).toHaveLength(3); + expect(nachHost.spalten.map((h) => h.id)).toEqual(["h-web"]); + + const nichts = matrixAufbauen(DATEN, { q: "gibtsnicht" }); + expect(nichts.zeilen).toHaveLength(0); + expect(nichts.spalten).toHaveLength(0); + }); + + it("blendet mit „nur belegt“ leere Zeilen und Spalten aus", () => { + const m = matrixAufbauen(DATEN, { nurBelegt: true, gruppeId: "g-pve" }); + expect(m.zeilen.map((s) => s.id)).toEqual(["s-anna", "s-backup"]); + expect(m.spalten.map((h) => h.id)).toEqual(["h-pve1", "h-pve2"]); + expect(matrixAufbauen(DATEN, { nurBelegt: true, q: "unbenutzt" }).zeilen).toHaveLength(0); + }); + + it("zaehlt nur, was in der gefilterten Ansicht steht", () => { + expect(matrixAufbauen(DATEN, { gruppeId: "g-pve" }).zaehler.zuweisungen).toBe(4); + }); +}); + +describe("Filter aus GET-Parametern", () => { + it("liest bekannte Werte und verwirft unbekannte Kategorien", () => { + const filter = matrixFilterAus({ + gruppe: "g1", + kategorie: "QUATSCH", + person: ["p1", "p2"], + q: " pve ", + belegt: "1", + }); + expect(filter).toEqual({ gruppeId: "g1", kategorie: "", personId: "p1", q: "pve", nurBelegt: true }); + expect(matrixFilterQuery(filter)).toBe("?gruppe=g1&person=p1&q=pve&belegt=1"); + expect(matrixFilterQuery(matrixFilterAus({}))).toBe(""); + }); +}); + +describe("CSV", () => { + it("entschaerft Formelbeginne fuer Excel", () => { + for (const wert of ["=1+1", "+49", "-x", "@SUMME(A1)", "\tx"]) + expect(csvEntschaerfen(wert)).toBe(`'${wert}`); + expect(csvEntschaerfen("root")).toBe("root"); + expect(csvZeile(['restrict,from="10.0.0.1"', null])).toBe('"restrict,from=""10.0.0.1""";""'); + }); + + it("schreibt eine Zeile je Zelleneintrag mit Kopf und BOM", () => { + const csv = matrixCsv(matrixAufbauen(DATEN)); + expect(csv.startsWith("")).toBe(true); + const zeilen = csv.slice(1).trimEnd().split("\r\n"); + expect(zeilen[0]).toBe( + '"Schlüssel";"Fingerprint";"Host";"Zielbenutzer";"Art";"Über Gruppe";"Optionen";"Zustand"', + ); + expect(zeilen).toHaveLength(1 + 5); + expect(zeilen).toContain( + '"Backup pve";"SHA256:backup";"srv-pve02";"root";"Public Key";"pve";"restrict";"synchron"', + ); + expect(zeilen).toContain( + '"Backup pve";"SHA256:backup";"srv-web01";"backup";"Private Key";"";"Pfad: ~/.ssh/id_backup";"fehlgeschlagen"', + ); + }); + + it("entschaerft boesartige Schluesselnamen im Export", () => { + const daten: MatrixDaten = { + ...DATEN, + schluessel: [{ ...backup, name: '=HYPERLINK("http://x","klick")' }], + }; + const csv = matrixCsv(matrixAufbauen(daten)); + expect(csv).toContain(`"'=HYPERLINK(""http://x"",""klick"")"`); + expect(csv).not.toMatch(/(^|;|\n)"=/); + }); +});