-
Notifications
You must be signed in to change notification settings - Fork 0
Testing
Three approaches, since no single one catches everything:
- Code review — structured passes across the full codebase, across multiple dedicated sessions
- 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
- 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.
| 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 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 |
| 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 |
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
returnToparam →<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_actionhad no self-thank guard → fixed -
knowledge_progresshad 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
returnToin login/signup →lib/safeReturnTo.ts - SVG-as-XSS vector in photo upload MIME check → explicit raster allowlist
-
notify_caretakershad no database-level rate limit → circuit breaker added - No coordinate range
CHECKconstraints oncolonies/reports→ added -
profiles.display_namehad 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.
| 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 |
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.