/** * Lesbare Beschriftung der technischen Protokoll-Aktionen (#027). * * Das Protokoll speichert stabile Schluessel wie `authorized_keys.geschrieben`, damit sich * Auswertungen (CSV, Syslog, SIEM) nicht an Oberflaechentexten aufhaengen. Die Ansicht * uebersetzt sie hier. `tests/protokoll-aktionen.test.ts` sucht jede `aktion: "…"` im * Quellcode und verlangt einen Eintrag – eine neue Aktion ohne Text faellt so sofort auf. * * `aendert`: Die Aktion veraendert etwas (Datei geschrieben, Schluessel erzeugt …) und wird bei * Erfolg in --ok gezeigt. Lesende oder rein informative Aktionen (Anmeldung, Abruf, Export) * bleiben neutral, damit das Grün die Stellen markiert, an denen sich etwas getan hat. */ export const AKTIONSGRUPPEN = { anmeldung: "Anmeldung", benutzer: "Benutzer", hostkey: "Host-Key", ausrollen: "Ausrollen", schluessel: "Schlüssel", widerruf: "Widerruf/Rotation", zielkonto: "Zielkonto", abgleich: "Abgleich", hosts: "Hosts", stammdaten: "Personen und Vorlagen", protokoll: "Protokoll", benachrichtigung: "Benachrichtigung", } as const; export type Aktionsgruppe = keyof typeof AKTIONSGRUPPEN; type Beschreibung = { readonly text: string; readonly gruppe: Aktionsgruppe; readonly aendert: boolean }; const a = (text: string, gruppe: Aktionsgruppe, aendert = true): Beschreibung => ({ text, gruppe, aendert }); export const AKTIONEN: Readonly> = { // Benachrichtigungen (#028) "benachrichtigung.gesendet": a("Benachrichtigung gesendet", "benachrichtigung", false), "benachrichtigung.fehlgeschlagen": a("Benachrichtigung fehlgeschlagen", "benachrichtigung", false), "einstellungen.benachrichtigungen.geaendert": a("Benachrichtigungen geändert", "benachrichtigung"), // Ereignisname im Webhook (#028); taucht als Text auf, wenn ein Host-Key-Alarm protokolliert wird. "hostkey.geaendert": a("Host-Key geändert (Alarm)", "hostkey", false), // Anmeldung und Bestaetigung (#004) "anmeldung.oidc": a("Anmeldung (OIDC)", "anmeldung", false), "anmeldung.oidc.erstmals": a("Erste Anmeldung (OIDC)", "anmeldung"), "anmeldung.verweigert": a("Anmeldung verweigert", "anmeldung", false), "anmeldung.notfall": a("Anmeldung Notfall-Admin", "anmeldung", false), "anmeldung.lokal": a("Anmeldung (lokales Konto)", "anmeldung", false), "anmeldung.lokal.fehlgeschlagen": a("Anmeldung (lokal) fehlgeschlagen", "anmeldung", false), "anmeldung.lokal.gesperrt": a("Anmeldung (lokal) gesperrt – zu viele Fehlversuche", "anmeldung", false), "anmeldung.lokal.totp_falsch": a("Anmeldung (lokal): falscher TOTP-Code", "anmeldung", false), "konto.passwort_gesetzt": a("Eigenes Passwort gesetzt", "benutzer"), "konto.totp_eingerichtet": a("TOTP eingerichtet", "anmeldung"), "benutzer.angelegt": a("Lokales Konto angelegt", "benutzer"), "benutzer.rolle_geaendert": a("Rolle geändert", "benutzer"), "benutzer.gesperrt": a("Konto gesperrt", "benutzer"), "benutzer.entsperrt": a("Konto entsperrt", "benutzer"), "benutzer.zurueckgesetzt": a("Konto zurückgesetzt (Passwort und TOTP)", "benutzer"), "anmeldung.notfall.fehlgeschlagen": a("Notfall-Anmeldung fehlgeschlagen", "anmeldung", false), "anmeldung.notfall.gesperrt": a("Notfall-Anmeldung gesperrt", "anmeldung", false), "anmeldung.notfall.totp_falsch": a("Notfall-Anmeldung: TOTP falsch", "anmeldung", false), "bestaetigung.oidc": a("Anmeldung bestätigt (Re-Auth)", "anmeldung", false), "notfall.totp_eingerichtet": a("TOTP für Notfall-Admin eingerichtet", "anmeldung"), // Host-Keys (#009) "hostkey.abgerufen": a("Host-Key abgerufen", "hostkey", false), "hostkey.bestaetigt": a("Host-Key bestätigt", "hostkey"), "hostkey.ersetzt": a("Host-Key ersetzt", "hostkey"), "hostkey.abgelehnt": a("Host-Key abgelehnt", "hostkey"), "hostkey.abweichung": a("Host-Key weicht ab – Verbindung abgebrochen", "hostkey", false), // Ausrollen (#016, #017) "authorized_keys.geschrieben": a("authorized_keys geschrieben", "ausrollen"), "privatekey.ausgerollt": a("Private Key ausgerollt", "ausrollen"), "verwendung.public.angelegt": a("Public Key zugewiesen", "ausrollen"), "verwendung.public.entfernen": a("Public-Key-Zuweisung zum Entfernen vorgemerkt", "ausrollen"), "verwendung.private.angelegt": a("Private Key zugewiesen", "ausrollen"), "verwendung.private.entfernen": a("Private-Key-Zuweisung zum Entfernen vorgemerkt", "ausrollen"), // Schluessel (#012, #013, #014) "schluessel.erzeugt": a("Schlüssel erzeugt", "schluessel"), "schluessel.importiert": a("Schlüssel importiert", "schluessel"), "schluessel.uebernommen": a("Schlüssel vom Host übernommen", "schluessel"), "schluessel.selbst_hinterlegt": a("Eigenen Public Key hinterlegt", "schluessel"), "schluessel.selbst_entfernt": a("Eigenen Public Key entfernt", "schluessel"), "schluessel.geaendert": a("Schlüssel geändert", "schluessel"), "privatekey.angefordert": a("Private Key angefordert", "schluessel", false), "privatekey.angezeigt": a("Private Key angezeigt", "schluessel", false), "privatekey.heruntergeladen": a("Private Key heruntergeladen", "schluessel", false), "privatekey.geloescht": a("Private Key gelöscht", "schluessel"), "deploymentkey.erzeugt": a("Deployment-Key erzeugt", "schluessel"), "deploymentkey.geprueft": a("Neuer Deployment-Key geprüft", "widerruf", false), "deploymentkey.umgestellt": a("Deployment-Key umgestellt", "widerruf"), "deploymentkey.abgeschlossen": a("Rotation des Deployment-Keys abgeschlossen", "widerruf"), // Widerruf und Rotation (#023, #024) "schluessel.widerruf.eingeleitet": a("Widerruf eingeleitet", "widerruf"), "schluessel.widerrufen": a("Schlüssel widerrufen", "widerruf"), "schluessel.rotiert": a("Schlüssel rotiert", "widerruf"), "schluessel.rotation.uebernommen": a("Rotation: Zuweisungen übernommen", "widerruf"), "schluessel.rotation.abgebrochen": a("Rotation abgebrochen", "widerruf"), // Zielkonten (#018) "zielkonto.angelegt": a("Zielkonto angelegt", "zielkonto"), "zielkonto.geaendert": a("Zielkonto geändert", "zielkonto"), "zielkonto.entfernt": a("Zielkonto entfernt", "zielkonto"), // Abgleich und Uebernahme (#021, #022) abgleich: a("Abgleich durchgeführt", "abgleich", false), "uebernahme.verwalten": a("Fremden Key übernommen und verwaltet", "abgleich"), "uebernahme.bekannt": a("Fremden Key als bekannt aufgenommen", "abgleich"), // Hosts, Gruppen, Kunden (#008, #010) "host.angelegt": a("Host angelegt", "hosts"), "host.geaendert": a("Host geändert", "hosts"), "host.archiviert": a("Host archiviert", "hosts"), "host.bootstrap.angefordert": a("Einrichtung angefordert", "hosts", false), "host.bootstrap": a("Host eingerichtet (Bootstrap)", "hosts"), "host.bootstrap.geprueft": a("Einrichtung geprüft", "hosts"), "hostgruppe.angelegt": a("Hostgruppe angelegt", "hosts"), "hostgruppe.geaendert": a("Hostgruppe geändert", "hosts"), "kunde.angelegt": a("Kunde angelegt", "hosts"), verbindungstest: a("Verbindung geprüft", "hosts", false), // Personen und Vorlagen (#013, #019) "person.angelegt": a("Person angelegt", "stammdaten"), "person.geaendert": a("Person geändert", "stammdaten"), "person.archiviert": a("Person archiviert", "stammdaten"), "person.verknuepft": a("Person mit Konto verknüpft", "stammdaten"), "vorlage.angelegt": a("Vorlage angelegt", "stammdaten"), "vorlage.geaendert": a("Vorlage geändert", "stammdaten"), "vorlage.archiviert": a("Vorlage archiviert", "stammdaten"), // Protokoll selbst (#027) "protokoll.exportiert": a("Protokoll exportiert (CSV)", "protokoll", false), "protokoll.kette_beschaedigt": a("Hash-Kette beschädigt gefunden", "protokoll", false), }; /** Text zur Aktion; unbekannte (etwa aus aelteren Versionen) bleiben technisch lesbar. */ export function aktionText(aktion: string): string { return AKTIONEN[aktion]?.text ?? aktion; } /** Alle bekannten Aktionen einer Gruppe – Grundlage fuer den Filter `aktion IN (…)`. */ export function aktionenDerGruppe(gruppe: Aktionsgruppe): string[] { return Object.entries(AKTIONEN) .filter(([, b]) => b.gruppe === gruppe) .map(([aktion]) => aktion); } export type AktionsTon = "ok" | "gefahr" | "neutral"; /** Farbe in der Liste: Fehlschlag und Verweigerung immer --danger, Aenderungen --ok. */ export function aktionTon(aktion: string, ergebnis: "ERFOLG" | "FEHLER" | "VERWEIGERT"): AktionsTon { if (ergebnis !== "ERFOLG") return "gefahr"; return AKTIONEN[aktion]?.aendert ? "ok" : "neutral"; } export function istAktionsgruppe(wert: string): wert is Aktionsgruppe { return Object.hasOwn(AKTIONSGRUPPEN, wert); }