feat(deploy): production hardening — Secret Manager mode, B9 import script, prod runbook (S6)#304
Conversation
Review — request changes 🔴 (adversarial pass)Secret Manager routing is right (every sensitive var covered, pushed via stdin not argv, removed from MUST-FIX 1 — a malformed/missing MUST-FIX 2 — MUST-FIX 3 — runbook sweep-token wiring is broken. Non-blocking but real: |
46f291a to
37b0104
Compare
…cript, prod runbook (S6) The gate before public signups (PLAN_WEB_SIGNUP S6): - deploy.sh SECRETS_MODE=sm: sensitive values (tokens, LLM/Stripe/Resend keys, Turnstile secret, reviewer seed) go to Secret Manager — created/ versioned idempotently per deploy, granted to the runtime SA, delivered via --set-secrets — instead of console-visible plain env vars. Default 'env' mode keeps demo behavior byte-identical. All env plumbing now routes through one addenv helper. - scripts/import-accounts-firestore.ts: the missing B9 cutover piece — imports accounts.json, per-uid balances, and the IAP tx index into the exact Firestore docs the runtime reads (lisa-global/accounts, lisa-balances/<uid>, lisa-txindex/<tx> create-only). Idempotent, with --dry-run/--force. firestore.ts gains LISA_FIRESTORE_TOKEN so admin tooling can run outside Cloud Run (no metadata server). - docs/RUNBOOK_CLOUD_PROD.md: the operator checklist from demo to public signup — prod project, Firestore create+import, sm-mode deploy, the third-party console table (Google OAuth, Apple SID, Turnstile, Resend, Stripe webhook), domain mapping (DNS-only), Scheduler sweep job, uptime/budget/anomaly alerts, three kill switches, smoke checklist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dd25710 to
ad785ba
Compare
Adversarial review + rebase onto
|
Part of PLAN_WEB_SIGNUP_v1.0 — milestone S6, the hard gate before public signups. Stacked on #302 (S4) → #301 → #299 → #297.
What
SECRETS_MODE=smfor deploy.shThe deploy script passed every secret (LLM keys, Stripe keys, the web token…) as plain
--set-env-vars, visible to anyone with console read access. Insmmode those values are now pushed to Secret Manager (secret created if absent, new version per deploy, runtime SA granted accessor) and reach the container via--set-secrets. Defaultenvmode keeps today's demo behavior byte-identical. All plumbing routes through oneaddenvhelper — verified with a bash unit test of the routing andbash -n.The missing B9 import script
RUNBOOK_ACCOUNTS_LAUNCH's Firestore section literally said "问我要导入脚本" — flipping
LISA_FIRESTORE=1on an empty database would orphan every existing account.scripts/import-accounts-firestore.tsimports the three file-backed stores into the exact docs the runtime seam reads:accounts.json→lisa-global/accounts {list}users/<uid>/billing/balance.json→lisa-balances/<uid>iap-transactions.json→lisa-txindex/<txId>(create-only, so replays are naturally deduped)Idempotent;
--dry-run/--force.firestore.tsgains aLISA_FIRESTORE_TOKENoverride so admin tooling can authenticate withgcloud auth print-access-tokenoutside Cloud Run (no metadata server there).docs/RUNBOOK_CLOUD_PROD.mdThe operator checklist from reviewer-demo to public signup: dedicated prod project → Firestore create + import →
SECRETS_MODE=sm LISA_FIRESTORE=1 MAX_INSTANCES=3deploy → third-party console table (Google OAuth client, Apple Services ID, Turnstile widget, Resend domain, Stripe webhook) →cloud.meetlisa.aidomain mapping (DNS-only/grey-cloud, TLS by Google) → Cloud Scheduler sweep job → uptime check + budget alerts + the built-in anomaly log alert → three kill switches → a launch smoke checklist. Every credential-gated step is flagged for the owner.Tests
npm test: 1324 pass / 0 fail;bash -n+ an addenv routing check on deploy.sh.🤖 Generated with Claude Code