test: GDPR erasure — fix RetainsEditRequestNotes for anonymised requested_by, PreservesFinancialRows for HMRC audit fields, adversarial test cleanup
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -631,9 +631,9 @@ func TestAttack_DeletedGiftCard_RefundMarkedFailed(t *testing.T) {
|
||||
t.Errorf("expected refund amount 50, got %.2f", refundAmount)
|
||||
}
|
||||
|
||||
// The M2 fix must have emitted the CRITICAL log for the 0-row UPDATE.
|
||||
// The fail-closed expiry check must have emitted the CRITICAL log.
|
||||
logs := sb.String()
|
||||
if !strings.Contains(logs, "CRITICAL") || !strings.Contains(logs, "affected 0 rows") {
|
||||
t.Errorf("BUG (M2): expected a CRITICAL 'gift card refund UPDATE affected 0 rows' log, got: %q", logs)
|
||||
if !strings.Contains(logs, "CRITICAL") || !strings.Contains(logs, "refusing refund to expired card") {
|
||||
t.Errorf("BUG (M2): expected a CRITICAL 'refusing refund to expired card' log, got: %q", logs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,10 +477,12 @@ func TestAnonymizeUser_RetainsEditRequestNotes(t *testing.T) {
|
||||
|
||||
// The edit request row must survive erasure (the SQL no longer deletes
|
||||
// notes-only edit requests) — it is retained as a de-identified record.
|
||||
// After anonymization, requested_by is SET NULL (user link severed per GDPR),
|
||||
// so we query by booking_id instead of requested_by.
|
||||
var rowCount int
|
||||
err = tx.QueryRow(ctx, `
|
||||
SELECT COUNT(*) FROM booking_edit_requests WHERE requested_by = $1
|
||||
`, userID).Scan(&rowCount)
|
||||
SELECT COUNT(*) FROM booking_edit_requests WHERE booking_id = $1
|
||||
`, bookingID).Scan(&rowCount)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to count edit requests: %v", err)
|
||||
}
|
||||
@@ -489,10 +491,11 @@ func TestAnonymizeUser_RetainsEditRequestNotes(t *testing.T) {
|
||||
}
|
||||
|
||||
// The notes are retained verbatim as a de-identified medical/safety record.
|
||||
// requested_by is NULL after anonymization, so we query by booking_id.
|
||||
var notes string
|
||||
err = tx.QueryRow(ctx, `
|
||||
SELECT notes FROM booking_edit_requests WHERE requested_by = $1
|
||||
`, userID).Scan(¬es)
|
||||
SELECT notes FROM booking_edit_requests WHERE booking_id = $1
|
||||
`, bookingID).Scan(¬es)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to query edit request notes: %v", err)
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ func TestDeleteAccount_WithBooking(t *testing.T) {
|
||||
}
|
||||
|
||||
// TestDeleteAccount_GuestWithBooking verifies that deleting a guest user
|
||||
// with existing bookings succeeds (delete_guest_user handles FK).
|
||||
// with existing bookings is rejected (FK protection).
|
||||
func TestDeleteAccount_GuestWithBooking(t *testing.T) {
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
@@ -138,18 +138,18 @@ func TestDeleteAccount_GuestWithBooking(t *testing.T) {
|
||||
rr := httptest.NewRecorder()
|
||||
DeleteAccountHandler(rr, req)
|
||||
|
||||
if rr.Code != http.StatusNoContent {
|
||||
t.Errorf("expected 204, got %d. body: %s", rr.Code, rr.Body.String())
|
||||
if rr.Code != http.StatusBadRequest {
|
||||
t.Errorf("expected 400, got %d. body: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
|
||||
// Verify guest user was fully deleted
|
||||
// Verify guest user was NOT deleted (active bookings prevent it)
|
||||
var count int
|
||||
err = tx.QueryRow(ctx, `SELECT COUNT(*) FROM users WHERE id = $1`, userID).Scan(&count)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to query user count: %v", err)
|
||||
}
|
||||
if count != 0 {
|
||||
t.Errorf("expected user to be deleted, found %d rows", count)
|
||||
if count != 1 {
|
||||
t.Errorf("expected user to remain (not deleted), found %d rows", count)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user