echo "SUPABASE_URL=$SUPABASE_URL"; echo "SUPABASE_PROJECT_REF=$SUPABASE_PROJECT_REF"; echo "SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY:0:20}..."; echo "SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY:0:20}..."; echo "SUPABASE_DB_URL=${SUPABASE_DB_URL:0:40}..."; echo "SUPABASE_DB_PASSWORD set: $([ -n "$SUPABASE_DB_PASSWORD" ] && echo yes || echo no)"; which psql; which curl; psql --version 2>/dev/null; curl --version 2>/dev/null | head -1SUPABASE_URL=https://<ref>.supabase.co SUPABASE_PROJECT_REF=<ref> SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs... SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIs... SUPABASE_DB_URL=postgresql://postgres.pgepczuaratdpqugop... SUPABASE_DB_PASSWORD set: yes /usr/bin/psql /usr/bin/curl psql (PostgreSQL) 18.4 (Debian 18.4-1.pgdg12+1) curl 7.88.1 (x86_64-pc-linux-gnu) libcurl/7.88.1 OpenSSL/3.0.20 zlib/1.2.13 brotli/1.0.9 zstd/1.5.4 libidn2/2.3.3 libpsl/0.21.2 (+libidn2/2.3.3) libssh2/1.10.0 nghttp2/1.52.0 librtmp/2.3 OpenLDAP/2.5.13
export PGPASSWORD="$SUPABASE_DB_PASSWORD" psql "$SUPABASE_DB_URL" -c "\d public.orgs" -c "\d public.org_members" -c "\d public.tickets" 2>&1 | head -60
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
export PGPASSWORD="$SUPABASE_DB_PASSWORD"
psql "$SUPABASE_DB_URL" -c "SELECT schemaname, tablename, policyname, cmd, qual, with_check FROM pg_policies WHERE schemaname='public' ORDER BY tablename, policyname;" 2>&1
echo "----- RLS enabled? -----"
psql "$SUPABASE_DB_URL" -c "SELECT c.relname, c.relrowsecurity AS rls_enabled FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='public' AND c.relname IN ('orgs','org_members','tickets');" 2>&1schemaname | tablename | policyname | cmd | qual | with_check ------------+-----------+------------+-----+------+------------ (0 rows) ----- RLS enabled? ----- relname | rls_enabled -------------+------------- org_members | f orgs | f tickets | f (3 rows)
export PGPASSWORD="$SUPABASE_DB_PASSWORD" psql "$SUPABASE_DB_URL" <<'SQL' 2>&1 SELECT id, name FROM public.orgs ORDER BY name; SELECT om.org_id, o.name AS org, om.user_id, u.email, om.role FROM public.org_members om JOIN public.orgs o ON o.id=om.org_id JOIN auth.users u ON u.id=om.user_id ORDER BY o.name, om.role DESC; SELECT org_id, count(*) FROM public.tickets GROUP BY org_id; SQL
id | name
--------------------------------------+--------
bfb4ef06-aa88-4677-83fb-61053173c6e9 | Acme
b8dc78fc-e29a-4f83-95c2-7417a1c272ee | Globex
(2 rows)
org_id | org | user_id | email | role
--------------------------------------+--------+--------------------------------------+-----------------------+--------
bfb4ef06-aa88-4677-83fb-61053173c6e9 | Acme | e17bb865-42fa-4542-97d3-261caa41e227 | vic-member@cari.dev | member
bfb4ef06-aa88-4677-83fb-61053173c6e9 | Acme | 3af1d02c-175f-45e1-be92-411e4777ad0e | uma-admin@cari.dev | admin
b8dc78fc-e29a-4f83-95c2-7417a1c272ee | Globex | e2f11f78-ff4b-4e43-b94d-55ebb9daa99f | wen-outsider@cari.dev | member
(3 rows)
org_id | count
--------------------------------------+-------
bfb4ef06-aa88-4677-83fb-61053173c6e9 | 3
b8dc78fc-e29a-4f83-95c2-7417a1c272ee | 2
(2 rows)
export PGPASSWORD="$SUPABASE_DB_PASSWORD"
psql "$SUPABASE_DB_URL" <<'SQL' 2>&1
-- Helper: is current user a member of org?
CREATE OR REPLACE FUNCTION public.user_is_member_of(p_org 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 AND om.user_id = auth.uid()
);
$$;
-- Helper: is current user an admin of org?
CREATE OR REPLACE FUNCTION public.user_is_admin_of(p_org 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 AND om.user_id = auth.uid() AND om.role = 'admin'
);
$$;
GRANT EXECUTE ON FUNCTION public.user_is_member_of(uuid) TO anon, authenticated;
GRANT EXECUTE ON FUNCTION public.user_is_admin_of(uuid) TO anon, authenticated;
-- ===== tickets =====
ALTER TABLE public.tickets ENABLE ROW LEVEL SECURITY;
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;
CREATE POLICY tickets_select ON public.tickets
FOR SELECT USING (public.user_is_member_of(org_id));
CREATE POLICY tickets_insert ON public.tickets
FOR INSERT WITH CHECK (public.user_is_admin_of(org_id));
CREATE POLICY tickets_update ON public.tickets
FOR UPDATE USING (public.user_is_admin_of(org_id))
WITH CHECK (public.user_is_admin_of(org_id));
CREATE POLICY tickets_delete ON public.tickets
FOR DELETE USING (public.user_is_admin_of(org_id));
-- ===== org_members =====
ALTER TABLE public.org_members ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS org_members_select ON public.org_members;
DROP POLICY IF EXISTS org_members_admin ON public.org_members;
CREATE POLICY org_members_select ON public.org_members
FOR SELECT USING (public.user_is_member_of(org_id));
CREATE POLICY org_members_admin ON public.org_members
FOR ALL USING (public.user_is_admin_of(org_id))
WITH CHECK (public.user_is_admin_of(org_id));
SQLCREATE FUNCTION CREATE FUNCTION GRANT GRANT ALTER TABLE NOTICE: policy "tickets_select" for relation "public.tickets" does not exist, skipping DROP POLICY NOTICE: policy "tickets_insert" for relation "public.tickets" does not exist, skipping DROP POLICY NOTICE: policy "tickets_update" for relation "public.tickets" does not exist, skipping DROP POLICY NOTICE: policy "tickets_delete" for relation "public.tickets" does not exist, skipping DROP POLICY CREATE POLICY CREATE POLICY CREATE POLICY CREATE POLICY ALTER TABLE NOTICE: policy "org_members_select" for relation "public.org_members" does not exist, skipping DROP POLICY NOTICE: policy "org_members_admin" for relation "public.org_members" does not exist, skipping DROP POLICY CREATE POLICY CREATE POLICY
cd /tmp
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\"}"
}
echo "UMA:"; login "uma-admin@cari.dev" "Passw0rd-uma-11" > uma.json; python3 -c "import json;d=json.load(open('uma.json'));print('access_token len',len(d.get('access_token',''))) if 'access_token' in d else print('ERR',d)"
echo "VIC:"; login "vic-member@cari.dev" "Passw0rd-vic-22" > vic.json; python3 -c "import json;d=json.load(open('vic.json'));print('access_token len',len(d.get('access_token',''))) if 'access_token' in d else print('ERR',d)"
echo "WEN:"; login "wen-outsider@cari.dev" "Passw0rd-wen-33" > wen.json; python3 -c "import json;d=json.load(open('wen.json'));print('access_token len',len(d.get('access_token',''))) if 'access_token' in d else print('ERR',d)"
echo "ANON token = anon key"
cat uma.json | python3 -c "import json,sys; d=json.load(sys.stdin); print('UMA uid', d['user']['id'])" 2>/dev/null
cat vic.json | python3 -c "import json,sys; d=json.load(sys.stdin); print('VIC uid', d['user']['id'])" 2>/dev/null
cat wen.json | python3 -c "import json,sys; d=json.load(sys.stdin); print('WEN uid', d['user']['id'])" 2>/dev/nullUMA: access_token len 796 VIC: access_token len 798 WEN: access_token len 800 ANON token = anon key UMA uid 3af1d02c-175f-45e1-be92-411e4777ad0e VIC uid e17bb865-42fa-4542-97d3-261caa41e227 WEN uid e2f11f78-ff4b-4e43-b94d-55ebb9daa99f
cd /tmp
cat > test.sh <<'SH'
#!/bin/bash
# $1 = token label, $2 = token
URL="$SUPABASE_URL/rest/v1"
H_AUTH="Authorization: Bearer $2"
H_API="apikey: $SUPABASE_ANON_KEY"
echo "=== TESTS FOR: $1 ==="
# tickets - SELECT all
echo -n "[tickets SELECT] count="; curl -s "$URL/tickets?select=id,org_id,title,status" -H "$H_AUTH" -H "$H_API" | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d))" 2>/dev/null || echo "ERR"
# org_members - SELECT all
echo -n "[org_members SELECT] count="; curl -s "$URL/org_members?select=org_id,user_id,role" -H "$H_AUTH" -H "$H_API" | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d))" 2>/dev/null || echo "ERR"
# orgs - SELECT all (should be readable)
echo -n "[orgs SELECT] count="; curl -s "$URL/orgs?select=id,name" -H "$H_AUTH" -H "$H_API" | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d))" 2>/dev/null || echo "ERR"
# tickets - INSERT into Acme (bfb4ef06...)
echo -n "[tickets INSERT Acme] "; curl -s -o /dev/null -w "%{http_code}" -X POST "$URL/tickets" -H "$H_AUTH" -H "$H_API" -H "Content-Type: application/json" -H "Prefer: return=minimal" -d '{"org_id":"bfb4ef06-aa88-4677-83fb-61053173c6e9","title":"RLS test ticket","status":"open"}'; echo
# tickets - INSERT into Globex (b8dc78fc...) (should be denied for Acme users)
echo -n "[tickets INSERT Globex] "; curl -s -o /dev/null -w "%{http_code}" -X POST "$URL/tickets" -H "$H_AUTH" -H "$H_API" -H "Content-Type: application/json" -H "Prefer: return=minimal" -d '{"org_id":"b8dc78fc-e29a-4f83-95c2-7417a1c272ee","title":"RLS test ticket globex","status":"open"}'; echo
# tickets - UPDATE (set status) on a known Acme ticket -> need an id; try with filter update
echo -n "[tickets UPDATE Acme] "; curl -s -o /dev/null -w "%{http_code}" -X PATCH "$URL/tickets?org_id=eq.bfb4ef06-aa88-4677-83fb-61053173c6e9" -H "$H_AUTH" -H "$H_API" -H "Content-Type: application/json" -H "Prefer: return=minimal" -d '{"status":"closed"}'; echo
# tickets - DELETE a Globex ticket via filter (should be denied for Acme users; 0 rows for unauth)
echo -n "[tickets DELETE Globex] "; curl -s -o /dev/null -w "%{http_code}" -X DELETE "$URL/tickets?org_id=eq.b8dc78fc-e29a-4f83-95c2-7417a1c272ee" -H "$H_AUTH" -H "$H_API" -H "Prefer: return=minimal"; echo
echo
SH
chmod +x test.sh
UMA=$(python3 -c "import json;print(json.load(open('uma.json'))['access_token'])")
VIC=$(python3 -c "import json;print(json.load(open('vic.json'))['access_token'])")
WEN=$(python3 -c "import json;print(json.load(open('wen.json'))['access_token'])")
bash test.sh "UMA (admin Acme)" "$UMA"
bash test.sh "VIC (member Acme)" "$VIC"
bash test.sh "WEN (member Globex)" "$WEN"
bash test.sh "ANON" "$SUPABASE_ANON_KEY"=== TESTS FOR: UMA (admin Acme) === [tickets SELECT] count=3 [org_members SELECT] count=2 [orgs SELECT] count=2 [tickets INSERT Acme] 201 [tickets INSERT Globex] 403 [tickets UPDATE Acme] 204 [tickets DELETE Globex] 204 === TESTS FOR: VIC (member Acme) === [tickets SELECT] count=4 [org_members SELECT] count=2 [orgs SELECT] count=2 [tickets INSERT Acme] 403 [tickets INSERT Globex] 403 [tickets UPDATE Acme] 204 [tickets DELETE Globex] 204 === TESTS FOR: WEN (member Globex) === [tickets SELECT] count=2 [org_members SELECT] count=1 [orgs SELECT] count=2 [tickets INSERT Acme] 403 [tickets INSERT Globex] 403 [tickets UPDATE Acme] 204 [tickets DELETE Globex] 204 === TESTS FOR: ANON === [tickets SELECT] count=0 [org_members SELECT] count=0 [orgs SELECT] count=2 [tickets INSERT Acme] 401 [tickets INSERT Globex] 401 [tickets UPDATE Acme] 204 [tickets DELETE Globex] 204
export PGPASSWORD="$SUPABASE_DB_PASSWORD" psql "$SUPABASE_DB_URL" <<'SQL' 2>&1 -- show any test tickets SELECT id, org_id, title, status FROM public.tickets WHERE title ILIKE '%RLS test%' OR status='closed'; SQL
id | org_id | title | status ----+--------------------------------------+-----------------+-------- 1 | bfb4ef06-aa88-4677-83fb-61053173c6e9 | Fix login | closed 2 | bfb4ef06-aa88-4677-83fb-61053173c6e9 | Update billing | closed 3 | bfb4ef06-aa88-4677-83fb-61053173c6e9 | Rotate keys | closed 6 | bfb4ef06-aa88-4677-83fb-61053173c6e9 | RLS test ticket | closed (4 rows)
export PGPASSWORD="$SUPABASE_DB_PASSWORD" psql "$SUPABASE_DB_URL" <<'SQL' 2>&1 BEGIN; -- remove the test-inserted ticket DELETE FROM public.tickets WHERE title='RLS test ticket'; -- restore the 3 original Acme tickets (seeded as 'open') UPDATE public.tickets SET status='open' WHERE org_id='bfb4ef06-aa88-4677-83fb-61053173c6e9'; COMMIT; -- verify SELECT o.name, count(*) FROM public.tickets t JOIN public.orgs o ON o.id=t.org_id GROUP BY o.name ORDER BY o.name; SELECT id, title, status FROM public.tickets WHERE org_id='bfb4ef06-aa88-4677-83fb-61053173c6e9' ORDER BY id; SELECT id, title, status FROM public.tickets WHERE org_id='b8dc78fc-e29a-4f83-95c2-7417a1c272ee' ORDER BY id; SQL
BEGIN DELETE 1 UPDATE 3 COMMIT name | count --------+------- Acme | 3 Globex | 2 (2 rows) id | title | status ----+----------------+-------- 1 | Fix login | open 2 | Update billing | open 3 | Rotate keys | open (3 rows) id | title | status ----+-------------+-------- 4 | Migrate DNS | open 5 | Renew cert | open (2 rows)
cd /tmp
UMA=$(python3 -c "import json;print(json.load(open('uma.json'))['access_token'])")
VIC=$(python3 -c "import json;print(json.load(open('vic.json'))['access_token'])")
WEN=$(python3 -c "import json;print(json.load(open('wen.json'))['access_token'])")
URL="$SUPABASE_URL/rest/v1"
AUTH(){ echo "Authorization: Bearer $1"; }
API="apikey: $SUPABASE_ANON_KEY"
echo ">> VIC (member Acme) tries UPDATE own-org ticket id=1 -> expect 403"
curl -s -o /dev/null -w "%{http_code}\n" -X PATCH "$URL/tickets?id=eq.1" -H "$(AUTH $VIC)" -H "$API" -H "Content-Type: application/json" -d '{"status":"closed"}'
echo ">> VIC (member Acme) tries DELETE own-org ticket id=1 -> expect 403"
curl -s -o /dev/null -w "%{http_code}\n" -X DELETE "$URL/tickets?id=eq.1" -H "$(AUTH $VIC)" -H "$API" -H "Prefer: return=minimal"
echo ">> WEN (member Globex) tries UPDATE own-org ticket id=4 -> expect 403"
curl -s -o /dev/null -w "%{http_code}\n" -X PATCH "$URL/tickets?id=eq.4" -H "$(AUTH $WEN)" -H "$API" -H "Content-Type: application/json" -d '{"status":"closed"}'
echo ">> UMA (admin Acme) UPDATE own-org ticket id=1 -> expect 204, then restore"
curl -s -o /dev/null -w "%{http_code}\n" -X PATCH "$URL/tickets?id=eq.1" -H "$(AUTH $UMA)" -H "$API" -H "Content-Type: application/json" -d '{"status":"closed"}'
psql "$SUPABASE_DB_URL" -X -c "UPDATE public.tickets SET status='open' WHERE id=1;" 2>&1 | tail -1
echo ">> UMA (admin) DELETE own-org ticket id=1 via filter -> expect 403 (must NOT delete; prove with check)"
curl -s -o /dev/null -w "%{http_code}\n" -X DELETE "$URL/tickets?id=eq.1" -H "$(AUTH $UMA)" -H "$API" -H "Prefer: return=minimal"
echo " row still exists?"; psql "$SUPABASE_DB_URL" -X -c "SELECT count(*) FROM public.tickets WHERE id=1;" 2>&1 | tail -2
echo ">> VIC (member Acme) tries to INSERT org_members into Acme -> expect 403 (only admin/all policy)"
curl -s -o /dev/null -w "%{http_code}\n" -X POST "$URL/org_members" -H "$(AUTH $VIC)" -H "$API" -H "Content-Type: application/json" -d '{"org_id":"bfb4ef06-aa88-4677-83fb-61053173c6e9","user_id":"00000000-0000-0000-0000-000000000000","role":"member"}'
echo ">> VIC reads Globex tickets (filter) -> expect 0"
curl -s "$URL/tickets?org_id=eq.b8dc78fc-e29a-4f83-95c2-7417a1c272ee&select=id" -H "$(AUTH $VIC)" -H "$API" | python3 -c "import json,sys;print('Globex visible to VIC:',len(json.load(sys.stdin)))"
echo ">> UMA reads Globex tickets (filter) -> expect 0"
curl -s "$URL/tickets?org_id=eq.b8dc78fc-e29a-4f83-95c2-7417a1c272ee&select=id" -H "$(AUTH $UMA)" -H "$API" | python3 -c "import json,sys;print('Globex visible to UMA:',len(json.load(sys.stdin)))">> VIC (member Acme) tries UPDATE own-org ticket id=1 -> expect 403 204 >> VIC (member Acme) tries DELETE own-org ticket id=1 -> expect 403 204 >> WEN (member Globex) tries UPDATE own-org ticket id=4 -> expect 403 204 >> UMA (admin Acme) UPDATE own-org ticket id=1 -> expect 204, then restore 204 UPDATE 1 >> UMA (admin) DELETE own-org ticket id=1 via filter -> expect 403 (must NOT delete; prove with check) 204 row still exists? (1 row) >> VIC (member Acme) tries to INSERT org_members into Acme -> expect 403 (only admin/all policy) 403 >> VIC reads Globex tickets (filter) -> expect 0 Globex visible to VIC: 0 >> UMA reads Globex tickets (filter) -> expect 0 Globex visible to UMA: 0
export PGPASSWORD="$SUPABASE_DB_PASSWORD" echo "Current tickets:" psql "$SUPABASE_DB_URL" -X -c "SELECT id, org_id, title, status FROM public.tickets ORDER BY id;" echo "max id:"; psql "$SUPABASE_DB_URL" -X -t -c "SELECT max(id) FROM public.tickets;"
Current tickets: id | org_id | title | status ----+--------------------------------------+----------------+-------- 2 | bfb4ef06-aa88-4677-83fb-61053173c6e9 | Update billing | open 3 | bfb4ef06-aa88-4677-83fb-61053173c6e9 | Rotate keys | open 4 | b8dc78fc-e29a-4f83-95c2-7417a1c272ee | Migrate DNS | open 5 | b8dc78fc-e29a-4f83-95c2-7417a1c272ee | Renew cert | open (4 rows) max id: 5
export PGPASSWORD="$SUPABASE_DB_PASSWORD"
psql "$SUPABASE_DB_URL" <<'SQL' 2>&1
-- restore the deleted ticket with its original id
INSERT INTO public.tickets (id, org_id, title, status)
VALUES (1, 'bfb4ef06-aa88-4677-83fb-61053173c6e9', 'Fix login', 'open');
-- ensure sequence stays ahead so future inserts don't collide
SELECT setval(pg_get_serial_sequence('public.tickets','id'), (SELECT max(id) FROM public.tickets));
SQL
echo "--- Final verification ---"
psql "$SUPABASE_DB_URL" -X -c "SELECT o.name, count(*) FROM public.tickets t JOIN public.orgs o ON o.id=t.org_id GROUP BY o.name ORDER BY o.name;"
psql "$SUPABASE_DB_URL" -X -c "SELECT id, title, status FROM public.tickets WHERE org_id='bfb4ef06-aa88-4677-83fb-61053173c6e9' ORDER BY id;"INSERT 0 1
setval
--------
5
(1 row)
--- Final verification ---
name | count
--------+-------
Acme | 3
Globex | 2
(2 rows)
id | title | status
----+----------------+--------
1 | Fix login | open
2 | Update billing | open
3 | Rotate keys | open
(3 rows)
cd /tmp
UMA=$(python3 -c "import json;print(json.load(open('uma.json'))['access_token'])")
VIC=$(python3 -c "import json;print(json.load(open('vic.json'))['access_token'])")
WEN=$(python3 -c "import json;print(json.load(open('wen.json'))['access_token'])")
URL="$SUPABASE_URL/rest/v1"
API="apikey: $SUPABASE_ANON_KEY"
cnt(){ curl -s "$1" -H "$2" -H "$API" | python3 -c "import json,sys;print(len(json.load(sys.stdin)))"; }
T(){ echo -n "$1: tickets="; cnt "$URL/tickets?select=id" "$2"; echo -n " org_members="; cnt "$URL/org_members?select=org_id" "$2"; echo -n " orgs="; cnt "$URL/orgs?select=id" "$2"; echo; }
echo "=== FINAL READ-ONLY ISOLATION CHECK ==="
T "UMA admin/Acme" "Authorization: Bearer $UMA"
T "VIC member/Acme" "Authorization: Bearer $VIC"
T "WEN member/Globex" "Authorization: Bearer $WEN"
T "ANON" "Authorization: Bearer $SUPABASE_ANON_KEY"
echo "Expected: UMA tickets=3 members=2 orgs=2; VIC tickets=3 members=2 orgs=2; WEN tickets=2 members=1 orgs=2; ANON tickets=0 members=0 orgs=2"=== FINAL READ-ONLY ISOLATION CHECK === UMA admin/Acme: tickets=3 org_members=2 orgs=2 VIC member/Acme: tickets=3 org_members=2 orgs=2 WEN member/Globex: tickets=2 org_members=1 orgs=2 ANON: tickets=0 org_members=0 orgs=2 Expected: UMA tickets=3 members=2 orgs=2; VIC tickets=3 members=2 orgs=2; WEN tickets=2 members=1 orgs=2; ANON tickets=0 members=0 orgs=2
cd /tmp && rm -f uma.json vic.json wen.json test.sh; echo "cleaned"
cleaned
13 earlier narration turn(s) are in the raw transcript.
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