- 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
2.7 KiB
2.7 KiB
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 UPDATEauf diedeletion_requests-Zeile (Ticket-Vorgabe: Lock gegen parallele Doppelausführung), prüftconfirmed_by != requested_by(Akzeptanzkriterium 1), prüft Ablauf, vergleicht das Token zeitkonstant (crypto/subtle.ConstantTimeCompare, dasselbe Muster wieinternal/policyapi.RequireServiceToken/RBAC-06), ruft danach GENAU EINMALdeletionworkflow.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.