feat: auth-gate demo chat + budget circuit breaker
Dev — Build & local smoke test / build-smoke (pull_request) Successful in 2m10s
Dev — Build & local smoke test / build-smoke (pull_request) Successful in 2m10s
Gate the demo chat behind Supabase auth: the widget now fetches Supabase config on open, shows a compact sign-in pane (Google OAuth or email/password) when the user is unauthenticated, and passes the access_token to /api/demo. The server verifies the token via supabase_auth_user() before any processing and uses the verified user ID as the rate-limit key. Add a budget kill switch: a demo_config table in Supabase holds a demo_enabled flag that /api/demo polls every 60s (cached, fails open). A Cloud Function (demo-budget-guard) is triggered by a GCP Pub/Sub budget alert and sets demo_enabled = 'false' when spend crosses 90% of the $150 daily budget. Budget and topic are provisioned; function is live in us-central1.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import json
|
||||
import base64
|
||||
import os
|
||||
import requests
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
def budget_alert(event, context):
|
||||
"""Triggered by a Pub/Sub budget alert. Disables demo if threshold exceeded."""
|
||||
data = base64.b64decode(event['data']).decode('utf-8')
|
||||
alert = json.loads(data)
|
||||
|
||||
# Only act on threshold exceeded alerts (not forecasts)
|
||||
cost_amount = alert.get('costAmount', 0)
|
||||
budget_amount = alert.get('budgetAmount', 1)
|
||||
threshold = cost_amount / budget_amount if budget_amount else 0
|
||||
|
||||
if threshold < 0.9:
|
||||
print(f"Threshold {threshold:.1%} below 90%, no action")
|
||||
return
|
||||
|
||||
supabase_url = os.environ['SUPABASE_URL']
|
||||
service_key = os.environ['SUPABASE_SERVICE_KEY']
|
||||
|
||||
resp = requests.patch(
|
||||
f"{supabase_url}/rest/v1/demo_config?key=eq.demo_enabled",
|
||||
headers={
|
||||
'Authorization': f'Bearer {service_key}',
|
||||
'apikey': service_key,
|
||||
'Content-Type': 'application/json',
|
||||
'Prefer': 'return=minimal',
|
||||
},
|
||||
json={'value': 'false', 'updated_at': datetime.now(timezone.utc).isoformat()}
|
||||
)
|
||||
print(f"Demo disabled — budget at {threshold:.1%}. Supabase: {resp.status_code}")
|
||||
@@ -0,0 +1 @@
|
||||
requests==2.31.0
|
||||
Reference in New Issue
Block a user