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
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user