Skip to content

Commit cf2d9af

Browse files
committed
fix hosted chat webhook url
1 parent 54827fe commit cf2d9af

2 files changed

Lines changed: 78 additions & 1 deletion

File tree

docs/supabase-data-architecture.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,17 @@ The current helper functions refresh read-model rows, enforce chat message/threa
161161

162162
Chat message email notifications are sent through the `send-email-for-new-chat-message` Edge Function. That function is invoked by a database trigger, not by browser clients, so it has `verify_jwt = false` and performs its own shared-secret check with `PEELS_CHAT_MESSAGE_WEBHOOK_SECRET`.
163163

164-
The same secret must exist in two places:
164+
The same webhook secret must exist in two places:
165165

166166
- Supabase Edge Function secrets as `PEELS_CHAT_MESSAGE_WEBHOOK_SECRET`.
167167
- Supabase Vault as `PEELS_CHAT_MESSAGE_WEBHOOK_SECRET`, so the database trigger can send it in the `x-peels-webhook-secret` header.
168168

169+
The database trigger also needs the hosted project URL in Vault:
170+
171+
- Supabase Vault as `PEELS_SUPABASE_PROJECT_URL`, for example `https://<project-ref>.supabase.co`.
172+
173+
Do not use local Supabase Docker hostnames such as `kong:8000` in migrations that run in hosted environments. They work during local `supabase db reset`, but hosted Postgres cannot resolve them.
174+
169175
Do not use the public anon key as the protection boundary for this webhook. The function holds a service-role client so the caller must be authenticated by a non-public secret.
170176

171177
## Change rules
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
-- Hosted Postgres cannot resolve the local Supabase Docker hostname
2+
-- `kong:8000`. Read the project URL from Vault so the chat email webhook can
3+
-- call the deployed Edge Function in every environment.
4+
5+
create or replace function private.notify_new_chat_message()
6+
returns trigger
7+
language plpgsql
8+
security definer
9+
set search_path = ''
10+
as $$
11+
declare
12+
webhook_secret text;
13+
project_url text;
14+
begin
15+
if to_regprocedure('net.http_post(text,jsonb,jsonb,jsonb,integer)') is null then
16+
raise warning 'Skipping chat message email webhook because pg_net is unavailable.';
17+
return new;
18+
end if;
19+
20+
if to_regclass('vault.decrypted_secrets') is not null then
21+
execute
22+
'select decrypted_secret from vault.decrypted_secrets where name = $1 limit 1'
23+
into webhook_secret
24+
using 'PEELS_CHAT_MESSAGE_WEBHOOK_SECRET';
25+
26+
execute
27+
'select decrypted_secret from vault.decrypted_secrets where name = $1 limit 1'
28+
into project_url
29+
using 'PEELS_SUPABASE_PROJECT_URL';
30+
end if;
31+
32+
if webhook_secret is null or webhook_secret = '' then
33+
raise warning 'Skipping chat message email webhook because PEELS_CHAT_MESSAGE_WEBHOOK_SECRET is not set in Vault.';
34+
return new;
35+
end if;
36+
37+
if project_url is null or project_url = '' then
38+
raise warning 'Skipping chat message email webhook because PEELS_SUPABASE_PROJECT_URL is not set in Vault.';
39+
return new;
40+
end if;
41+
42+
begin
43+
perform net.http_post(
44+
url := rtrim(project_url, '/') || '/functions/v1/send-email-for-new-chat-message',
45+
body := jsonb_build_object(
46+
'type', tg_op,
47+
'table', tg_table_name,
48+
'schema', tg_table_schema,
49+
'record', jsonb_build_object('id', new.id),
50+
'old_record', null
51+
),
52+
params := '{}'::jsonb,
53+
headers := jsonb_build_object(
54+
'Content-Type', 'application/json',
55+
'x-peels-webhook-secret', webhook_secret
56+
),
57+
timeout_milliseconds := 5000
58+
);
59+
exception
60+
when others then
61+
raise warning 'Skipping chat message email webhook because the request failed: %', sqlerrm;
62+
end;
63+
64+
return new;
65+
end;
66+
$$;
67+
68+
alter function private.notify_new_chat_message() owner to postgres;
69+
70+
revoke all privileges on function private.notify_new_chat_message()
71+
from anon, authenticated, public;

0 commit comments

Comments
 (0)