Skip to content

CONFIG-001A — Require typed server environment, origin, and Stripe mode before side effects #149

Closed

Description

@daliu

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: canonical http or https loopback origin on exact localhost, 127.0.0.1, or [::1]; Stripe test mode; test server key.
  • test: canonical HTTPS synthetic .test origin; Stripe test mode; test server key.
  • staging: exact https://dev.runmprc.com; Stripe test mode; test server key.
  • production: exact canonical https://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_ and sk_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.
  • stripeWebhook and both sendConfirmationEmail exports validate base environment/origin/mode only. They remain least-privilege and do not bind or require STRIPE_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-precondition message; 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.js and focused test.
  • functions/stripeHelpers.js.
  • Current commerce/email entry points only: createCheckoutSession.js, createMerchCheckout.js, adminRegistrationAction.js, adminOrderAction.js, stripeWebhook.js, and both exports in sendConfirmationEmail.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

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

  1. self-assigned this
    on Jul 13, 2026
  2. added
    priority:P0Launch blocker or urgent security risk
    type:securitySecurity or privacy boundary
    area:firebaseFirebase services and data
    size:MMedium multi-file issue
    status:readyDependencies complete and ready to claim
    area:stripeStripe payments and financial lifecycle
    type:testingTest infrastructure and quality gates
    on Jul 13, 2026
  3. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    CLAIMED by /root at 2026-07-13T11:45:23Z; branch codex/issue-149-typed-server-config; base 46557c7.

  4. added
    status:in-progressClaimed and actively being implemented
    and removed
    status:readyDependencies complete and ready to claim
    on Jul 13, 2026
  5. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    SCOPE AMENDMENT — focused entry-point proof

    Add one new test-only file: functions/serverConfigEntryPoints.test.js.

    Reason: adminOrderAction and both sendConfirmationEmail exports 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.

  6. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    DOCUMENTATION SCOPE AMENDMENT

    Add minimum status/truth paragraphs to SYSTEM_DESIGN.md and STRIPE_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.

  7. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    DOCUMENTATION SCOPE AMENDMENT — status index

    Add one minimum status sentence to IMPLEMENTATION_PLAN.md so the first-tranche CONFIG work points to live child #149 and does not invite duplicate publication. No implementation or deployment scope changes.

  8. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    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:

    • Node 20 focused: 5 suites, 196/196 passed
    • Full Functions: 7 suites, 226 passed; 1 emulator-only test skipped
    • Functions lint: passed
    • Frontend Jest: 9 suites, 113/113 passed
    • SPA callback suite: 10/10 passed
    • Diagnostic frontend build: passed
    • Diff/link/sensitive-pattern review: passed
    • Local Rules: not runnable on this Mac because Java is absent; no Rules files changed; hosted Rules CI is required before merge
    • Two independent exact-diff reviews: APPROVED

    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.

  9. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:firebaseFirebase services and dataarea:stripeStripe payments and financial lifecyclepriority:P0Launch blocker or urgent security risksize:MMedium multi-file issuetype:reliabilityReliability and recoverytype:securitySecurity or privacy boundarytype:testingTest infrastructure and quality gates

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions