Repository navigation
CONFIG-001A — Require typed server environment, origin, and Stripe mode before side effects #149
Description
Officer impact: Releases with missing or mismatched server settings stop safely before creating registrations, orders, Stripe objects, refunds, or mail. Officers never handle or copy a Stripe key.
Officer documentation: Update docs/officers/PUBLISH_AND_CHECK.md plus exact status/evidence in SECURITY.md, OPERATIONS_RUNBOOK.md, GITHUB_ISSUES.md, and GITHUB_ISSUE_SLICES.md.
Deployment evidence: None at issue creation. Closure must separate source/tests, merge, Firebase deployment, Stripe/Firebase parameter configuration, website publication, and observed production behavior. No provider values, live key, production payment, email, or member data may be used.
Parent and dependency
Focused CONFIG-001A child of the catalogued CONFIG-001 design. #103 provides the local frontend baseline and is closed. #99, #101, and #102 are merged; their callback, webhook, and promotion protections must be preserved. CONFIG-001B remains a separate future child for global/per-domain commerce kill switches.
Problem
Several Functions silently replace a missing SITE_ORIGIN with https://runmprc.com. Stripe client construction checks only that a key exists, while expected livemode is validated separately in the webhook. A missing or mismatched environment setting can therefore create production-looking URLs, use a test/live key in the wrong environment, or allow Firestore/mail/Stripe work before configuration failure is known.
Atomic outcome
Create one small CommonJS server-configuration boundary and require it at each current commerce or commerce-email invocation. It parses an allowlisted environment, a canonical site origin, explicit expected Stripe mode, and test/live server-key compatibility. It returns only frozen nonsecret configuration. It never logs, returns, stores, serializes, or passes through the complete key. Unsafe or missing configuration fails with a fixed generic result before Firestore writes, mail enqueue, rate-limit writes, or Stripe calls.
Required environment matrix
local: canonicalhttporhttpsloopback origin on exactlocalhost,127.0.0.1, or[::1]; Stripe test mode; test server key.test: canonical HTTPS synthetic.testorigin; Stripe test mode; test server key.staging: exacthttps://dev.runmprc.com; Stripe test mode; test server key.production: exact canonicalhttps://runmprc.com; Stripe live mode; live server key.- Origins contain no credentials, path, trailing slash, query, fragment, whitespace normalization, or default-port alias. No code supplies a production fallback.
- Recognize only documented server-side
sk_test_/rk_test_andsk_live_/rk_live_mode markers with a nonempty suffix. Reject publishable, webhook, blank, padded, prefix-only, or unknown forms. Never print or validate the complete key contents.
Validation scope and precedence
- Both checkout creators and both admin action Functions already bind
STRIPE_SECRET_KEY; they validate base configuration plus key compatibility on every path, including free/comp/note/cancel paths. stripeWebhookand bothsendConfirmationEmailexports validate base environment/origin/mode only. They remain least-privilege and do not bind or requireSTRIPE_SECRET_KEY; webhook mode is never inferred from its signing secret.- Callable App Check/auth checks keep precedence so configuration does not become an authentication oracle; configuration still runs before data dispatch, rate limits, Firestore, audit, or Stripe.
- Webhook keeps method and signature verification precedence; valid signed events then validate base configuration before any Firestore/event-ledger work. Bad signatures remain fixed
400. - Email triggers keep irrelevant/no-op eligibility checks first; qualifying work validates configuration before event reads, outbox writes, or sent markers.
Invariants
- Invalid configuration causes no registration/order/rate-limit/audit/mail/event-ledger write and no Stripe client or request.
- A callable receives one generic
failed-preconditionmessage; an HTTP/trigger path returns/throws a fixed non-secret configuration failure. - Webhook signature, reference, promotion/quarantine, replay, async-payment, and terminal-state protections from PAY-003A — Harden Stripe webhook ingress and monotonic event reduction #101/PROMO-001 — Disable unmodeled Stripe price adjustments #102 do not weaken.
- Webhook ingestion remains independent of a checkout kill switch; CONFIG-001B owns switch behavior.
- Free/volunteer and paid checkout start behind the same base environment/origin/mode/key boundary after App Check.
- Existing URL paths and successful test-mode behavior remain backward compatible once valid settings are supplied.
- Tests use made-up keys/identities and mocked Stripe/Firestore/mail only. No network.
Initial source boundary
- New
functions/serverConfig.jsand focused test. functions/stripeHelpers.js.- Current commerce/email entry points only:
createCheckoutSession.js,createMerchCheckout.js,adminRegistrationAction.js,adminOrderAction.js,stripeWebhook.js, and both exports insendConfirmationEmail.js. - The minimum existing tests and local example files needed to express valid synthetic configuration.
- Minimum root/officer status documentation listed above.
Post a scope amendment before editing any additional runtime, workflow, package/lock, Rules, client, or provider file.
Acceptance criteria
- A pure/table-tested parser accepts only the documented environment/origin/mode combinations.
- Missing, unknown, whitespace-padded, malformed, credential-bearing, path/query/fragment, insecure hosted, production-in-nonproduction, and nonproduction-in-production combinations fail closed.
- Missing, prefix-only, unrecognized, live-in-local/test/staging, and test-in-production server keys fail before client construction or other side effects.
- The returned config and every error/log contain no complete Stripe key or supplied unsafe value.
- No current server code silently falls back to
https://runmprc.com. - Focused endpoint tests prove invalid configuration causes zero Firestore, rate-limit, mail, and Stripe side effects.
- Existing checkout payload, webhook lifecycle, authorization, profile, and Rules tests remain green.
- Functions lint, full Functions tests, frontend Jest/SPA checks, Rules tests, diagnostic build, diff/link/secret review all pass as applicable.
- Officer guidance names purpose, approver, prerequisites, expected result, stop conditions, proof, undo, and escalation in plain language.
Explicitly excluded
COMMERCE_ENABLED, global/per-event/per-product kill-switch enforcement, and its race matrix (CONFIG-001B).- New request schemas, idempotency/state reducers, capacity/inventory, refunds redesign, provider configuration, Secret Manager/IAM, deployment workflow changes, Stripe Dashboard changes, live-mode enabling, or real payment/email tests.
- Any weakening or redesign of SAFETY-001 — Preserve callbacks and fail closed on local Firebase isolation #99 callback guards, PAY-003A — Harden Stripe webhook ingress and monotonic event reduction #101 webhook state handling, or PROMO-001 — Disable unmodeled Stripe price adjustments #102 promotion/adjustment quarantine.
Rollout and rollback
Source is backward compatible only when every environment supplies explicit valid settings. Deployment/provider setup is a separate protected operation with private evidence. Roll back by reverting this child; never restore a production-domain fallback.
Claim protocol
Assigned and claimed by /root at 2026-07-13T11:45:23Z on codex/issue-149-typed-server-config, base 46557c7988a496c1081e268baad6f33fb186ee0f. Keep this one configuration outcome.
Activity
daliu commentedon Jul 13, 2026
CLAIMED by /root at 2026-07-13T11:45:23Z; branch codex/issue-149-typed-server-config; base 46557c7.
daliu commentedon Jul 13, 2026
SCOPE AMENDMENT — focused entry-point proof
Add one new test-only file:
functions/serverConfigEntryPoints.test.js.Reason:
adminOrderActionand bothsendConfirmationEmailexports have no existing tests, yet #149 requires direct proof that invalid base/key configuration causes zero Firestore, mail, marker, and Stripe side effects. The file will use mocks and synthetic values only. It will not change runtime scope, packages, workflows, Rules, clients, providers, or production state. Existing checkout/admin-registration/webhook tests remain the owners for their current entry points.daliu commentedon Jul 13, 2026
DOCUMENTATION SCOPE AMENDMENT
Add minimum status/truth paragraphs to
SYSTEM_DESIGN.mdandSTRIPE_COMMERCE_DESIGN.md.Reason: #149 changes the trusted server configuration boundary and exact Stripe environment matrix. The root design documents are authoritative and must distinguish this source guard from provider configuration/deployment. No additional runtime, client, workflow, package, Rules, provider, or data scope is added.
daliu commentedon Jul 13, 2026
DOCUMENTATION SCOPE AMENDMENT — status index
Add one minimum status sentence to
IMPLEMENTATION_PLAN.mdso the first-tranche CONFIG work points to live child #149 and does not invite duplicate publication. No implementation or deployment scope changes.daliu commentedon Jul 13, 2026
IMPLEMENTATION / REVIEW READY — 2026-07-13T12:04:34Z
Source commit: 41c0304
Base: 46557c7
Exact reviewed staged diff SHA-256: 8aabdfadf9be73b8da7c4ebf7cdafb20ecf7e6b8a4f0940c046382f5ae21200d
Outcome: current commerce and confirmation-mail entry points now parse one frozen, nonsecret server configuration on every invocation. Missing, malformed, or environment-mismatched origin/mode/key settings fail with fixed messages before rate-limit, business-data, mail, event-ledger, or Stripe side effects. App Check/admin checks, webhook method/signature checks, and mail no-op eligibility keep precedence.
Verification:
Officer impact: Releases with missing or mismatched settings stop before registrations, orders, refunds, mail, or Stripe work. Officers never handle a Stripe key.
Officer documentation: docs/officers/PUBLISH_AND_CHECK.md
Deployment evidence: source/tests only. Firebase parameters, Secret Manager bindings, Stripe provider mode, Firebase deployment, website publication, and production behavior remain unproven. No production payment, email, member data, provider setting, or secret was used. CONFIG-001B still owns the future checkout stop switch.
daliu commentedon Jul 13, 2026
COMPLETED — 2026-07-13T12:09:44Z
PR #150 squash-merged exact reviewed source as 2c62b8d. Post-merge CI run 29248650885 passed frontend Jest and SPA safety checks, diagnostic build, Functions lint/tests, and Firestore Rules tests at that exact main commit.
Deployment truth: CONFIG-001A is merged but not deployed to Firebase. The protected release workflow supports only the fixed profile-recovery plan and therefore cannot deploy the commerce/mail Function set in #149. A read-only configuration-name audit also found the required production protected environment and public website configuration absent. No release was triggered because it would either deploy the wrong fixed scope or repeat a known fail-closed configuration error. No Firebase, Stripe provider, website, email, payment, or production-data behavior was changed or verified.
Residual work: #105/#133/#136 own protected deployment authority and evidence. A separately reviewed immutable release plan must explicitly name and verify the #149 Function set before deployment. CONFIG-001B remains separate for the commerce stop switch.
Officer impact: Unsafe releases now fail closed in merged source; this is not yet live backend behavior.
Officer documentation: docs/officers/PUBLISH_AND_CHECK.md
Deployment evidence: exact merge and hosted CI proven; Firebase/provider/website/live behavior unproven.