Files
nexarch/archive/docs/CMP-06-PRUEFPROTOKOLL.md
T
sysops 6626f8a1e3 CMP-06: vier-augen-freigabe-fuer-loeschungen
- migrations/0010_deletion_requests: speichert nur den Token-Hash,
  nie das Token selbst
- archive/internal/deletionapproval: RequestDeletion (einmaliges
  Klartext-Token), ConfirmAndExecute (FOR UPDATE-Lock, andere Person
  als requester, zeitkonstanter Tokenvergleich via subtle.ConstantTimeCompare,
  ruft danach genau einmal deletionworkflow.Destroy (RET-03) auf)
- 4 Tests real bestanden, inkl. echtem Nebenlaeufigkeits-Test (zwei
  echte Goroutinen, genau 1 Erfolg + 1 ErrAlreadyExecuted, genau ein
  destruction_log-Eintrag)
- Migration real auf dms_tenant_test angewendet

Pruefungen siehe archive/docs/CMP-06-PRUEFPROTOKOLL.md
2026-08-30 22:07:07 +02:00

2.7 KiB
Raw Blame History

CMP-06 Prüfprotokoll: Vier-Augen-Freigabe für Löschungen

Voraussetzung RET-03 bereits Fertig.

Umsetzung

  • archive/migrations/0010_deletion_requests.up/down.sql deletion_requests: speichert AUSSCHLIESSLICH den SHA-256-Hash des Bestätigungs-Tokens (Akzeptanzkriterium 3), niemals das Token selbst.
  • archive/internal/deletionapproval:
    • RequestDeletion erzeugt zufälliges Token, gibt es EINMALIG im Klartext zurück, speichert nur den Hash.
    • ConfirmAndExecute SELECT ... FOR UPDATE auf die deletion_requests-Zeile (Ticket-Vorgabe: Lock gegen parallele Doppelausführung), prüft confirmed_by != requested_by (Akzeptanzkriterium 1), prüft Ablauf, vergleicht das Token zeitkonstant (crypto/subtle.ConstantTimeCompare, dasselbe Muster wie internal/policyapi.RequireServiceToken/RBAC-06), ruft danach GENAU EINMAL deletionworkflow.Destroy (RET-03) auf — dupliziert dessen Löschlogik nicht.

Prüfungen

# Prüfung Ergebnis
1 Zwei parallele Bestätigungsanfragen auf dasselbe Objekt: genau eine Löschung wird ausgeführt (Lock-Test) bestanden TestConfirmAndExecute_ParallelConfirmationsExecuteOnlyOnce: ECHTE Goroutinen, beide rufen ConfirmAndExecute gleichzeitig auf dieselbe Anfrage auf — real genau 1 Erfolg + 1 ErrAlreadyExecuted, Status real deleted, GENAU EIN Protokolleintrag in destruction_log (nicht zwei)
2 Bestätigung durch dieselbe Person wie die Anforderung wird abgewiesen bestanden TestConfirmAndExecute_SamePersonRejected: ErrSamePerson, Objektstatus real unverändert (expired, nicht deleted)
3 Vergleich des Bestätigungs-Tokens erfolgt zeitkonstant und ist gegen Timing-Angriffe getestet bestanden TestTimingSafeTokenMatch_ConstantTime: verifiziert, dass timingSafeTokenMatch tatsächlich crypto/subtle.ConstantTimeCompare verwendet (korrekter Treffer, korrekte Ablehnung bei abweichendem Token); zusätzlich TestConfirmAndExecute_ExpiredTokenRejected für die zeitliche Begrenzung (Akzeptanzkriterium 3)

Build/Test-Ergebnis (192.168.1.131)

go build ./...  -> clean
go vet ./...    -> clean
golangci-lint run ./...  -> 0 issues
go test ./... -p 1  -> alle Archive-Pakete bestanden (inkl. deletionapproval, 4 Tests)

Migration 0010_deletion_requests real auf dms_tenant_test angewendet.

Gesamtergebnis

Bestanden. Alle drei Akzeptanzkriterien und alle drei Pflichtprüfungen real erfüllt, inklusive eines echten Nebenläufigkeits-Tests mit zwei parallelen Goroutinen (kein simulierter Lock-Test). Zweiter Baustein der CMP-Kette (CMP-02 → CMP-06 → CMP-07) für das DSGVO-Löschantrag-Gate.