diff options
| author | Chia <Chia@93.nz> | 2026-08-05 22:01:29 +1200 |
|---|---|---|
| committer | Chia <Chia@93.nz> | 2026-08-05 22:07:50 +1200 |
| commit | eadb2ffe85c43cf6fc741c9823cd28eedb4a844c (patch) | |
| tree | 1aba2536d57360da403aa35c9ced58b615c7064e /internal/controlplane/retention.go | |
| parent | cd0dd91ab93653631904f2ea0e574ccde6d60339 (diff) | |
feat: harden prepaid billing and commercial operations
Diffstat (limited to '')
| -rw-r--r-- | internal/controlplane/retention.go | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/internal/controlplane/retention.go b/internal/controlplane/retention.go new file mode 100644 index 0000000..4b20611 --- /dev/null +++ b/internal/controlplane/retention.go @@ -0,0 +1,57 @@ +package controlplane + +import ( + "context" + "log/slog" + "time" +) + +func (s *Store) RunRetentionWorker(ctx context.Context, auditDays, securityDays int, logger *slog.Logger) { + run := func() { + cleanupCtx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + if err := s.pruneExpiredSecurityData(cleanupCtx, auditDays, securityDays); err != nil { + logger.Error("retention_cleanup_failed", "error", err) + } + } + run() + ticker := time.NewTicker(24 * time.Hour) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + run() + } + } +} + +func (s *Store) pruneExpiredSecurityData(ctx context.Context, auditDays, securityDays int) error { + tx, err := s.db.Begin(ctx) + if err != nil { + return err + } + defer tx.Rollback(ctx) + auditCutoff := time.Now().UTC().AddDate(0, 0, -auditDays) + securityCutoff := time.Now().UTC().AddDate(0, 0, -securityDays) + queries := []struct { + query string + cutoff time.Time + }{ + {`DELETE FROM audit_logs WHERE created_at < $1`, auditCutoff}, + {`DELETE FROM console_sessions WHERE expires_at < $1 OR (revoked_at IS NOT NULL AND revoked_at < $1)`, securityCutoff}, + {`DELETE FROM console_action_tokens WHERE expires_at < $1 OR (consumed_at IS NOT NULL AND consumed_at < $1)`, securityCutoff}, + {`DELETE FROM console_auth_challenges WHERE expires_at < $1 OR (consumed_at IS NOT NULL AND consumed_at < $1)`, securityCutoff}, + {`DELETE FROM console_webauthn_challenges WHERE expires_at < $1 OR (consumed_at IS NOT NULL AND consumed_at < $1)`, securityCutoff}, + {`DELETE FROM console_login_throttles WHERE updated_at < $1`, securityCutoff}, + {`DELETE FROM console_rate_limits WHERE updated_at < $1`, securityCutoff}, + {`DELETE FROM console_mail_outbox WHERE status='sent' AND sent_at < $1`, securityCutoff}, + } + for _, item := range queries { + if _, err := tx.Exec(ctx, item.query, item.cutoff); err != nil { + return err + } + } + return tx.Commit(ctx) +} |
