SPRINT-7 T5-B Phase 2 — api.last1.app public exposure¶
Date: 2026-08-30 (23:20 UTC)
Status: PHASE 2 COMPLETE — STOP for Ryan review
Authorization: Ryan T5-B Phase 2 go (Phase 1 SAFE TO EXPOSE confirmed)
Prior: SPRINT7_T5-B_PHASE1_RERUN_REPORT.md
Verdict¶
api.last1.app LIVE — public smoke ALL PASS¶
Production Supabase API hostname is exposed through Cloudflare proxied orange cloud → last1app-edge tunnel → Kong on VM 103 (192.168.1.103:8000).
STOP. Ryan reviews public RLS proof below before T5-C/T5-D (iOS pointer cutover, webhook URL rewrites, hosted teardown).
1. DNS + tunnel¶
| Item | Value |
|---|---|
| Hostname | api.last1.app |
| Record | CNAME → 6b0fa8e8-2eef-4550-9811-12e6ad31d10b.cfargotunnel.com |
| Proxied | Yes (orange cloud) |
| Public A | 104.21.32.216, 172.67.136.24 (Cloudflare anycast) |
| Tunnel VM | last1app-app @ 192.168.1.104 (VM 121) |
| Tunnel ingress | api.last1.app → http://192.168.1.103:8000 |
| Script | scripts/last1app/t5-b-dns-api.sh |
| Rollback backup | /tmp/last1app-gate-b/t5b-api-dns-backup-20260830T231851Z |
TLS terminates at Cloudflare (valid cert for api.last1.app, issuer Google Trust Services / Cloudflare edge).
2. Public smoke (through CF proxy — not LAN)¶
All requests showed cf-ray + server: cloudflare.
| Test | Result |
|---|---|
GET /auth/v1/health + apikey |
HTTP 200 |
Anon GET /rest/v1/users?select=id&limit=1 |
0 rows, HTTP 200 |
Anon GET /rest/v1/check_ins?select=id&limit=1 |
0 rows, HTTP 200 |
Anon GET /rest/v1/units?select=id&limit=1 |
0 rows, HTTP 200 |
Edge anon POST sync-user-from-last1 |
401 (rejected) |
Edge anon POST delete-account |
401 (rejected) |
Edge anon POST quick-check-in |
400 (rejected, not 200) |
Edge anon POST stripe-checkout |
400 (rejected, not 200) |
Edge cron anon POST sms-cron |
401 |
Edge cron anon POST org-sms-cron |
401 |
Storage profile-photos public path |
Reachable via CF (HTTP 400 without object path — bucket public) |
Storage unit-chat-images anon list |
0 objects, HTTP 200 |
DNS resolves to CF, not 192.168.* |
PASS |
Final proof (Ryan-requested): RLS identity denial holds on the public path, not just LAN Kong.
Report: /tmp/last1app-gate-b/t5b-public-smoke-20260830T231956Z.txt
Script: scripts/last1app/t5-b-public-smoke.sh
3. Direct-origin bypass¶
| Probe | Result |
|---|---|
Public DNS api.last1.app A records |
Cloudflare anycast only (no RFC1918) |
| Kong origin | 192.168.1.103:8000 — LAN/Tailscale only, not routed on public internet |
| Traffic path | Internet → CF WAF/proxy → tunnel → Kong |
No public bypass to Kong without going through Cloudflare tunnel hostname.
4. iOS / RadioCheck archive pointer (host + anon key pairing)¶
Sovereign stack (VM 103) — use for tonight's archive build:
| Env var | Value |
|---|---|
EXPO_PUBLIC_SUPABASE_URL |
https://api.last1.app |
EXPO_PUBLIC_SUPABASE_ANON_KEY |
BWS LAST1APP_DB_PROD_SUPABASE_ANON_KEY (last1-radiocheck project) |
JWT payload (sovereign anon key): role=anon, iss=supabase (stack-issued HS256 — not hosted ref tcthzakppndkykatoefx).
Current audit clone defaults (lib/supabase.ts): still fall back to hosted https://tcthzakppndkykatoefx.supabase.co + hosted anon JWT if env vars unset. Archive build must inject env (EAS secrets / .env.production) — code change not required if env is set at build time.
Auth note: Phone OTP / Apple SIWA on sovereign GoTrue are live (T5-A). Last1 auth client in supabase.ts remains pinned to hosted defaults for OTP; full cutover may require separate Last1 auth URL work (T5-C scope).
Staging reference (unchanged): https://last1app-db.last1.enterprises still works for internal smoke; production iOS should use api.last1.app.
5. Not in scope (deferred)¶
| Item | When |
|---|---|
| RadioCheck iOS TestFlight with new URL | T5-C (Ryan + archive) |
Twilio/Stripe webhook URL → api.last1.app |
T5-C/D |
pg_cron URL rewrite 192.168.1.103 → https://api.last1.app |
Before activating SMS crons publicly |
API_EXTERNAL_URL on VM 103 (still last1app-db.last1.enterprises) |
OAuth redirect URI alignment — separate pass |
| Hosted Supabase teardown | After iOS + webhooks cut over |
STOP¶
Phase 2 complete. Review public anon 0-row proof above before authorizing T5-C/T5-D.