printf 'DB URL set: '; [ -n "$SUPABASE_DB_URL" ] && echo yes || echo no; printf 'URL set: '; [ -n "$SUPABASE_URL" ] && echo yes || echo no; command -v psql || true
DB URL set: yes URL set: yes /usr/bin/psql
env | grep '^SUPABASE_' | sed -E 's/=.*/=<set>/'
SUPABASE_DB_PASSWORD=<set> SUPABASE_DB_URL=<set> SUPABASE_URL=<set> SUPABASE_SERVICE_ROLE_KEY=<set> SUPABASE_PROJECT_REF=<set> SUPABASE_ANON_KEY=<set>
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 -P pager=off -c "select schemaname, tablename, rowsecurity, force_row_security from pg_tables where schemaname='public' and tablename in ('orgs','org_members','tickets'); select schemaname, tablename, policyname, permissive, roles, cmd, qual, with_check from pg_policies where schemaname='public' and tablename in ('orgs','org_members','tickets') order by tablename,policyname;"ERROR: column "force_row_security" does not exist
LINE 1: select schemaname, tablename, rowsecurity, force_row_securit...
^
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 -P pager=off <<'SQL'
select schemaname, tablename, rowsecurity, (select relforcerowsecurity from pg_class c join pg_namespace n on n.oid=c.relnamespace where n.nspname=t.schemaname and c.relname=t.tablename) as force_rls from pg_tables t where schemaname='public' and tablename in ('orgs','org_members','tickets');
select schemaname, tablename, policyname, permissive, roles, cmd, qual, with_check from pg_policies where schemaname='public' and tablename in ('orgs','org_members','tickets') order by tablename,policyname;
SQLschemaname | tablename | rowsecurity | force_rls ------------+-------------+-------------+----------- public | org_members | f | f public | orgs | f | f public | tickets | f | f (3 rows) schemaname | tablename | policyname | permissive | roles | cmd | qual | with_check ------------+-----------+------------+------------+-------+-----+------+------------ (0 rows)
psql "$SUPABASE_DB_URL" -P pager=off -c "select table_name,column_name,data_type,udt_name from information_schema.columns where table_schema='public' and table_name in ('orgs','org_members','tickets') order by table_name,ordinal_position;"table_name | column_name | data_type | udt_name -------------+-------------+-----------+---------- org_members | org_id | uuid | uuid org_members | user_id | uuid | uuid org_members | role | text | text orgs | id | uuid | uuid orgs | name | text | text tickets | id | bigint | int8 tickets | org_id | uuid | uuid tickets | title | text | text tickets | status | text | text (9 rows)
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 <<'SQL'
begin;
create or replace function public.is_org_member(p_org_id uuid)
returns boolean
language sql
stable
security definer
set search_path = public
as $$
select exists (
select 1
from public.org_members om
where om.org_id = p_org_id
and om.user_id = auth.uid()
);
$$;
create or replace function public.is_org_admin(p_org_id uuid)
returns boolean
language sql
stable
security definer
set search_path = public
as $$
select exists (
select 1
from public.org_members om
where om.org_id = p_org_id
and om.user_id = auth.uid()
and om.role = 'admin'
);
$$;
revoke all on function public.is_org_member(uuid) from public;
revoke all on function public.is_org_admin(uuid) from public;
grant execute on function public.is_org_member(uuid) to anon, authenticated;
grant execute on function public.is_org_admin(uuid) to anon, authenticated;
alter table public.tickets enable row level security;
alter table public.org_members enable row level security;
drop policy if exists tickets_member_select on public.tickets;
drop policy if exists tickets_admin_insert on public.tickets;
drop policy if exists tickets_admin_update on public.tickets;
drop policy if exists tickets_admin_delete on public.tickets;
drop policy if exists org_members_same_org_select on public.org_members;
create policy tickets_member_select on public.tickets
for select to anon, authenticated
using (public.is_org_member(org_id));
create policy tickets_admin_insert on public.tickets
for insert to authenticated
with check (public.is_org_admin(org_id));
create policy tickets_admin_update on public.tickets
for update to authenticated
using (public.is_org_admin(org_id))
with check (public.is_org_admin(org_id));
create policy tickets_admin_delete on public.tickets
for delete to authenticated
using (public.is_org_admin(org_id));
create policy org_members_same_org_select on public.org_members
for select to anon, authenticated
using (public.is_org_member(org_id));
commit;
SQLBEGIN CREATE FUNCTION CREATE FUNCTION REVOKE REVOKE GRANT GRANT ALTER TABLE ALTER TABLE DROP POLICY DROP POLICY DROP POLICY DROP POLICY DROP POLICY CREATE POLICY CREATE POLICY CREATE POLICY CREATE POLICY CREATE POLICY COMMIT
NOTICE: policy "tickets_member_select" for relation "public.tickets" does not exist, skipping NOTICE: policy "tickets_admin_insert" for relation "public.tickets" does not exist, skipping NOTICE: policy "tickets_admin_update" for relation "public.tickets" does not exist, skipping NOTICE: policy "tickets_admin_delete" for relation "public.tickets" does not exist, skipping NOTICE: policy "org_members_same_org_select" for relation "public.org_members" does not exist, skipping
set -e
base="$SUPABASE_URL"; key="$SUPABASE_ANON_KEY"
login(){ curl -sS "$base/auth/v1/token?grant_type=password" -H "apikey: $key" -H 'Content-Type: application/json' --data "{\"email\":\"$1\",\"password\":\"$2\"}"; }
for spec in 'uma-admin@cari.dev Passw0rd-uma-11' 'vic-member@cari.dev Passw0rd-vic-22' 'wen-outsider@cari.dev Passw0rd-wen-33'; do set -- $spec; echo "$1"; login "$1" "$2" | jq -r '.access_token' | wc -c; doneuma-admin@cari.dev 797 vic-member@cari.dev 799 wen-outsider@cari.dev 801
set -e
base="$SUPABASE_URL"; key="$SUPABASE_ANON_KEY"; api="$base/rest/v1"
gettok(){ curl -sS "$base/auth/v1/token?grant_type=password" -H "apikey: $key" -H 'Content-Type: application/json' --data "{\"email\":\"$1\",\"password\":\"$2\"}" | jq -r .access_token; }
uma=$(gettok uma-admin@cari.dev Passw0rd-uma-11); vic=$(gettok vic-member@cari.dev Passw0rd-vic-22); wen=$(gettok wen-outsider@cari.dev Passw0rd-wen-33)
for who in anon uma vic wen; do eval "tok=\${$who:-}"; echo "=== $who tickets"; curl -sS "$api/tickets?select=id,org_id,title,status&order=id" -H "apikey: $key" ${tok:+-H "Authorization: Bearer $tok"}; echo; echo "=== $who members"; curl -sS "$api/org_members?select=org_id,user_id,role&order=org_id,user_id" -H "apikey: $key" ${tok:+-H "Authorization: Bearer $tok"}; echo; done=== anon tickets
[]
=== anon members
[]
=== uma tickets
[{"id":1,"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","title":"Fix login","status":"open"},
{"id":2,"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","title":"Update billing","status":"open"},
{"id":3,"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","title":"Rotate keys","status":"open"}]
=== uma members
[{"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","user_id":"c4cd636d-dddf-4ad4-b494-123c81bb15a6","role":"member"},
{"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","user_id":"d3ef8a08-a1e6-4b55-bae7-0653dc48d853","role":"admin"}]
=== vic tickets
[{"id":1,"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","title":"Fix login","status":"open"},
{"id":2,"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","title":"Update billing","status":"open"},
{"id":3,"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","title":"Rotate keys","status":"open"}]
=== vic members
[{"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","user_id":"c4cd636d-dddf-4ad4-b494-123c81bb15a6","role":"member"},
{"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","user_id":"d3ef8a08-a1e6-4b55-bae7-0653dc48d853","role":"admin"}]
=== wen tickets
[{"id":4,"org_id":"b7a380b9-3446-4852-82ed-8cc3ecf77025","title":"Migrate DNS","status":"open"},
{"id":5,"org_id":"b7a380b9-3446-4852-82ed-8cc3ecf77025","title":"Renew cert","status":"open"}]
=== wen members
[{"org_id":"b7a380b9-3446-4852-82ed-8cc3ecf77025","user_id":"6fd3e5de-c15e-4e27-841e-b662f28e9fb7","role":"member"}]
set -e
base="$SUPABASE_URL"; key="$SUPABASE_ANON_KEY"; api="$base/rest/v1"; tok=$(curl -sS "$base/auth/v1/token?grant_type=password" -H "apikey: $key" -H 'Content-Type: application/json' --data '{"email":"vic-member@cari.dev","password":"Passw0rd-vic-22"}' | jq -r .access_token)
for method in POST PATCH DELETE; do
if [ "$method" = POST ]; then url="$api/tickets"; data='{"org_id":"ac445b49-5d60-43f0-98b8-370017b2f28a","title":"rls-test","status":"open"}'; else url="$api/tickets?id=eq.1"; data='{"title":"rls-test"}'; fi
echo -n "$method: "; curl -sS -o /tmp/body -w '%{http_code}' -X "$method" "$url" -H "apikey: $key" -H "Authorization: Bearer $tok" -H 'Content-Type: application/json' -H 'Prefer: return=minimal' --data "$data"; echo " $(cat /tmp/body)"
donePOST: 403 {"code":"42501","details":null,"hint":null,"message":"new row violates row-level security policy for table \"tickets\""}
PATCH: 204
DELETE: 204
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 -c "insert into public.tickets (id, org_id, title, status) values (1, 'ac445b49-5d60-43f0-98b8-370017b2f28a', 'Fix login', 'open');" && psql "$SUPABASE_DB_URL" -P pager=off -c "select id,org_id,title,status from public.tickets order by id;"
ERROR: duplicate key value violates unique constraint "tickets_pkey" DETAIL: Key (id)=(1) already exists.
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 <<'SQL' insert into public.tickets (id, org_id, title, status) values (1, 'ac445b49-5d60-43f0-98b8-370017b2f28a', 'Fix login', 'open'); SQL # verify REST state and admin write test only with rollback impossible via REST; avoid writes curl -sS "$SUPABASE_URL/rest/v1/tickets?select=id,org_id,title,status&order=id" -H "apikey: $SUPABASE_ANON_KEY"
[]
ERROR: duplicate key value violates unique constraint "tickets_pkey" DETAIL: Key (id)=(1) already exists.
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 -c "select id,org_id,title,status from public.tickets order by id;"
id | org_id | title | status ----+--------------------------------------+----------------+-------- 1 | ac445b49-5d60-43f0-98b8-370017b2f28a | Fix login | open 2 | ac445b49-5d60-43f0-98b8-370017b2f28a | Update billing | open 3 | ac445b49-5d60-43f0-98b8-370017b2f28a | Rotate keys | open 4 | b7a380b9-3446-4852-82ed-8cc3ecf77025 | Migrate DNS | open 5 | b7a380b9-3446-4852-82ed-8cc3ecf77025 | Renew cert | open (5 rows)
A shell script executed against the live project and asserted on the state the agent left behind. No model judged another model.
Raw transcript · Task definition and verifier · Every attempt