Skip to content

SPRINT-7 T2-1 Report — Edge Functions Deploy + Auth Model

Date: 2026-08-30
Status: T2-1 PASS. STOP — await Ryan review before T2-2 (last1.app monolith).
VM: 120 last1app-db @ 192.168.1.103


Executive summary

Workstream Result
Edge Functions deployed 22/22 on R940 Edge Runtime (container recreated)
Secret injection 25 keys via Onset-style .env + docker-compose.yml patch (BWS + Railway + vault + last1.id DB)
LAST1_ID_API_BASE https://auth.last1.id (sovereign; no nztgswcpnwggymncrnyx in edge env)
Internal HTTP smoke 23/23 PASS (22 functions + cron-auth path)
pg_cron activation 3/3 active → internal Kong 192.168.1.103:8000/functions/v1/*
Realtime healthy (unchanged)
Hosted untouched

Scripts: t2-1-build-edge-secrets.py, t2-1-deploy-edge.sh, t2-1-smoke-edge.sh, t2-1-activate-crons.sh

Flag T2-3: Twilio (GG 29160801) + Stripe (GG 29615733) deployed with current Railway values — rotate at T2-3.

Flag smoke: sms-daily-check anon probe returned messages_sent: 2 (live Twilio credentials). Review whether 2 SMS left the account during smoke.


1. Deploy

Functions (22)

All RadioCheck supabase/functions/* synced from agent clone → /tmp/last1app-functions → volumes/functions/.

hello staging artifact removed. Count verified: 22.

Secret injection (Onset pattern)

  1. t2-1-build-edge-secrets.py (agent or VM + BWS token) writes /tmp/last1app-ef-secrets.env
  2. patch_env → /opt/supabase/docker/.env
  3. Python patch → docker-compose.yml under VERIFY_JWT anchor (25 env keys)
  4. docker compose up -d --force-recreate functions

Sovereign last1.id bridge verification

Function Target R940 value nztgswcp?
check-in-proof-events (outbound trust POST) LAST1_ID_API_BASE https://auth.last1.id No
sync-last1 (outbound bundle/org webhooks) LAST1_WEBHOOK_URL / LAST1_ORG_ACCESS_WEBHOOK_URL https://last1.app/api/webhooks/... (Railway monolith until T2-2) No
sync-user-from-last1 (inbound from last1.app) HMAC LAST1_WEBHOOK_SECRET Railway shared secret No
revoke-from-last1 (inbound from last1.id) LAST1_INBOUND_WEBHOOK_SECRET From last1.id DB app_clients.webhook_secret_b64 (radiocheck) No

Note: last1.id app_clients.webhook_url for radiocheck still points at hosted https://tcthzakppndkykatoefx.supabase.co/functions/v1/revoke-from-last1. Revoke deliveries remain on hosted until T-5 URL update on last1.id (same class as Twilio/Stripe dashboard cutover).

Note: BWS EXPO_PUBLIC_LAST1_ID_SUPABASE_URL in last1-radiocheck project still references deleted hosted ref — iOS/build T-5, not edge runtime.

Injected secrets (categories)

Source Keys
Railway last1.app Twilio, Stripe, SendGrid, LAST1_WEBHOOK_SECRET
BWS Last1.id RADIOCHECK_APP_SECRET, sovereign LAST1_ID_API_BASE
R940 vault RADIOCHECK_CRON_SECRET
last1.id DB LAST1_INBOUND_WEBHOOK_SECRET
Twilio API TWILIO_MESSAGING_SERVICE_SID
Stripe API STRIPE_PRICE_* (6 RadioCheck/VSO monthly prices)
Derived Internal webhook URLs on 192.168.1.103:8000, last1.app webhook URLs

Not injected (hosted-only today): APNs (APNS_*), FCM (FCM_*). silence-engine / trigger-check-ins return 500 Missing APNs credentials until those are added (push path).


2. Per-function auth model (T-5 public exposure prep)

Global gateway: FUNCTIONS_VERIFY_JWT=false (all functions). T-5 should add per-function gateway JWT (Onset T5-1 pattern) for user-facing endpoints before api.last1.app goes public.

Function Auth model T-5 gateway recommendation
sms-webhook Twilio X-Twilio-Signature Public, no JWT — signature only
stripe-webhook Stripe stripe-signature Public, no JWT — signature only
sync-user-from-last1 HMAC x-last1-signature + timestamp Public, no JWT — HMAC only
revoke-from-last1 HMAC X-Last1-Signature (@last1id/sdk) Public, no JWT — HMAC only
check-in-proof-events Bearer RADIOCHECK_CRON_SECRET (preferred) Internal/cron only at T-5; block public anon
sms-cron pg_cron → no JWT Internal (cron + LAN)
org-sms-cron pg_cron → no JWT Internal
sms-checkin-cron pg_cron → sms-cron Internal
delete-account Supabase user JWT in-function Enable gateway JWT
quick-check-in Supabase user JWT in-function Enable gateway JWT
stripe-checkout Supabase user JWT in-function Enable gateway JWT
stripe-portal Supabase user JWT in-function Enable gateway JWT
unit-request-actions HMAC signed email links + JWT for user routes Mixed — keep webhook actions on HMAC; JWT for authenticated routes
last1-id-callback Public GET (OAuth redirect HTML) Public, no JWT
sync-last1 Internal caller / service (outbound to last1.app) Restrict at gateway if exposed
org-sms, sms-send, sms-checkin, sms-daily-check Service-role / Twilio pipeline Internal or signed; review before public
send-push Service role today (no in-function JWT) Enable gateway JWT if client-callable
trigger-check-ins, silence-engine Internal scheduler/service Keep internal
verify-org-email Internal/admin trigger Restrict

3. Internal HTTP smoke (192.168.1.103:8000)

Log: /var/lib/supabase-data/gate-b/t2-1-edge-smoke.log

Check HTTP Notes
sms-webhook (anon) 403 Missing Twilio signature ✓
stripe-webhook (anon) 400 Missing stripe-signature ✓
sync-user-from-last1 (anon) 401 Missing HMAC ✓
revoke-from-last1 (anon) 401 invalid_signature ✓
check-in-proof-events (anon) 401 Unauthorized ✓
check-in-proof-events (cron bearer, dry_run) 200 Sovereign proof path ✓
delete-account (anon) 401 ✓
quick-check-in (anon) 401 ✓
stripe-checkout / stripe-portal (anon) 400 Reachable; body validation before auth
All other functions POST (anon) 200/400/500 Reachable (not connection refused)
last1-id-callback GET 200 Public HTML ✓

Summary: pass=23, fail=0


4. pg_cron activation

After smoke PASS, jobs activated as supabase_admin (postgres lacks cron.job write):

jobid jobname active Target
1 sms-checkin-cron true http://192.168.1.103:8000/functions/v1/sms-cron
2 org-sms-cron true http://192.168.1.103:8000/functions/v1/org-sms-cron
3 check-in-proof-events-cron true http://192.168.1.103:8000/functions/v1/check-in-proof-events (+ vault Bearer)

Manual cron-auth fire: HTTP 200 dry_run on sovereign Edge.

T-5 reminder: sms-checkin-cron + org-sms-cron at 14:00 UTC = first live outbound SMS on sovereign infra — conscious activation at DNS cutover, not auto-flip. Until T-5, crons hit internal Kong only (no public api.last1.app).

Hosted pg_cron on tcthzakppndkykatoefx unchanged (rollback net).


5. Ryan review checklist (before T2-2)

  1. Accept 22-function deploy + 25 secret keys (Twilio/Stripe rotation deferred T2-3)
  2. Accept LAST1_ID_API_BASE=https://auth.last1.id on Edge
  3. Accept cron active on internal URLs (note daily SMS crons now scheduled on R940)
  4. Review sms-daily-check smoke sent 2 messages — unintended live SMS?
  5. Plan APNs/FCM secret import before push-heavy paths matter
  6. Plan T-5 updates: last1.id webhook_url → api.last1.app, gateway JWT hardening

Next: T2-2 last1.app monolith on VM 121 + cloudflared prep (no DNS).