Can Agents Run It? · evidence — Issue 1: Supabase

claude-sonnet-5 · d2_rls_tenant · rep 1

pass
model
claude-sonnet-5
task
d2_rls_tenant
rep
1
day
2
steps
14
tokens
85,932
est. cost
$0.516
agent time
76s
wave
s4
started
2026-07-24T05:01:16Z

The task as the agent received it

You have operator access to a hosted Supabase project. Credentials are in environment variables: SUPABASE_URL, SUPABASE_PROJECT_REF, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY, SUPABASE_DB_URL, SUPABASE_DB_PASSWORD. The project has a multi-tenant schema, already populated: public.orgs (id, name), public.org_members (org_id, user_id references auth.users, role with values 'admin' or 'member'), public.tickets (id, org_id, title, status). Enforce tenant isolation with row-level security, through the REST API with real user JWTs: - members of an org (any role) can READ that org's tickets; - only role='admin' members can INSERT/UPDATE/DELETE tickets of their org; - users see nothing from orgs they do not belong to; anonymous sees no tickets at all; - org_members rows must be visible ONLY to members of that same org (a member can see the member list of their own org, nothing of other orgs); anonymous sees none; - the orgs table itself may remain readable; do not break legitimate access for org members. Existing users for your own testing: uma-admin@cari.dev / Passw0rd-uma-11 (admin of Acme), vic-member@cari.dev / Passw0rd-vic-22 (member of Acme), wen-outsider@cari.dev / Passw0rd-wen-33 (member of Globex only). Acme has 3 tickets, Globex has 2. Do not modify the data.

What it ran — 14 commands

#1exit 0
env | grep -i supabase | sed 's/=.*KEY.*/=***REDACTED***/' 
SUPABASE_DB_PASSWORD=<redacted:SUPABASE_DB_PASSWORD>
SUPABASE_DB_URL=<redacted:SUPABASE_DB_URL>
SUPABASE_URL=https://<ref>.supabase.co
SUPABASE_SERVICE_ROLE_KEY=<redacted:SUPABASE_SERVICE_ROLE_KEY>
SUPABASE_PROJECT_REF=<ref>
SUPABASE_ANON_KEY=<redacted:SUPABASE_ANON_KEY>
#2exit 0
which psql curl jq 2>&1; echo "---"; psql --version 2>&1
/usr/bin/psql
/usr/bin/curl
/usr/bin/jq
---
psql (PostgreSQL) 18.4 (Debian 18.4-1.pgdg12+1)
#3exit 0
psql "$SUPABASE_DB_URL" -c "\d public.orgs" -c "\d public.org_members" -c "\d public.tickets"
                   Table "public.orgs"
 Column | Type | Collation | Nullable |      Default      
--------+------+-----------+----------+-------------------
 id     | uuid |           | not null | gen_random_uuid()
 name   | text |           | not null | 
Indexes:
    "orgs_pkey" PRIMARY KEY, btree (id)
    "orgs_name_key" UNIQUE CONSTRAINT, btree (name)
Referenced by:
    TABLE "org_members" CONSTRAINT "org_members_org_id_fkey" FOREIGN KEY (org_id) REFERENCES orgs(id) ON DELETE CASCADE
    TABLE "tickets" CONSTRAINT "tickets_org_id_fkey" FOREIGN KEY (org_id) REFERENCES orgs(id) ON DELETE CASCADE

           Table "public.org_members"
 Column  | Type | Collation | Nullable | Default 
---------+------+-----------+----------+---------
 org_id  | uuid |           | not null | 
 user_id | uuid |           | not null | 
 role    | text |           | not null | 
Indexes:
    "org_members_pkey" PRIMARY KEY, btree (org_id, user_id)
Check constraints:
    "org_members_role_check" CHECK (role = ANY (ARRAY['admin'::text, 'member'::text]))
Foreign-key constraints:
    "org_members_org_id_fkey" FOREIGN KEY (org_id) REFERENCES orgs(id) ON DELETE CASCADE
    "org_members_user_id_fkey" FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE

                          Table "public.tickets"
 Column |  Type  | Collation | Nullable |             Default              
--------+--------+-----------+----------+----------------------------------
 id     | bigint |           | not null | generated by default as identity
 org_id | uuid   |           | not null | 
 title  | text   |           | not null | 
 status | text   |           | not null | 'open'::text
Indexes:
    "tickets_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "tickets_org_id_fkey" FOREIGN KEY (org_id) REFERENCES orgs(id) ON DELETE CASCADE

#4exit 0
psql "$SUPABASE_DB_URL" -c "select relname, relrowsecurity, relforcerowsecurity from pg_class where relname in ('orgs','org_members','tickets');"
   relname   | relrowsecurity | relforcerowsecurity 
-------------+----------------+---------------------
 orgs        | f              | f
 org_members | f              | f
 tickets     | f              | f
(3 rows)

#5exit 0
psql "$SUPABASE_DB_URL" -c "select * from pg_policies where schemaname='public';"
psql "$SUPABASE_DB_URL" -c "select o.name, count(*) from tickets t join orgs o on o.id=t.org_id group by o.name;"
psql "$SUPABASE_DB_URL" -c "select o.name, om.role, u.email from org_members om join orgs o on o.id=om.org_id join auth.users u on u.id=om.user_id order by 1,2;"
 schemaname | tablename | policyname | permissive | roles | cmd | qual | with_check 
------------+-----------+------------+------------+-------+-----+------+------------
(0 rows)

  name  | count 
--------+-------
 Acme   |     3
 Globex |     2
(2 rows)

  name  |  role  |         email         
--------+--------+-----------------------
 Acme   | admin  | uma-admin@cari.dev
 Acme   | member | vic-member@cari.dev
 Globex | member | wen-outsider@cari.dev
(3 rows)

#6exit 0
cat <<'SQL' > /tmp/rls.sql
-- Helper functions (SECURITY DEFINER to avoid RLS recursion issues)
create or replace function public.is_org_member(p_org_id uuid)
returns boolean
language sql
security definer
set search_path = public
stable
as $$
  select exists (
    select 1 from public.org_members m
    where m.org_id = p_org_id
      and m.user_id = auth.uid()
  );
$$;

create or replace function public.is_org_admin(p_org_id uuid)
returns boolean
language sql
security definer
set search_path = public
stable
as $$
  select exists (
    select 1 from public.org_members m
    where m.org_id = p_org_id
      and m.user_id = auth.uid()
      and m.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;

-- Enable RLS
alter table public.orgs enable row level security;
alter table public.org_members enable row level security;
alter table public.tickets enable row level security;

alter table public.orgs force row level security;
alter table public.org_members force row level security;
alter table public.tickets force row level security;

-- Drop pre-existing policies if any (idempotency)
drop policy if exists orgs_select on public.orgs;
drop policy if exists org_members_select on public.org_members;
drop policy if exists org_members_insert on public.org_members;
drop policy if exists org_members_update on public.org_members;
drop policy if exists org_members_delete on public.org_members;
drop policy if exists tickets_select on public.tickets;
drop policy if exists tickets_insert on public.tickets;
drop policy if exists tickets_update on public.tickets;
drop policy if exists tickets_delete on public.tickets;

-- orgs: readable by any authenticated member of that org (keep it simple/open for members)
create policy orgs_select on public.orgs
  for select
  to authenticated
  using ( public.is_org_member(id) );

-- org_members: visible only to members of the same org; nothing for anon
create policy org_members_select on public.org_members
  for select
  to authenticated
  using ( public.is_org_member(org_id) );

-- (No insert/update/delete policies for org_members are requested; leave management to service role only)

-- tickets: any member can read
create policy tickets_select on public.tickets
  for select
  to authenticated
  using ( public.is_org_member(org_id) );

-- tickets: only admins can insert, must be for their own org
create policy tickets_insert on public.tickets
  for insert
  to authenticated
  with check ( public.is_org_admin(org_id) );

-- tickets: only admins can update, restrict to their own org rows both before and after
create policy tickets_update on public.tickets
  for update
  to authenticated
  using ( public.is_org_admin(org_id) )
  with check ( public.is_org_admin(org_id) );

-- tickets: only admins can delete
create policy tickets_delete on public.tickets
  for delete
  to authenticated
  using ( public.is_org_admin(org_id) );
SQL
psql "$SUPABASE_DB_URL" -f /tmp/rls.sql
CREATE FUNCTION
CREATE FUNCTION
REVOKE
REVOKE
GRANT
GRANT
ALTER TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE
DROP POLICY
DROP POLICY
DROP POLICY
DROP POLICY
DROP POLICY
DROP POLICY
DROP POLICY
DROP POLICY
DROP POLICY
CREATE POLICY
CREATE POLICY
CREATE POLICY
CREATE POLICY
CREATE POLICY
CREATE POLICY
psql:/tmp/rls.sql:46: NOTICE:  policy "orgs_select" for relation "public.orgs" does not exist, skipping
psql:/tmp/rls.sql:47: NOTICE:  policy "org_members_select" for relation "public.org_members" does not exist, skipping
psql:/tmp/rls.sql:48: NOTICE:  policy "org_members_insert" for relation "public.org_members" does not exist, skipping
psql:/tmp/rls.sql:49: NOTICE:  policy "org_members_update" for relation "public.org_members" does not exist, skipping
psql:/tmp/rls.sql:50: NOTICE:  policy "org_members_delete" for relation "public.org_members" does not exist, skipping
psql:/tmp/rls.sql:51: NOTICE:  policy "tickets_select" for relation "public.tickets" does not exist, skipping
psql:/tmp/rls.sql:52: NOTICE:  policy "tickets_insert" for relation "public.tickets" does not exist, skipping
psql:/tmp/rls.sql:53: NOTICE:  policy "tickets_update" for relation "public.tickets" does not exist, skipping
psql:/tmp/rls.sql:54: NOTICE:  policy "tickets_delete" for relation "public.tickets" does not exist, skipping
#7exit 0
psql "$SUPABASE_DB_URL" -c "select schemaname, tablename, policyname, cmd, roles from pg_policies where schemaname='public' order by tablename, cmd;"
 schemaname |  tablename  |     policyname     |  cmd   |      roles      
------------+-------------+--------------------+--------+-----------------
 public     | org_members | org_members_select | SELECT | {authenticated}
 public     | orgs        | orgs_select        | SELECT | {authenticated}
 public     | tickets     | tickets_delete     | DELETE | {authenticated}
 public     | tickets     | tickets_insert     | INSERT | {authenticated}
 public     | tickets     | tickets_select     | SELECT | {authenticated}
 public     | tickets     | tickets_update     | UPDATE | {authenticated}
(6 rows)

#8exit 0
set -e
login() {
  local email="$1" pass="$2"
  curl -s -X POST "$SUPABASE_URL/auth/v1/token?grant_type=password" \
    -H "apikey: $SUPABASE_ANON_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"email\":\"$email\",\"password\":\"$pass\"}"
}
UMA=$(login "uma-admin@cari.dev" "Passw0rd-uma-11")
VIC=$(login "vic-member@cari.dev" "Passw0rd-vic-22")
WEN=$(login "wen-outsider@cari.dev" "Passw0rd-wen-33")

echo "$UMA" | jq -r '.access_token' > /tmp/uma.jwt
echo "$VIC" | jq -r '.access_token' > /tmp/vic.jwt
echo "$WEN" | jq -r '.access_token' > /tmp/wen.jwt

echo "UMA token len: $(wc -c < /tmp/uma.jwt)"
echo "VIC token len: $(wc -c < /tmp/vic.jwt)"
echo "WEN token len: $(wc -c < /tmp/wen.jwt)"
UMA token len: 797
VIC token len: 799
WEN token len: 801
#9exit 0
UMA=$(cat /tmp/uma.jwt); VIC=$(cat /tmp/vic.jwt); WEN=$(cat /tmp/wen.jwt)

req() {
  local user_jwt="$1"; local method="$2"; local path="$3"; local body="$4"
  if [ -n "$body" ]; then
    curl -s -w "\nHTTP_STATUS:%{http_code}\n" -X "$method" "$SUPABASE_URL/rest/v1/$path" \
      -H "apikey: $SUPABASE_ANON_KEY" \
      -H "Authorization: Bearer $user_jwt" \
      -H "Content-Type: application/json" \
      -H "Prefer: return=representation" \
      -d "$body"
  else
    curl -s -w "\nHTTP_STATUS:%{http_code}\n" -X "$method" "$SUPABASE_URL/rest/v1/$path" \
      -H "apikey: $SUPABASE_ANON_KEY" \
      -H "Authorization: Bearer $user_jwt"
  fi
}

echo "===== 1. TICKETS SELECT as UMA (Acme admin) - expect 3 Acme tickets ====="
req "$UMA" GET "tickets?select=*"

echo "===== 2. TICKETS SELECT as VIC (Acme member) - expect 3 Acme tickets ====="
req "$VIC" GET "tickets?select=*"

echo "===== 3. TICKETS SELECT as WEN (Globex member) - expect 2 Globex tickets, no Acme ====="
req "$WEN" GET "tickets?select=*"

echo "===== 4. TICKETS SELECT anonymous - expect empty ====="
curl -s -w "\nHTTP_STATUS:%{http_code}\n" -X GET "$SUPABASE_URL/rest/v1/tickets?select=*" \
  -H "apikey: $SUPABASE_ANON_KEY"
===== 1. TICKETS SELECT as UMA (Acme admin) - expect 3 Acme tickets =====
[{"id":1,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","title":"Fix login","status":"open"}, 
 {"id":2,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","title":"Update billing","status":"open"}, 
 {"id":3,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","title":"Rotate keys","status":"open"}]
HTTP_STATUS:200
===== 2. TICKETS SELECT as VIC (Acme member) - expect 3 Acme tickets =====
[{"id":1,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","title":"Fix login","status":"open"}, 
 {"id":2,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","title":"Update billing","status":"open"}, 
 {"id":3,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","title":"Rotate keys","status":"open"}]
HTTP_STATUS:200
===== 3. TICKETS SELECT as WEN (Globex member) - expect 2 Globex tickets, no Acme =====
[{"id":4,"org_id":"143214d8-ebba-4465-842f-7bb5527e56bc","title":"Migrate DNS","status":"open"}, 
 {"id":5,"org_id":"143214d8-ebba-4465-842f-7bb5527e56bc","title":"Renew cert","status":"open"}]
HTTP_STATUS:200
===== 4. TICKETS SELECT anonymous - expect empty =====
[]
HTTP_STATUS:200
#10exit 0
UMA=$(cat /tmp/uma.jwt); VIC=$(cat /tmp/vic.jwt); WEN=$(cat /tmp/wen.jwt)
ACME_ORG="a966db61-54a6-4773-ba7f-d4a738d519dc"
GLOBEX_ORG="143214d8-ebba-4465-842f-7bb5527e56bc"

req() {
  local user_jwt="$1"; local method="$2"; local path="$3"; local body="$4"
  curl -s -w "\nHTTP_STATUS:%{http_code}\n" -X "$method" "$SUPABASE_URL/rest/v1/$path" \
    -H "apikey: $SUPABASE_ANON_KEY" \
    -H "Authorization: Bearer $user_jwt" \
    -H "Content-Type: application/json" \
    -H "Prefer: return=representation" \
    -d "$body"
}

echo "===== 5. INSERT as UMA (admin) into Acme - should succeed ====="
req "$UMA" POST "tickets" "{\"org_id\":\"$ACME_ORG\",\"title\":\"RLS test ticket by admin\",\"status\":\"open\"}"

echo "===== 6. INSERT as VIC (member, not admin) into Acme - should FAIL (RLS) ====="
req "$VIC" POST "tickets" "{\"org_id\":\"$ACME_ORG\",\"title\":\"RLS test ticket by member\",\"status\":\"open\"}"

echo "===== 7. INSERT as WEN (Globex member) into Acme org - should FAIL ====="
req "$WEN" POST "tickets" "{\"org_id\":\"$ACME_ORG\",\"title\":\"cross-org insert attempt\",\"status\":\"open\"}"
===== 5. INSERT as UMA (admin) into Acme - should succeed =====
[{"id":6,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","title":"RLS test ticket by admin","status":"open"}]
HTTP_STATUS:201
===== 6. INSERT as VIC (member, not admin) into Acme - should FAIL (RLS) =====
{"code":"42501","details":null,"hint":null,"message":"new row violates row-level security policy for table \"tickets\""}
HTTP_STATUS:403
===== 7. INSERT as WEN (Globex member) into Acme org - should FAIL =====
{"code":"42501","details":null,"hint":null,"message":"new row violates row-level security policy for table \"tickets\""}
HTTP_STATUS:403
#11exit 0
UMA=$(cat /tmp/uma.jwt); VIC=$(cat /tmp/vic.jwt); WEN=$(cat /tmp/wen.jwt)

req() {
  local user_jwt="$1"; local method="$2"; local path="$3"; local body="$4"
  if [ -n "$body" ]; then
    curl -s -w "\nHTTP_STATUS:%{http_code}\n" -X "$method" "$SUPABASE_URL/rest/v1/$path" \
      -H "apikey: $SUPABASE_ANON_KEY" \
      -H "Authorization: Bearer $user_jwt" \
      -H "Content-Type: application/json" \
      -H "Prefer: return=representation" \
      -d "$body"
  else
    curl -s -w "\nHTTP_STATUS:%{http_code}\n" -X "$method" "$SUPABASE_URL/rest/v1/$path" \
      -H "apikey: $SUPABASE_ANON_KEY" \
      -H "Authorization: Bearer $user_jwt" \
      -H "Prefer: return=representation"
  fi
}

echo "===== 8. UPDATE as VIC (member) on ticket id=6 - should FAIL / affect 0 rows ====="
req "$VIC" PATCH "tickets?id=eq.6" '{"status":"closed"}'

echo "===== 9. UPDATE as WEN (outsider) on ticket id=6 (Acme) - should FAIL / 0 rows ====="
req "$WEN" PATCH "tickets?id=eq.6" '{"status":"closed"}'

echo "===== 10. UPDATE as UMA (admin) on ticket id=6 - should succeed ====="
req "$UMA" PATCH "tickets?id=eq.6" '{"status":"closed"}'

echo "===== 11. DELETE as VIC (member) on ticket id=6 - should FAIL / 0 rows ====="
req "$VIC" DELETE "tickets?id=eq.6"

echo "===== 12. DELETE as UMA (admin) on ticket id=6 - should succeed (cleanup) ====="
req "$UMA" DELETE "tickets?id=eq.6"

echo "===== 13. Confirm ticket count back to original (Acme=3, Globex=2) ====="
req "$UMA" GET "tickets?select=id,org_id"
===== 8. UPDATE as VIC (member) on ticket id=6 - should FAIL / affect 0 rows =====
[]
HTTP_STATUS:200
===== 9. UPDATE as WEN (outsider) on ticket id=6 (Acme) - should FAIL / 0 rows =====
[]
HTTP_STATUS:200
===== 10. UPDATE as UMA (admin) on ticket id=6 - should succeed =====
[{"id":6,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","title":"RLS test ticket by admin","status":"closed"}]
HTTP_STATUS:200
===== 11. DELETE as VIC (member) on ticket id=6 - should FAIL / 0 rows =====
[]
HTTP_STATUS:200
===== 12. DELETE as UMA (admin) on ticket id=6 - should succeed (cleanup) =====
[{"id":6,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","title":"RLS test ticket by admin","status":"closed"}]
HTTP_STATUS:200
===== 13. Confirm ticket count back to original (Acme=3, Globex=2) =====
[{"id":1,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc"}, 
 {"id":2,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc"}, 
 {"id":3,"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc"}]
HTTP_STATUS:200
#12exit 0
psql "$SUPABASE_DB_URL" -c "select o.name, t.id, t.title, t.status from tickets t join orgs o on o.id=t.org_id order by o.name, t.id;"
  name  | id |     title      | status 
--------+----+----------------+--------
 Acme   |  1 | Fix login      | open
 Acme   |  2 | Update billing | open
 Acme   |  3 | Rotate keys    | open
 Globex |  4 | Migrate DNS    | open
 Globex |  5 | Renew cert     | open
(5 rows)

#13exit 0
UMA=$(cat /tmp/uma.jwt); VIC=$(cat /tmp/vic.jwt); WEN=$(cat /tmp/wen.jwt)

req() {
  local user_jwt="$1"; local method="$2"; local path="$3"
  curl -s -w "\nHTTP_STATUS:%{http_code}\n" -X "$method" "$SUPABASE_URL/rest/v1/$path" \
    -H "apikey: $SUPABASE_ANON_KEY" \
    -H "Authorization: Bearer $user_jwt"
}

echo "===== 14. org_members SELECT as UMA (Acme admin) - expect only Acme members (uma, vic) ====="
req "$UMA" GET "org_members?select=*"

echo "===== 15. org_members SELECT as VIC (Acme member) - expect only Acme members ====="
req "$VIC" GET "org_members?select=*"

echo "===== 16. org_members SELECT as WEN (Globex member) - expect only Globex members, no Acme ====="
req "$WEN" GET "org_members?select=*"

echo "===== 17. org_members SELECT anonymous - expect empty ====="
curl -s -w "\nHTTP_STATUS:%{http_code}\n" -X GET "$SUPABASE_URL/rest/v1/org_members?select=*" \
  -H "apikey: $SUPABASE_ANON_KEY"
===== 14. org_members SELECT as UMA (Acme admin) - expect only Acme members (uma, vic) =====
[{"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","user_id":"ac31469c-2781-46d3-a864-7066418d5708","role":"admin"}, 
 {"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","user_id":"cdb4e96e-7bc5-4721-a6b3-0f67e6075e6d","role":"member"}]
HTTP_STATUS:200
===== 15. org_members SELECT as VIC (Acme member) - expect only Acme members =====
[{"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","user_id":"ac31469c-2781-46d3-a864-7066418d5708","role":"admin"}, 
 {"org_id":"a966db61-54a6-4773-ba7f-d4a738d519dc","user_id":"cdb4e96e-7bc5-4721-a6b3-0f67e6075e6d","role":"member"}]
HTTP_STATUS:200
===== 16. org_members SELECT as WEN (Globex member) - expect only Globex members, no Acme =====
[{"org_id":"143214d8-ebba-4465-842f-7bb5527e56bc","user_id":"f5ace662-c1c5-4af1-8000-33a7d04c97f2","role":"member"}]
HTTP_STATUS:200
===== 17. org_members SELECT anonymous - expect empty =====
[]
HTTP_STATUS:200
#14exit 0
UMA=$(cat /tmp/uma.jwt); WEN=$(cat /tmp/wen.jwt)

req() {
  local user_jwt="$1"; local method="$2"; local path="$3"
  curl -s -w "\nHTTP_STATUS:%{http_code}\n" -X "$method" "$SUPABASE_URL/rest/v1/$path" \
    -H "apikey: $SUPABASE_ANON_KEY" \
    -H "Authorization: Bearer $user_jwt"
}

echo "===== 18. orgs SELECT as UMA (Acme) - expect only Acme ====="
req "$UMA" GET "orgs?select=*"

echo "===== 19. orgs SELECT as WEN (Globex) - expect only Globex ====="
req "$WEN" GET "orgs?select=*"

echo "===== 20. orgs SELECT anonymous - expect empty (since policy requires authenticated) ====="
curl -s -w "\nHTTP_STATUS:%{http_code}\n" -X GET "$SUPABASE_URL/rest/v1/orgs?select=*" \
  -H "apikey: $SUPABASE_ANON_KEY"
===== 18. orgs SELECT as UMA (Acme) - expect only Acme =====
[{"id":"a966db61-54a6-4773-ba7f-d4a738d519dc","name":"Acme"}]
HTTP_STATUS:200
===== 19. orgs SELECT as WEN (Globex) - expect only Globex =====
[{"id":"143214d8-ebba-4465-842f-7bb5527e56bc","name":"Globex"}]
HTTP_STATUS:200
===== 20. orgs SELECT anonymous - expect empty (since policy requires authenticated) =====
[]
HTTP_STATUS:200

What it said at the end

org_members isolation works perfectly. Now let's test the `orgs` table visibility (member sees own org, not others; anonymous handling).

11 earlier narration turn(s) are in the raw transcript.

How it was graded

A shell script executed against the live project and asserted on the state the agent left behind. No model judged another model.

exit 0 OK

Check it yourself

Raw transcript · Task definition and verifier · Every attempt