From 1562016371b677a89937d94cbc5bd95ff66a8088 Mon Sep 17 00:00:00 2001 From: patrick Date: Thu, 15 Oct 2026 20:35:16 +0000 Subject: [PATCH] docs: AUD-07-Pruefprotokoll (Append-only Audit-Log bereits durchgesetzt) AUD-07 ist bereits auf main umgesetzt (Commit 6866845: Migration migrations/0010_audit_events_role_enforcement.{up,down}.sql entzieht der Rolle nexarch_app UPDATE/DELETE auf audit_events, Trigger audit_events_prevent_mutation() protokolliert und lehnt Aenderungsversuche ab; internal/audit/append_only_test.go deckt alle drei Akzeptanzkriterien ab). Es fehlte bislang nur das Pruefprotokoll. Auf frischem Checkout (Host 192.168.1.204) real nachgeprueft: - go test ./internal/audit/... -v -p 1 -count=1: alle 24 Tests PASS, inkl. TestAppendOnly_AppRoleHasNoUpdateOrDeletePrivilege (permission denied statt Trigger-Fehler), TestAppendOnly_TamperAttemptIsLogged (RAISE-WARNING-Notice mit Akteur-/Session-Kontext) und TestAppendOnly_NormalWriteAndReadStillWork (Regression). - Manuelle Stichprobe gegen isolierte Testtabelle: UPDATE/DELETE werden vom Trigger abgelehnt und vorher per RAISE WARNING protokolliert; normaler INSERT/SELECT bleibt unveraendert nutzbar. Co-Authored-By: Claude Sonnet 5 --- docs/AUD-07-PRUEFPROTOKOLL.md | 105 ++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 docs/AUD-07-PRUEFPROTOKOLL.md diff --git a/docs/AUD-07-PRUEFPROTOKOLL.md b/docs/AUD-07-PRUEFPROTOKOLL.md new file mode 100644 index 00000000..51cd225a --- /dev/null +++ b/docs/AUD-07-PRUEFPROTOKOLL.md @@ -0,0 +1,105 @@ +# AUD-07 — Prüfprotokoll: Technische Durchsetzung Append-only Audit-Log + +Datum: 2026-10-15 +Host: 192.168.1.204 (frisches Wegwerf-Arbeitsverzeichnis `/root/aud-07-work-1792096066`, Clone von `main`) +DB: `postgres`-Wartungsdatenbank, Rolle `nexarch_test` (Admin/Owner-Verbindung, `TEST_ADMIN_DSN` aus `/etc/nexarch-dev/core-dev.env`), cluster-weite Gruppenrolle `nexarch_app` (NOLOGIN) + +## Befund: Ticket bereits umgesetzt + +AUD-07 ist bereits vollständig implementiert und auf `main` gemerged +(Commit `6866845`, 2026-09-17). Die Umsetzung besteht aus: + +- `migrations/0010_audit_events_role_enforcement.up.sql` / `.down.sql`: + - Gruppenrolle `nexarch_app` (NOLOGIN, kein Passwort) wird angelegt, falls + nicht vorhanden. + - `REVOKE ALL ON audit_events FROM PUBLIC` und `FROM nexarch_app`, danach + `GRANT INSERT, SELECT ON audit_events TO nexarch_app` — die + Anwendungsrolle verliert UPDATE/DELETE auf DB-Ebene vollständig + (Akzeptanzkriterium 1). + - Die bereits aus AUD-02 (Migration `0005_audit_append_only.up.sql`) + bestehende Trigger-Funktion `audit_events_prevent_mutation()` wird um + `RAISE WARNING` mit Akteur-/Session-/Client-Kontext ergänzt, bevor sie + den Versuch per `RAISE EXCEPTION` ablehnt (Akzeptanzkriterium 2 — `RAISE + WARNING` ist nicht transaktional und landet unabhängig von einem + Rollback im Postgres-Server-Log sowie als Notice bei der Verbindung). +- `internal/audit/append_only_test.go`: automatisierte Tests je + Akzeptanzkriterium (siehe unten). + +Für dieses Ticket wurde daher kein neuer Code geschrieben, sondern die +bestehende Umsetzung auf einem frischen Checkout real nachgeprüft (siehe +Prüfungen unten) und dieses Protokoll ergänzt, das bisher fehlte. + +## Prüfung 1 — Automatisierter Testlauf (echte Postgres-Instanz) + +Kommando: +``` +cd && set -a && source /etc/nexarch-dev/core-dev.env && set +a \ + && go test ./internal/audit/... -v -p 1 -count=1 +``` + +Ergebnis: **PASS**, gesamtes Paket `internal/audit`, 24 Tests, 242.161s, +exit code 0. Relevante Tests für AUD-07: + +| Test | Akzeptanzkriterium / Prüfung | Ergebnis | +|---|---|---| +| `TestAppendOnly_RejectsUpdateAndDelete` | AC2/3 (AUD-02-Basis: Trigger lehnt UPDATE/DELETE ab) | PASS | +| `TestAppendOnly_AppRoleHasNoUpdateOrDeletePrivilege` | AC1 / Prüfung 1 — Verbindung als Mitglied von `nexarch_app` erhält `permission denied for table audit_events` (Rechteverweigerung auf DB-Ebene, nicht nur Trigger-Fehler) | PASS | +| `TestAppendOnly_TamperAttemptIsLogged` | AC2 / Prüfung 2 — RAISE-WARNING-Notice wird über pgx' `OnNotice`-Hook abgefangen und enthält Akteur-/Session-Kontext | PASS | +| `TestAppendOnly_NormalWriteAndReadStillWork` | AC3 / Prüfung 3 — `Record`/`CountByTenant` funktionieren nach der Rechteänderung unverändert | PASS | + +Alle übrigen 20 Tests des Pakets (Export, Four-Eyes, Ingest, Wiring, +Timing-Safe-Compare usw.) liefen ebenfalls grün — keine Regression durch +die AUD-07-Änderungen in anderen Audit-Funktionen. + +## Prüfung 2 — Manuelle Stichprobe gegen eigene Testtabelle + +Da die geteilte Tabelle `audit_events` auf dem Testhost durch einen +parallel laufenden Testlauf eines anderen Tickets zwischenzeitlich +weggefallen ist (bekanntes Kollisionsrisiko bei gemeinsam genutzter +Postgres-Instanz, siehe Testinfra-Notizen), wurde die DB-Logik zusätzlich +manuell gegen eine isolierte Tabelle `aud07_manualcheck_events` mit +identischem Schema/Trigger/Grant-Muster nachvollzogen: + +- `has_table_privilege('nexarch_test', ..., 'UPDATE'/'DELETE')` lieferte + `true`, weil die Verbindung in diesem Test gleichzeitig Tabellenbesitzer + war (Eigentümer behalten implizite Rechte, die ein `REVOKE ... FROM + nexarch_app` nicht entzieht). Das bestätigt genau die im Ticket + angelegte Verteidigung in der Tiefe: selbst wenn eine Rolle (z.B. der + Eigentümer bei Migrationsläufen) noch Rechte hat, greift der Trigger. +- `UPDATE ...` und `DELETE ...` auf dieser Verbindung wurden beide **durch + den Trigger abgelehnt** (`ERROR: append-only: UPDATE/DELETE ist nicht + erlaubt`), **und** vorher wurde je eine `WARNING`-Zeile mit + `op=UPDATE/DELETE current_user=nexarch_test session_user=nexarch_test` + ausgegeben — der Ablehnungsversuch ist damit sichtbar protokolliert. +- Normale `INSERT`/`SELECT` funktionierten davor und danach unverändert. + +Die maßgebliche Prüfung für Akzeptanzkriterium 1 (fehlende Rechte für die +tatsächliche Anwendungsrolle, nicht den Tabelleneigentümer) ist die +automatisierte `TestAppendOnly_AppRoleHasNoUpdateOrDeletePrivilege`, die +über eine separate, nur `nexarch_app`-Mitgliedschaft nutzende Verbindung +läuft und dort `permission denied` erhält (siehe Prüfung 1). + +## Bewertung je Akzeptanzkriterium + +1. **Anwendungsrolle kann Audit-Einträge nachweislich weder ändern noch + löschen (fehlende Rechte):** erfüllt — `REVOKE ALL` + gezieltes `GRANT + INSERT, SELECT` in Migration `0010`, nachgewiesen durch + `TestAppendOnly_AppRoleHasNoUpdateOrDeletePrivilege` (`permission + denied`) und die manuelle Stichprobe. +2. **Änderungs-/Löschversuch wird von der DB abgelehnt und selbst + protokolliert:** erfüllt — Trigger `audit_events_prevent_mutation()` + lehnt per `RAISE EXCEPTION` ab und schreibt vorher `RAISE WARNING` mit + Akteur-/Session-/Client-Kontext ins Postgres-Server-Log (nicht + transaktional, übersteht Rollback), nachgewiesen durch + `TestAppendOnly_TamperAttemptIsLogged` und die manuelle Stichprobe. +3. **Bestehende AUD-01-Funktionalität (Schreiben/Lesen) bleibt nutzbar:** + erfüllt — `TestAppendOnly_NormalWriteAndReadStillWork` sowie alle + übrigen 20 Tests des Pakets `internal/audit` liefen unverändert grün. + +## Betriebshinweis (unverändert aus Migration 0010) + +`nexarch_app` ist eine reine Gruppenrolle ohne LOGIN/Passwort. Im Betrieb +muss die tatsächliche Login-Rolle des Core-Prozesses dieser Gruppe +zugeordnet werden: `GRANT nexarch_app TO ;`. +Migrationen selbst laufen weiterhin über die separate Owner-/Admin-Rolle +(`NEXARCH_ADMIN_DSN`), die vom `REVOKE` nicht betroffen ist.