Skip to content

fix(compliance): complete right-to-erasure cascade (audit H9, PR 1/5) [REVIEW BEFORE MERGE] - #184

Open
mdenner1234 wants to merge 1 commit into
mainfrom
fix/h9-erasure-cascade
Open

fix(compliance): complete right-to-erasure cascade (audit H9, PR 1/5) [REVIEW BEFORE MERGE]#184
mdenner1234 wants to merge 1 commit into
mainfrom
fix/h9-erasure-cascade

Conversation

@mdenner1234

Copy link
Copy Markdown
Collaborator

fix(compliance): complete the right-to-erasure cascade (audit H9, PR 1/5)

⚠️ REVIEW BEFORE MERGE — this changes what account deletion does to a live
product's data and encodes GDPR/retention policy defaults. Confirm the
policy calls below before merging.

handle_user_deletion() (BEFORE DELETE ON auth.users) erased a hardcoded 15-table
list; ~20 more tables clean up via ON DELETE CASCADE. Four tables carried user PII
with NEITHER — they orphaned personal data after account deletion:
gumroad_sales.email, cookie_consents, support_provisioning_log,
support_ticket_events.

This extends the function to cover them, to_regclass-guarded so a missing/renamed
table can't abort the whole cascade, idempotent.

Policy defaults applied (please confirm):

  • gumroad_salesretain the row, de-identify it (redact email, null
    resolved_user_id). Rationale: financial records typically sit under a legal
    retention obligation (tax) that overrides erasure; we keep the transaction but
    drop the person link. (Alternative: hard-delete — say the word.)
  • cookie_consentsretain as proof-of-consent, de-identify (null user_id,
    user_agent, ip_country). Rationale: GDPR accountability may require keeping that
    consent was given. (Alternative: hard-delete.)
  • support_provisioning_log / support_ticket_eventsdelete the user's rows
    (append-only operational logs). Bypasses the append-only guard for just that
    erase (transactional → auto-reverts on error), mirroring support_prune_webhook_events.
  • audit_log and other tamper-evident tables are not touched here — they get
    redact-in-place via the admin-erasure PR (PR 2/5), never hard-deleted.

Test: supabase/tests/h9_erasure_cascade_test.sql (pgTAP, 6 cases) creates a user
with PII in all four orphan tables, deletes the account, and asserts each is
erased/de-identified and the profile is gone. Full supabase test db = 105/105.

Part of the H9 series: (1) this cascade, (2) admin erasure RPC + DSAR-queue wiring,
(3) fix the broken/contradictory audit-log purge, (4) enforce documented retention
floors, (5) complete export_my_data + DSAR SLA watchdog.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

🤖 Generated with Claude Code

…1/5)

> ⚠️ REVIEW BEFORE MERGE — this changes what account deletion does to a live
> product's data and encodes GDPR/retention **policy defaults**. Confirm the
> policy calls below before merging.

`handle_user_deletion()` (BEFORE DELETE ON auth.users) erased a hardcoded 15-table
list; ~20 more tables clean up via ON DELETE CASCADE. Four tables carried user PII
with NEITHER — they orphaned personal data after account deletion:
`gumroad_sales.email`, `cookie_consents`, `support_provisioning_log`,
`support_ticket_events`.

This extends the function to cover them, `to_regclass`-guarded so a missing/renamed
table can't abort the whole cascade, idempotent.

**Policy defaults applied (please confirm):**
- `gumroad_sales` — **retain the row, de-identify it** (redact email, null
  resolved_user_id). Rationale: financial records typically sit under a legal
  retention obligation (tax) that overrides erasure; we keep the transaction but
  drop the person link. (Alternative: hard-delete — say the word.)
- `cookie_consents` — **retain as proof-of-consent, de-identify** (null user_id,
  user_agent, ip_country). Rationale: GDPR accountability may require keeping that
  consent was given. (Alternative: hard-delete.)
- `support_provisioning_log` / `support_ticket_events` — **delete** the user's rows
  (append-only operational logs). Bypasses the append-only guard for just that
  erase (transactional → auto-reverts on error), mirroring support_prune_webhook_events.
- `audit_log` and other tamper-evident tables are **not** touched here — they get
  redact-in-place via the admin-erasure PR (PR 2/5), never hard-deleted.

Test: `supabase/tests/h9_erasure_cascade_test.sql` (pgTAP, 6 cases) creates a user
with PII in all four orphan tables, deletes the account, and asserts each is
erased/de-identified and the profile is gone. Full `supabase test db` = 105/105.

Part of the H9 series: (1) this cascade, (2) admin erasure RPC + DSAR-queue wiring,
(3) fix the broken/contradictory audit-log purge, (4) enforce documented retention
floors, (5) complete export_my_data + DSAR SLA watchdog.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

🛡️ Penetration test results

Pen-test suite: sast

Generated 2026-04-29T03:40:44.503Z

Totals: ✅ 49 pass · ❌ 0 fail · ⊘ 0 skip · ⚠️ 0 error

Status Test Control Evidence
SAST-NO-DANGEROUSLY-SET-INNER-HTML-WITHOUT-SANITIZE XSS prevention via DOMPurify 6 usage(s), all sanitized.
SAST-NO-EVAL Code injection
SAST-NO-DOCUMENT-WRITE DOM clobbering
SAST-NO-DANGEROUS-DOM-SINKS DOM-based XSS sink prevention 0 DOM sink usage(s) audited.
SAST-DOMPURIFY-DOM-CLOBBERING-GUARDS DOM clobbering prevention
SAST-TARGET-BLANK-NOOPENER Reverse-tabnabbing
SAST-NO-HARDCODED-SECRETS Secret leakage
SAST-NO-CONSOLE-LOG-OF-SECRETS Secret logging
SAST-NO-STACKTRACE-TO-CLIENT Safe error handling
SAST-NO-INSECURE-RANDOM-FOR-CRYPTO Cryptographic randomness
SAST-NO-WEAK-HASH Cryptographic strength
SAST-NO-MANUAL-PASSWORD-STORAGE Password storage delegation
SAST-CLIENT-COOKIE-SAMESITE-SECURE Cookie theft and CSRF mitigation 1 client-set cookie(s) audited.
SAST-NO-CLIENT-STORAGE-AUTHZ Authorization must be server-side
SAST-JWT-VERIFY-NOT-DECODE-ONLY JWT verification
SAST-IDOR-OBJECT-ACCESS-HELPER IDOR and multi-tenant object access
SAST-NO-SECURITY-QUESTION-AUTH Authentication recovery strength
SAST-EMAIL-VALIDATION-CENTRALIZED Email validation and verification
SAST-FORGOT-PASSWORD-NON-ENUMERATING Forgot password enumeration resistance
SAST-PUBLIC-EDGE-ROUTE-JUSTIFICATION Attack surface review 3 public route(s) justified.
SAST-SHARED-JSON-SECURITY-HEADERS AJAX response hardening
SAST-REST-QUERY-PARAMETERIZATION-GUARDS REST query parameterization and SQL injection prevention
SAST-NO-HTTP-URLS-IN-SOURCE Mixed-content
SAST-EDGE-JSON-REQUESTS-USE-BOUNDED-PARSER CSRF, deserialization, and DoS request parsing 49 edge function(s) audited; adopted helpers may not be bypassed.
SAST-NO-RAW-SQL-EXECUTION Database security least privilege
SAST-MASS-ASSIGNMENT-ALLOWLIST-HELPERS Mass assignment prevention
SAST-SBOM-SCRIPT-PRESENT Dependency graph and SBOM inventory
SAST-FILE-UPLOAD-ALLOWLISTS File upload validation
SAST-NO-SVG-UPLOADS Scriptable upload content rejection
SAST-PROTOTYPE-POLLUTION-RECURSIVE-GUARDS Prototype pollution prevention
SAST-CSS-UNTRUSTED-STYLING-GUARDS CSS injection and UI redress prevention
SAST-NO-GRAPHQL-PROD-INTROSPECTION GraphQL attack surface reduction
SAST-HTML5-POSTMESSAGE-ORIGIN HTML5 messaging origin safety
SAST-IAC-NO-PERMISSIVE-PATTERNS Infrastructure as Code secure defaults 5 infrastructure/config file(s) audited.
SAST-SSRF-CLOUD-BOUNDARY-GUARDS SSRF, network segmentation, and secure cloud architecture
SAST-GITHUB-ACTIONS-NO-UNTRUSTED-CONTEXT-IN-RUN CI/CD command injection prevention
SAST-GITHUB-ACTIONS-PINNED-BY-SHA CI/CD supply-chain integrity
SAST-GITHUB-ACTIONS-LEAST-PRIVILEGE-PERMISSIONS CI/CD least privilege
SAST-EDGE-FUNCTIONS-VERIFY-JWT-OR-EXPLICIT Edge-function auth posture 49 edge functions audited.
SAST-LOGGING-STRUCTURED-REDACTED Logging vocabulary and sensitive data redaction
SAST-DISCORD-NOTIFY-PAYLOAD-SANITIZED Outbound webhook injection prevention
SAST-LLM-MCP-TOOL-GUARDS LLM prompt injection and MCP tool safety
SAST-SESSION-MANAGEMENT-GUARDS Session management server-side posture
SAST-REDIRECT-TLS-THIRD-PARTY-GUARDS Redirect, TLS, and third-party JavaScript safety
SAST-PAYMENT-TRANSACTION-AUTH-GUARDS Third-party payment and transaction authorization integrity
SAST-WEBSOCKET-WEB-SERVICE-XXE-GUARDS WebSocket, web service, and XML parser safety
SAST-PRIVACY-VIRTUAL-PATCH-ZERO-TRUST-GUARDS Privacy protection, virtual patching, and zero-trust authorization
SAST-DEPENDENCY-RISK-ACCEPTANCE-GUARDS Vulnerable dependency management
SAST-RLS-MIGRATIONS-PRESENT RLS coverage 213 migration(s) audited.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant