Skip to content

Testing

Luara edited this page Jul 5, 2026 · 2 revisions

Testing

Methodology

Three approaches, since no single one catches everything:

  1. Code review — structured passes across the full codebase, across multiple dedicated sessions
  2. API testing — direct HTTP requests against the live Supabase REST/RPC endpoints using the real public anon key, the same vantage point an attacker with no account has
  3. Manual flow testing — walking every major journey in both anonymous and signed-in states

The API-testing pass is what caught the RLS/RPC gaps documented in Security — reading the code alone missed them, because the intent in a migration's comments didn't always match the deployed database's actual state.


Main Flows Tested

Flow Result Bug found
Home → Map → Colony (anonymous) ✅ Pass
Login with returnTo ✅ Pass Fixed: signup ignored returnTo; later hardened against open redirect
Colony registration ✅ Pass
Becoming a caretaker (instant access) ✅ Pass Fixed: button didn't refresh
Anonymous report (9 types) ✅ Pass
Help flow (9 situations) ✅ Pass
Full article + tracked progress ✅ Pass Fixed: marked read on open instead of on scroll-to-bottom
Quiz (3 result profiles) ✅ Pass
PT/EN toggle on every page ✅ Pass Fixed: raw translation keys showing on the caretaker letter
Cat assistant (9 triggers) ✅ Pass Fixed: markers recorded without ever displaying

Edge Cases Tested

Edge case Result Action
Colony registration validation fails Redirects to sighting registration
Health index with 0 registered cats No division-by-zero
Same user confirms a report twice Blocked by constraint
Self-confirmation of a report Blocked by RPC
Self-thanking Blocked by RPC (migration 0068)
Rate limit: 11th anonymous report in 1h Friendly message shown
Streak: two visits same day Idempotent
Streak: 1+ day gap Resets to 1, not 0
Colony not found (invalid ID) Proper 404
Non-image file upload Rejected before upload
File > 5MB Rejected with message
Double-click on check-in Fixed: was creating 2 events
Duplicate flag Fixed: unique constraint added
3rd false-pin flag on a colony Colony removed, creator banned, notified
returnTo=//evil.com on login Rejected, falls back to a safe internal path

Security Tests (via API, using the anon key)

Test Result
SELECT latitude FROM colonies ✅ Permission denied
SELECT latitude FROM reports ✅ Permission denied
RPC get_colony_exact_location for a colony you're not linked to ✅ Denied
RPC confirm_report on your own report ✅ Denied (self-confirm guard)
RPC thank_action on your own action ✅ Denied (self-thank guard)
RPC record_daily_visit anonymously ✅ Initially succeeded (drift found), fixed, re-verified rejected
Path traversal ../ in upload path ✅ Sanitized before reaching storage
Reverse-geocode with out-of-range coordinates ✅ Rejected before any request is built
SELECT current_streak FROM profiles for another user ✅ Denied (column-level grant)
Insert beyond a text field's length limit ✅ Rejected by CHECK constraint
Insert a colony/report with out-of-range coordinates ✅ Rejected by CHECK constraint
SELECT * FROM knowledge_progress for another user ✅ Empty result, RLS scoped to own rows
Call notify_caretakers directly via REST, repeatedly ✅ Rate-limited by the database circuit breaker
Upload without authentication ✅ Denied

Bugs Found and Fixed (representative sample by day)

Early functional audit:

  • New caretaker couldn't see controls without a manual refresh → fixed with a dedicated access provider
  • "Become a caretaker" button persisted after linking → fixed with a load-time check

Larger bug-hunt sessions (16+ bugs in one pass):

  • Missing-cat flow was in the wrong place → moved to the help flow
  • Interest modal shown even to already-linked caretakers → fixed
  • Castration status was manually set → made automatic from registered cats
  • Weather was hardcoded to Natal → made dynamic based on map coordinates

4-agent parallel audit:

  • Article marked "read" on open instead of on scroll-to-bottom → fixed
  • Double-click created 2 check-ins → debounce added
  • A fully-built banner component was never actually rendered anywhere → fixed
  • Signup ignored the returnTo param → <Suspense> boundary added (was also a build-breaking bug)
  • Critical RPCs were executable by the anon key → migrations added

Security-focused pass:

  • Exact report coordinates visible to anonymous users → fixed
  • Streaks readable by any authenticated user → column-level grant added
  • thank_action had no self-thank guard → fixed
  • knowledge_progress had no unique constraint → fixed
  • Notification RPCs were open to spam/phishing injection → fixed with a fixed message template

WCAG + Aikido pass:

  • 15 modals with no focus trap → shared hook rewritten
  • 2 forms relying on placeholder-only labels → real labels added
  • Success-state contrast at 3.3:1 → corrected to 4.5:1+
  • Path traversal in uploads (Aikido HIGH) → buildSafeStoragePath()
  • SSRF in geocoding (Aikido LOW) → validateCoordinates()

Final pre-submission security pass (this session):

  • Open redirect via returnTo in login/signup → lib/safeReturnTo.ts
  • SVG-as-XSS vector in photo upload MIME check → explicit raster allowlist
  • notify_caretakers had no database-level rate limit → circuit breaker added
  • No coordinate range CHECK constraints on colonies/reports → added
  • profiles.display_name had no database-level length limit → added
  • Missing security headers (X-DNS-Prefetch-Control, X-XSS-Protection, Strict-Transport-Security) → added

Full itemized findings: docs/AUDIT_REPORT.md, docs/UI_AUDIT_REPORT.md.


Accessibility (WCAG 2.2)

Criterion Status
4.5:1 contrast on normal text ✅ Failures found and fixed
Keyboard navigation ✅ Main flows tested
Visible focus ✅ Ring fixed on dark sections
Modal focus trap ✅ 15 modals fixed
Form labels ✅ 2 forms fixed
Correct ARIA roles ✅ Tabs, modals, progress bars
aria-live on dynamic content ✅ Notifications, confirmations
prefers-reduced-motion ✅ All animations disabled
44×44px touch targets ✅ Verified on mobile
lang attribute PT/EN ✅ Updated dynamically

Numbers

40+ bugs found and fixed across many dedicated audit sessions (functional, security, accessibility, UI consistency, content, performance, mobile responsiveness), plus a dedicated final pre-submission security pass covering RLS, RPCs, headers, rate limiting, and dependency audits.

Clone this wiki locally