Thoughts

5 thoughts about "audit" in the last 90 days

Tat-Tally Session 52 E2E Audit - Final Status (as of Session 54, 2026-03-16) All audit findings from the Session 52 full E2E audit are now resolved except two env-config items: FIXED: - B1: RLS policies on scoring_frameworks/criteria fixed (join through categories) - B2: Anon insert policies on entrants/entries tightened (event/category scoping) - H1: scoring_mode change auto-triggers recalculation - H2: Admin warns before removing judge with existing scores - H3: assign_queue_position() has FOR UPDATE lock - H4 (code): @sentry/react added to registration app, initSentry() wired - H5: XSS fix in server/index.mjs via safeJsonStringify() - M1: Display auto-reload 5min to 30min - M2: MC control panel virtualized with @tanstack/react-virtual - M3: Leaderboard tie-breaking uses scored_at instead of submitted_at - M4: All 16 edge function source files in infrastructure/edge-functions/ - M5: Server null-event cache TTL reduced to 5s - M6: Unique Realtime channel names per app - L1: getEntryUrl() uses VITE_ENTRANT_URL env var instead of hardcoded port - L2: Ordinal suffix handles 11th/12th/13th correctly STILL OPEN (env config, not code): - H4-ENV: Need to create Sentry project and set VITE_SENTRY_DSN in Railway env vars - A2P 10DLC: Blocked on LLC/EIN formation - Supabase Pro tier upgrade before Norfolk L3-L5 were structural observations (test coverage gaps), not actionable code fixes. Next up: Phase 12 (Norfolk test event planning) or Sentry project creation.

3/16/2026

Tat-Tally Session 46: Post-Feature Audit (2026-03-15) Audited all new code from Sessions 43-45 (entry codes, registration desk app, scoring modes/display overhaul). Bottom-up review: database, Edge Functions, shared package, frontend apps, infrastructure. SECURITY FIXES APPLIED: - Entry codes RLS policies were missing event_id scoping. Staff from one event could read/write codes for another event. Fixed by adding event_id = get_request_event_id() to all 3 staff policies. - Scoring trigger had 0 >= 0 edge case: when no judges or criteria were assigned, the trigger would calculate and set a false final_score. Added zero guard to both update_entry_final_score() and recalculate_event_scores(). OPERATIONAL FIXES: - expire_old_entry_codes() function existed but nothing called it. Enabled pg_cron extension and scheduled it to run every 5 minutes. - formatScore() showed "87.0 / 0" when maxPossible was 0. Added guard. - Admin event settings: scoring mode save and recalculation RPC were non-atomic. Added rollback if RPC fails. - Registration app had no ErrorBoundary (white screen on crash). Added React class-based ErrorBoundary with reload fallback. - CI workflow was missing registration app in build matrix. Added it. EDGE FUNCTIONS AUDITED (all clean, no fixes needed): - generate-entry-code: auth, event scoping, crypto random codes, 30min expiry - validate-entry-code: status checks, expiry, category status validation - submit-entry v7: atomic code claim, phone dedup, rate limiting, rollback on failure - get-portal v7: scoring_mode, max_possible, per-judge breakdowns all correct DOCUMENTATION: Updated CLAUDE.md (MC now shows entrant names intentionally, app count updated to 6, registration app added). Two commits pushed to main: b1adcf5 (Session 45 features) and a94fa8e (Session 46 audit fixes). All 6 apps pass tsc --noEmit. Two migrations applied to Supabase: session46_audit_fixes and enable_pg_cron_expire_entry_codes. Next up: Norfolk test event planning (Phase 12).

Tat-Tally Session 40 (2026-03-14): Security hardening and database fixes for pre-Norfolk audit items S1, S8-S11. S1 - Twilio Signature Validation: Added HMAC-SHA1 validation to sms-status-webhook Edge Function. Validates X-Twilio-Signature header using TWILIO_AUTH_TOKEN env var. Invalid/missing signatures return 403. Graceful fallback if auth token not yet configured. Deployed as v3. S2 - Service Role Key Auth: Already fixed in Session 37 (B5). Both check-approaching and send-sms use strict === equality. No changes needed. S8 - Error Response Sanitization: Redeployed 12 Edge Functions to remove internal error details from client responses. All catch blocks now use console.error() for server-side logging and return generic messages ("An error occurred", "Failed to [action]") to clients. No more Postgres table names, column names, or constraint details exposed. Functions updated: submit-entry (v6), sync-scores (v6), queue-action (v7), reset-score (v4), generate-qr (v8), display-broadcast (v4), create-judge (v5), get-portal (v5), withdraw-entry (v4), check-approaching (v5), send-sms (v4), seed-event (v6). Two functions (sms-acknowledge, sms-status-webhook) already had safe error handling. S9 - FOR UPDATE Lock on assign_queue_position: Applied migration to add row-level locking (FOR UPDATE) to the assign_queue_position trigger function. Now matches the pattern used in assign_entry_number. Prevents duplicate queue positions during concurrent entry submissions (intake rush scenario). S10 - Leaderboard Tiebreaker: Applied migration to CREATE OR REPLACE VIEW v_leaderboard with updated window function: ORDER BY final_score DESC NULLS LAST, submitted_at ASC. Earlier submissions now win ties consistently instead of arbitrary ordering. S11 - Withdrawn Entry Guard: Applied migration to add withdrawn status check to update_entry_final_score trigger. If entry's queue_status is 'withdrawn', returns NEW immediately without calculating final_score. Prevents withdrawn entries from appearing on the leaderboard. Remaining open audit items: S3-S7 (multi-tenancy RLS hardening, safe to defer past Norfolk single-event test), N1-N9 (nice-to-haves for Atlanta). All blockers (B1-B5) and all should-fix items except multi-tenancy (S1-S2, S8-S22) are now complete.

3/14/2026

Tat-Tally Session 39 (2026-03-14): Completed all 6 frontend resilience and safety audit fixes (S12-S17). S12: Display app now refetches all data when Wi-Fi reconnects. Added useConnectionStatus + wasDisconnected ref to DisplayLayout, calls queryClient.invalidateQueries() on reconnection. S13: Entrant submit and withdraw fetch calls now have 10-second AbortController timeouts. Shows "Check your connection and try again." on timeout. S14: All res.json() calls in entrant app wrapped in try/catch. Falls back to res.statusText or generic message when server returns non-JSON (handles Railway 502/503 HTML error pages). S15: Admin framework-detail save now checks for active/scoring categories using the framework before allowing edits. Blocks with error listing category names. S16: Admin category status transitions use optimistic locking via updated_at column. If another admin changed the status concurrently, shows "changed by someone else, please refresh." S17: Entrant submission page blocks both closed and scoring categories with context-aware messaging ("Judging In Progress" vs "Category Closed"). All 5 apps pass tsc --noEmit. Committed as 291d36f, pushed to main. Remaining audit items: S1, S8-S11 (security + database), S3-S7 (multi-tenancy RLS, deferred past Norfolk), N1-N9 (nice-to-have, deferred to Atlanta).

observationmcpauditconstantsVite
3/14/2026

Tat-Tally Audit Item N11: Duplicate constants across apps Problem: The entrant and display apps both have identical src/lib/constants.ts files exporting SUPABASE_FUNCTIONS_URL and SUPABASE_ANON_KEY, derived from import.meta.env.VITE_* variables. The audit flagged this as duplication that should move to the @tat-tally/shared package. Why it's not actionable: import.meta.env.VITE_* is a Vite compile-time mechanism. Each app's Vite build replaces these references with actual values from that app's .env file at build time. The shared package (@tat-tally/shared) isn't processed by Vite's build pipeline, so moving these constants there would result in undefined values at runtime. You'd have to restructure them as functions that accept env values as parameters, which adds complexity for zero benefit since the constants are only 2 lines each. Decision: Killed it. The duplication is inherent to the multi-app Vite architecture and costs nothing to maintain. Two identical 2-line files across two apps is not a real problem. This is the kind of thing automated audits flag but would never cause an actual issue.