cat > /tmp/provision_supabase_users.py <<'PY'
import json, os, sys, urllib.request, urllib.error
base = os.environ['SUPABASE_URL'].rstrip('/')
service = os.environ['SUPABASE_SERVICE_ROLE_KEY']
anon = os.environ['SUPABASE_ANON_KEY']
users = [
('dana@cari.dev', 'Passw0rd-dana-91'),
('omar@cari.dev', 'Passw0rd-omar-17'),
]
def request(method, path, key, payload=None):
data = None if payload is None else json.dumps(payload).encode()
req = urllib.request.Request(base + path, data=data, method=method)
req.add_header('apikey', key)
req.add_header('Authorization', 'Bearer ' + key)
if data is not None:
req.add_header('Content-Type', 'application/json')
try:
with urllib.request.urlopen(req, timeout=30) as r:
body = r.read()
return r.status, json.loads(body) if body else {}
except urllib.error.HTTPError as e:
body = e.read()
try: parsed = json.loads(body) if body else {}
except Exception: parsed = {'raw': body.decode(errors='replace')}
return e.code, parsed
# Load users once, paginating, so reruns can reconcile existing accounts.
def all_auth_users():
found=[]
page=1
while True:
status, data = request('GET', f'/auth/v1/admin/users?page={page}&per_page=1000', service)
if status != 200:
raise RuntimeError(f'Cannot list auth users: HTTP {status}: {data}')
batch = data.get('users', []) if isinstance(data, dict) else []
found.extend(batch)
if len(batch) < 1000: break
page += 1
return found
existing = {u.get('email','').lower(): u for u in all_auth_users()}
for email, password in users:
old = existing.get(email.lower())
if old:
# Admin update sets password immediately and marks email confirmed.
status, data = request('PUT', f"/auth/v1/admin/users/{old['id']}", service,
{'password': password, 'email_confirm': True})
action = 'updated'
else:
status, data = request('POST', '/auth/v1/admin/users', service,
{'email': email, 'password': password, 'email_confirm': True})
action = 'created'
if status not in (200, 201):
raise RuntimeError(f'Failed to provision {email}: HTTP {status}: {data}')
print(f'{email}: {action} and confirmed')
# Prove password grant produces a real session for each user, without printing secrets.
failed = False
for email, password in users:
status, data = request('POST', '/auth/v1/token?grant_type=password', anon,
{'email': email, 'password': password})
valid = (status == 200 and isinstance(data, dict) and
bool(data.get('access_token')) and bool(data.get('refresh_token')) and
data.get('user', {}).get('email', '').lower() == email.lower())
if valid:
print(f'{email}: password sign-in verified (HTTP 200, session/access token returned)')
else:
print(f'{email}: sign-in verification FAILED (HTTP {status}): {data}', file=sys.stderr)
failed = True
if failed:
sys.exit(1)
PY
python3 /tmp/provision_supabase_users.py
rc=$?
rm -f /tmp/provision_supabase_users.py
exit $rcdana@cari.dev: created and confirmed omar@cari.dev: created and confirmed dana@cari.dev: password sign-in verified (HTTP 200, session/access token returned) omar@cari.dev: password sign-in verified (HTTP 200, session/access token returned)
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