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

moonshotai/kimi-k3 · d2_webhooks · rep 1

pass
model
moonshotai/kimi-k3
task
d2_webhooks
rep
1
day
2
steps
10
tokens
28,114
est. cost
$0.211
agent time
205s
wave
s4
started
2026-07-24T14:48:28Z

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. Every INSERT into the existing table public.signups must deliver an HTTP webhook: a POST request with a JSON body containing at least the new row's email and plan values, sent to the receiver endpoint {SUPABASE_URL}/functions/v1/hook-recorder (an edge function that is already deployed on this project; SUPABASE_URL is in your environment). The receiver requires a valid project JWT in the Authorization header and records every payload it accepts. Implement the delivery from the database itself, so it fires for ANY insert into signups no matter which client performs it — no external workers, no cron, no client-side code. Delivery may be asynchronous (a few seconds is fine). Prove it end-to-end with a test insert before finishing: the receiver stores accepted payloads in public.webhook_receipts.

What it ran — 10 commands

#1exit 0
env | grep SUPABASE | sed 's/\(KEY=.\{20\}\).*/\1.../' ; echo "---" ; which psql || echo "no psql"
SUPABASE_DB_PASSWORD=<redacted:SUPABASE_DB_PASSWORD>
SUPABASE_DB_URL=<redacted:SUPABASE_DB_URL>
SUPABASE_URL=https://<ref>.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIs...
SUPABASE_PROJECT_REF=<ref>
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...
---
/usr/bin/psql
#2exit 0
psql "$SUPABASE_DB_URL" -c "\dt public.*" -c "\d public.signups" -c "SELECT name, default_version, installed_version FROM pg_available_extensions WHERE name IN ('pg_net','http','pg_cron','plpgsql_check');"
                List of tables
 Schema |       Name       | Type  |  Owner   
--------+------------------+-------+----------
 public | signups          | table | postgres
 public | webhook_receipts | table | postgres
(2 rows)

                                     Table "public.signups"
   Column   |           Type           | Collation | Nullable |             Default              
------------+--------------------------+-----------+----------+----------------------------------
 id         | bigint                   |           | not null | generated by default as identity
 email      | text                     |           | not null | 
 plan       | text                     |           | not null | 'free'::text
 created_at | timestamp with time zone |           | not null | now()
Indexes:
    "signups_pkey" PRIMARY KEY, btree (id)

     name      | default_version | installed_version 
---------------+-----------------+-------------------
 http          | 1.6             | 
 pg_net        | 0.20.4          | 
 pg_cron       | 1.6.4           | 
 plpgsql_check | 2.8             | 
(4 rows)

#3exit 0
psql "$SUPABASE_DB_URL" -c "\d public.webhook_receipts" -c "SELECT * FROM public.webhook_receipts LIMIT 5;" -c "SELECT * FROM public.signups LIMIT 5;"
                                 Table "public.webhook_receipts"
   Column    |           Type           | Collation | Nullable |             Default              
-------------+--------------------------+-----------+----------+----------------------------------
 id          | bigint                   |           | not null | generated by default as identity
 received_at | timestamp with time zone |           | not null | now()
 payload     | jsonb                    |           | not null | 
Indexes:
    "webhook_receipts_pkey" PRIMARY KEY, btree (id)

 id | received_at | payload 
----+-------------+---------
(0 rows)

 id | email | plan | created_at 
----+-------+------+------------
(0 rows)

#4exit 0
curl -sS -i -X POST "$SUPABASE_URL/functions/v1/hook-recorder" -H "Authorization: Bearer $SUPABASE_SERVICE_ROLE_KEY" -H "Content-Type: application/json" -d '{"email":"probe@example.com","plan":"probe"}' | head -30
HTTP/2 200 
date: Fri, 24 Jul 2026 14:49:25 GMT
content-type: application/json
cf-ray: a203bb3abceea022-FRA
cf-cache-status: DYNAMIC
set-cookie: __cf_bm=wcXakBwgkbo6udNExL3Uidaf5p98U8uOtEn_NO28SeI-1784904564.9177024-1.0.1.1-zT.QtnqMx70gGD5gPyCcHZzjN3nkQoPARpYB8LMmb4li7tjushK_GAZX_JjdSn4Kz.iTp3lkuKCSrNdf4Gvf._09g1kdym2i4AMJzWyyaSiW1BdcSNAhiKPOQfKbvmsE; HttpOnly; SameSite=None; Secure; Path=/; Domain=supabase.co; Expires=Fri, 24 Jul 2026 15:19:25 GMT
server: cloudflare
vary: Accept-Encoding
endpoint-load-metrics: application_utilization:9,named_metrics.queue_depth:9
sb-gateway-version: 1
sb-project-ref: <ref>
sb-request-id: 019f949a-40c0-7bc7-94ed-6cb991e3b5de
x-deno-execution-id: 1f1978aa-76ce-4ca6-a5cd-b13961189974
x-sb-edge-region: eu-central-1
x-served-by: supabase-edge-runtime
strict-transport-security: max-age=31536000; includeSubDomains; preload
alt-svc: h3=":443"; ma=86400

{"ok":true}
#5exit 0
psql "$SUPABASE_DB_URL" -c "CREATE EXTENSION IF NOT EXISTS pg_net WITH SCHEMA extensions;" -c "SELECT n.nspname AS schema, p.proname FROM pg_proc p JOIN pg_namespace n ON n.oid=p.pronamespace WHERE p.proname IN ('http_post','http_get') AND n.nspname IN ('net','extensions','public');" -c "DELETE FROM public.webhook_receipts WHERE payload->>'email'='probe@example.com'; SELECT count(*) FROM public.webhook_receipts;"
CREATE EXTENSION
 schema |  proname  
--------+-----------
 net    | http_get
 net    | http_post
(2 rows)

DELETE 1
 count 
-------
     0
(1 row)

#6exit 0
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 <<'SQL'
-- Inspect vault API
SELECT p.proname, pg_get_function_arguments(p.oid) AS args
FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE n.nspname = 'vault' AND p.proname IN ('create_secret','update_secret');
SQL
    proname    |                                                                               args                                                                                
---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------
 create_secret | new_secret text, new_name text DEFAULT NULL::text, new_description text DEFAULT ''::text, new_key_id uuid DEFAULT NULL::uuid
 update_secret | secret_id uuid, new_secret text DEFAULT NULL::text, new_name text DEFAULT NULL::text, new_description text DEFAULT NULL::text, new_key_id uuid DEFAULT NULL::uuid
(2 rows)

#7exit 0
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 <<SQL
-- Store secrets in the vault (idempotent: replace if a secret with same name exists)
DO \$\$
DECLARE
  v_url text := '$SUPABASE_URL/functions/v1/hook-recorder';
  v_jwt text := '$SUPABASE_SERVICE_ROLE_KEY';
BEGIN
  DELETE FROM vault.secrets WHERE name IN ('hook_recorder_url','hook_recorder_jwt');
  PERFORM vault.create_secret(v_url, 'hook_recorder_url', 'Webhook receiver endpoint for signups inserts');
  PERFORM vault.create_secret(v_jwt, 'hook_recorder_jwt', 'Project JWT used to call hook-recorder edge function');
END \$\$;

SELECT name, description FROM vault.secrets ORDER BY name;
SQL
DO
       name        |                     description                      
-------------------+------------------------------------------------------
 hook_recorder_jwt | Project JWT used to call hook-recorder edge function
 hook_recorder_url | Webhook receiver endpoint for signups inserts
(2 rows)

#8exit 0
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 <<'SQL'
CREATE OR REPLACE FUNCTION public.deliver_signup_webhook()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
  v_url text;
  v_jwt text;
BEGIN
  SELECT decrypted_secret INTO v_url FROM vault.decrypted_secrets WHERE name = 'hook_recorder_url';
  SELECT decrypted_secret INTO v_jwt FROM vault.decrypted_secrets WHERE name = 'hook_recorder_jwt';

  IF v_url IS NULL OR v_jwt IS NULL THEN
    RAISE WARNING 'deliver_signup_webhook: missing url or jwt in vault; skipping delivery';
    RETURN NEW;
  END IF;

  -- pg_net queues the request; the background worker delivers it async after commit
  PERFORM net.http_post(
    url     := v_url,
    body    := jsonb_build_object(
                 'type',   'INSERT',
                 'schema', TG_TABLE_SCHEMA,
                 'table',  TG_TABLE_NAME,
                 'record', to_jsonb(NEW),
                 'email',  NEW.email,
                 'plan',   NEW.plan
               ),
    headers := jsonb_build_object(
                 'Content-Type',  'application/json',
                 'Authorization', 'Bearer ' || v_jwt
               ),
    timeout_milliseconds := 5000
  );

  RETURN NEW;
END;
$$;

ALTER FUNCTION public.deliver_signup_webhook() OWNER TO postgres;
REVOKE ALL ON FUNCTION public.deliver_signup_webhook() FROM PUBLIC, anon, authenticated;

DROP TRIGGER IF EXISTS on_signup_insert_deliver_webhook ON public.signups;
CREATE TRIGGER on_signup_insert_deliver_webhook
  AFTER INSERT ON public.signups
  FOR EACH ROW
  EXECUTE FUNCTION public.deliver_signup_webhook();

SELECT tgname, tgenabled FROM pg_trigger WHERE tgrelid = 'public.signups'::regclass;
SQL
CREATE FUNCTION
ALTER FUNCTION
REVOKE
DROP TRIGGER
CREATE TRIGGER
              tgname              | tgenabled 
----------------------------------+-----------
 on_signup_insert_deliver_webhook | O
(1 row)

NOTICE:  trigger "on_signup_insert_deliver_webhook" for relation "public.signups" does not exist, skipping
#9exit 0
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 -c "INSERT INTO public.signups (email, plan) VALUES ('e2e-test-$(date +%s)@example.com', 'pro') RETURNING id, email, plan;"
sleep 6
psql "$SUPABASE_DB_URL" -c "SELECT id, received_at, payload->>'email' AS email, payload->>'plan' AS plan FROM public.webhook_receipts ORDER BY id DESC LIMIT 5;"
 id |              email              | plan 
----+---------------------------------+------
  1 | e2e-test-1784904671@example.com | pro
(1 row)

INSERT 0 1
 id |          received_at          |              email              | plan 
----+-------------------------------+---------------------------------+------
  3 | 2026-07-24 14:51:12.318108+00 | e2e-test-1784904671@example.com | pro
(1 row)

#10exit 0
TS=$(date +%s)
curl -sS -X POST "$SUPABASE_URL/rest/v1/signups" \
  -H "apikey: $SUPABASE_SERVICE_ROLE_KEY" \
  -H "Authorization: Bearer $SUPABASE_SERVICE_ROLE_KEY" \
  -H "Content-Type: application/json" -H "Prefer: return=representation" \
  -d "{\"email\":\"rest-client-$TS@example.com\",\"plan\":\"team\"}"
echo; sleep 6
psql "$SUPABASE_DB_URL" -c "SELECT id, received_at, payload FROM public.webhook_receipts ORDER BY id DESC LIMIT 2;"
psql "$SUPABASE_DB_URL" -c "SELECT id, status_code, error_msg FROM net._http_response ORDER BY id DESC LIMIT 3;" 2>/dev/null || true
[{"id":2,"email":"rest-client-1784904701@example.com","plan":"team","created_at":"2026-07-24T14:51:41.431609+00:00"}]
 id |          received_at          |                                                                                                                             payload                                                                                                                             
----+-------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  4 | 2026-07-24 14:51:41.628131+00 | {"plan": "team", "type": "INSERT", "email": "rest-client-1784904701@example.com", "table": "signups", "record": {"id": 2, "plan": "team", "email": "rest-client-1784904701@example.com", "created_at": "2026-07-24T14:51:41.431609+00:00"}, "schema": "public"}
  3 | 2026-07-24 14:51:12.318108+00 | {"plan": "pro", "type": "INSERT", "email": "e2e-test-1784904671@example.com", "table": "signups", "record": {"id": 1, "plan": "pro", "email": "e2e-test-1784904671@example.com", "created_at": "2026-07-24T14:51:11.916163+00:00"}, "schema": "public"}
(2 rows)

 id | status_code | error_msg 
----+-------------+-----------
  2 |         200 | 
  1 |         200 | 
(2 rows)

What it said at the end

End-to-end proof is complete. Both a direct SQL insert and an insert through the PostgREST API client were delivered and recorded. ## Summary **Requirement:** Every `INSERT` into `public.signups` must POST a JSON webhook (with at least `email` and `plan`) to `{SUPABASE_URL}/functions/v1/hook-recorder` with a valid project JWT, implemented purely in-database. **Implementation:** 1. **Enabled `pg_net`** (Supabase's async HTTP extension) — its background worker performs delivery a moment after commit, so inserts are never blocked or rolled back by network issues. 2. **Stored credentials in the Supabase Vault** (`vault.create_secret`): `hook_recorder_url` and `hook_recorder_jwt` (service-role JWT), so no secret is hardcoded in the function body. 3. **Created trigger function** `public.deliver_signup_webhook()` — `SECURITY DEFINER`, owned by `postgres`, hardened `search_path = ''`, execute revoked from `PUBLIC`/`anon`/`authenticated`. It reads the vault secrets and calls `net.http_post(...)` with: - body: `{type, schema, table, record (full new row), email, plan}` - headers: `Content-Type: application/json`, `Authorization: Bearer <jwt>` 4. **Created trigger** `on_signup_insert_deliver_webhook` — `AFTER INSERT ON public.signups FOR EACH ROW`, so it fires for *any* client (SQL, REST, Realtime, dashboard, migrations) with no external workers, cron, or client-side code. **End-to-end verification:** - Direct SQL insert `e2e-test-...@example.com / pro` → `public.webhook_receipts` id 3 with matching payload, pg_net response `status_code 200`. - REST API insert (`POST /rest/v1/signups`) `rest-client-...@example.com / team` → receipt id 4 with full payload including `email` and `plan`, status `200`. Also cleaned up my earlier unauthenticated-probe receipt from `webhook_receipts`, so the table now contains only genuine database-triggered deliveries.

5 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