/** * Die Sperren der Anwendungsrolle — nach einer Wiederherstellung. * * Hintergrund, und er ist unerwartet: * * Beim ersten Start richtet `docker/postgres/10-init-app-role.sh` eine * Vorgabeprivilegierung ein — jede künftig angelegte Tabelle bekommt * automatisch alle Rechte für `florian_app`. Das ist im Betrieb genau richtig: * eine neue Migration soll nicht daran scheitern, dass jemand vergessen hat, * Rechte zu vergeben. * * `pg_restore` legt die Tabellen aber ebenfalls neu an. Die Vorgabe greift * also auch dort — und die `GRANT`-Anweisungen aus dem Dump können nur * hinzufügen, nie wegnehmen. Nach einer Wiederherstellung stünde die * Anwendungsrolle damit wieder mit allen Rechten da: sie dürfte das Audit-Log * ändern, Wiki-Fassungen löschen, Kiosk-Vorgänge umschreiben. * * Nichts an der Anwendung würde darauf hinweisen. Die Unveränderlichkeit, auf * der jeder Nachweis gegenüber der Unfallkasse beruht, wäre stillschweigend * weg — bis jemand danach fragt. * * Gefunden haben das die Datenbanktests nach der ersten Rückspielprobe. * Deshalb gibt es diese Datei: **eine** Liste, aus der sowohl das * Wiederherstellen als auch das Prüfen der Sperren entsteht. Zwei Listen * wären zwei Wahrheiten. */ /** Tabelle → Rechte, die `florian_app` NICHT haben darf, mit Begründung. */ export const SPERREN: Array<{ tabelle: string; rechte: string[]; grund: string }> = [ { tabelle: "berechtigung", rechte: ["INSERT", "UPDATE", "DELETE"], grund: "systemweiter Rechtekatalog — nur lesbar", }, { tabelle: "audit_log", rechte: ["UPDATE", "DELETE"], grund: "append-only; das Löschen geht nur im Aufbewahrungslauf", }, { tabelle: "kiosk_vorgang", rechte: ["UPDATE", "DELETE"], grund: "übermittelte Terminalvorgänge sind unveränderlich", }, { tabelle: "druckmessung", rechte: ["UPDATE", "DELETE"], grund: "Atemschutzüberwachung — Druckwerte werden nie korrigiert", }, { tabelle: "atemschutz_ereignis", rechte: ["UPDATE", "DELETE"], grund: "wie oben: der Verlauf einer Überwachung bleibt, wie er war", }, { tabelle: "benachrichtigung", rechte: ["DELETE"], grund: "was zugestellt wurde, bleibt nachweisbar", }, { tabelle: "ki_vorgang", rechte: ["DELETE"], grund: "das KI-Protokoll belegt, was die Maschine getan hat", }, { tabelle: "wikiversion", rechte: ["UPDATE", "DELETE"], grund: "jede Fassung einer Wiki-Seite bleibt erhalten", }, { tabelle: "kassenabschluss", rechte: ["DELETE"], grund: "ein festgeschriebener Abschluss lässt sich nicht wegräumen", }, { tabelle: "benutzer", rechte: ["INSERT", "DELETE"], grund: "Konten entstehen und vergehen über den Systemzugang", }, ]; /** Die SQL-Anweisungen, die die Sperren wiederherstellen. */ export function sperrenSql(): string[] { return SPERREN.map( ({ tabelle, rechte }) => `REVOKE ${rechte.join(", ")} ON "${tabelle}" FROM florian_app`, ); } /** Alle Kombinationen, die nach der Wiederherstellung fehlen müssen. */ export function verboteneRechte(): Array<{ tabelle: string; recht: string }> { return SPERREN.flatMap(({ tabelle, rechte }) => rechte.map((recht) => ({ tabelle, recht })), ); }