#!/usr/bin/env bash # RLS isolation audit — manual curl edition. # # Mirrors `packages/test-utils/tests/rls-audit.test.ts` (the Vitest version is # authoritative) but hits the stack via Kong using a real anon key + an # Eva-signed JWT, which is what a misconfigured RLS policy would actually # leak data to. Useful as a post-deploy sanity check where Vitest isn't # available. # # Exit non-zero if any endpoint returns rows to Eva (who is NOT a member of # the seed collective). set -euo pipefail ROOT="$(cd "$(dirname "$0")/../.." && pwd)" cd "$ROOT" source .env KONG="${PUBLIC_SUPABASE_URL:-http://localhost:8001}" ANON="$PUBLIC_SUPABASE_ANON_KEY" SECRET="$SUPABASE_JWT_SECRET" EVA_ID='55555555-5555-5555-5555-555555555555' sign_eva() { local header='{"alg":"HS256","typ":"JWT"}' local exp=$(( $(date +%s) + 3600 )) local payload="{\"sub\":\"$EVA_ID\",\"role\":\"authenticated\",\"aud\":\"authenticated\",\"iss\":\"supabase-demo\",\"exp\":$exp}" local b64h b64p b64h=$(printf '%s' "$header" | openssl base64 -e -A | tr '+/' '-_' | tr -d '=') b64p=$(printf '%s' "$payload" | openssl base64 -e -A | tr '+/' '-_' | tr -d '=') local sig sig=$(printf '%s.%s' "$b64h" "$b64p" \ | openssl dgst -sha256 -hmac "$SECRET" -binary \ | openssl base64 -e -A \ | tr '+/' '-_' | tr -d '=') printf '%s.%s.%s' "$b64h" "$b64p" "$sig" } TOKEN=$(sign_eva) HDRS=(-H "apikey: $ANON" -H "Authorization: Bearer $TOKEN") check() { local label="$1"; local url="$2" local body body=$(curl -s -m 5 "${HDRS[@]}" "$KONG$url") if [ "$body" = "[]" ]; then printf ' ok %-35s %s\n' "$label" "[]" else printf ' FAIL %-35s %s\n' "$label" "$body" return 1 fi } echo "RLS audit — Eva (non-member) should see [] everywhere:" fail=0 check 'collectives' '/rest/v1/collectives?select=id' || fail=1 check 'shopping_lists' '/rest/v1/shopping_lists?select=id' || fail=1 check 'shopping_items' '/rest/v1/shopping_items?select=id' || fail=1 check 'task_lists' '/rest/v1/task_lists?select=id' || fail=1 check 'tasks' '/rest/v1/tasks?select=id' || fail=1 check 'notes' '/rest/v1/notes?select=id' || fail=1 check 'collective_members' '/rest/v1/collective_members?select=user_id&user_id=neq.'"$EVA_ID" || fail=1 check 'collective_invitations' '/rest/v1/collective_invitations?select=id' || fail=1 if [ "$fail" -eq 0 ]; then echo echo "RLS audit passed." else echo echo "RLS audit FAILED — one or more tables returned data to a non-member." exit 1 fi