Skip to content

[Low] Launch hardening & cleanup batch (from launch-readiness audit) #59

Description

@novaspatial

Severity: Low — batch of hardening/cleanup items from the launch-readiness audit. Split out if any grows.

Items

  1. Enable leaked-password protection in Supabase Auth (security advisor: currently disabled) — checks passwords against HaveIBeenPwned.

  2. No Stripe idempotencyKey on paymentIntents.create (src/app/api/portal/projects/checkout/route.ts:381-406) — a double-submit mints two intents + rows (bounded only by the 3/min limit). Add an idempotency key.

  3. Observability gaps: webhook/poll metadata-mismatch events log-and-200 with no alerting surface, and absent metadata passes the cross-checks; no error-reporting service (Sentry/OTel) is wired at all (src/app/error.tsx:15 has only a scaffold comment). Wire error reporting + a mismatch alert.

  4. Discount RPC surface: lookup_discount_code is granted to authenticated with no in-body guard and returns full code params incl. reserved/redeemed counts — a per-guess oracle (supabase/migrations/20260715_consume_discount_codes.sql); reserve_/restore_first_mix_discount retain the default EXECUTE TO PUBLIC and their identity guard is bypassed for anon (auth.uid() null passes). Bounded today (0 codes; dormant flag). Route lookup through the service client and revoke the first-mix RPCs to service_role only, matching the catalog trio.

  5. Thin confirm route + error leakage: files/[fileId]/confirm/route.ts uses requireApiUser only (no state/uploader check, blind upload_status='uploaded'); files/route.ts:91 forwards the raw storage/PG error object to the client on 500. Tighten the guard; stop leaking internal error details.

  6. Stripe API version drift: pinned 2026-03-25.dahlia is two releases behind the installed SDK's 2026-05-27.dahlia, and the as ApiVersion cast suppresses drift detection (src/lib/stripe/server.ts:16-20). Re-pin deliberately.

  7. Cosmetic/config: dead footer newsletter form promising a welcome discount (no submit handler); STRIPE_RESTRICTED_KEY documented but unused; package.json still named tailwind-plus-studio with no engines field; contact page shows mix@nova-spatial.com while CONTACT_INBOX_TO=contact@nova-spatial.com; RESEND_FROM_EMAIL fallback is the wrong brand ("Atmos onboarding@resend.dev"); several handlers await request.json() unguarded (500 instead of 400 on malformed bodies); enforce_studio_only_archive lacks the service-role escape its sibling fences have; purge drains only 20 projects/day with mayHaveMore ignored (irrelevant at launch volume).

  8. Orphan rows: no sweeper exists for stale pending project_files rows (register → abandoned PUT) or for registered-but-never-submitted comment-attachment objects. Harmless for /listen (filters upload_status='uploaded') but accumulates.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions