Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions GITHUB_ISSUES.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Every issue inherits `AGENTS.md` and the definition of done in `IMPLEMENTATION_P
| 8 | OAUTH-001 | Make Strava token lifecycle server-only, transactional, and auditable | P0 | M | represented by live [#88](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/88); proposed/unclaimed | SAFETY-001/#99; SEC-001 and AUTH-003 for A; staged deferral/cutover with ABUSE-001A for C |
| 9 | AUTH-003 | Introduce scoped admin capabilities, MFA, and recent authentication | P1 | L | proposed | AUTH-001, AUTH-002, SEC-001 |
| 10 | ABUSE-001 | Enforce native App Check and privacy-preserving abuse limits | P0 | L | ready | CI-001 baseline |
| 11 | PAY-001 | Add strict request schemas and immutable monetary snapshots | P0 | L | ready | ABUSE-001 interface agreed |
| 11 | PAY-001 | Add strict request schemas and immutable monetary snapshots | P0 | L | partial: PAY-001A source/tests tracked in [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157); B/C/D and endpoint adoption open | ABUSE-001 interface agreed |
| 12 | PROMO-001 | Disable unmodeled Stripe promotions until discounts are authoritative | P0 | S | source/tests complete under open GitHub issue #102; provider inventory and deployment remain owner action | PAY-001 for any future discount contract |
| 13 | PAY-002 | Implement idempotent payment commands and explicit state machines | P0 | L | ready after PAY-001 | CONFIG-001, PAY-001 |
| 14 | PAY-003 | Build idempotent, async-aware Stripe webhook ingestion | P0 | L | PAY-003A source merged in #101; PAY-003B/C remain open; not deployed | CONFIG-001, PAY-001/PAY-002 target contract |
Expand Down Expand Up @@ -533,9 +533,15 @@ App Check is not authentication. Do not remove Auth/capability checks or rely on
## PAY-001 — Add strict request schemas and immutable monetary snapshots

**Labels:** `priority:P0`, `type:security`, `area:stripe`, `area:race`, `area:shop`, `size:L`
**Status:** Ready
**Status:** Partial. PAY-001A source/tests are tracked in live [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157). PAY-001B/C/D, endpoint adoption, snapshots, deployment, and live behavior remain open.
**Depends on:** ABUSE-001 interface agreed

### Current atomic boundary

PAY-001A adds dependency-free strict-root-object, root-budget, bounded array/string, integer-cents, fixed-currency, calendar-date, canonical-URL, conservative-email, fixed-error, and closed-enum safe-log primitives. Unknown configured root keys reject; nested values remain data-only/budgeted until endpoint-owned exact schemas validate them. The libraries return new immutable values, contain no Firebase, Stripe, network, logger, clock, or random dependency, and make no such call themselves. A supplied array item parser must be trusted, pure, synchronous, and endpoint-owned. Exact review, merge, and hosted-CI status belong to [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157).

No current endpoint imports these helpers. Race, merchandise, lookup, refund, cancellation, substitution, role, tracking, export, and dynamic custom-field schemas remain **NOT AVAILABLE YET** under PAY-001B/C/D. PAY-001A also does not create immutable price/waiver snapshots, deploy Firebase, configure Stripe, or prove production protection.

### Problem

Public/admin Functions validate only a few required strings. Names, phones, dates, notes, tracking values, custom fields, arrays, URLs, amounts, and nested payload size are weakly bounded. Event-required custom fields and allowed options are enforced only in HTML. Monetary records store one list amount but not an immutable expected/actual breakdown.
Expand Down
2 changes: 1 addition & 1 deletion GITHUB_ISSUE_SLICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ An agent-ready child has one observable outcome, one trust boundary, explicit de
| CONFIG-001B1 | source/tests tracked in live [#151](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/151); CONFIG-001A; not deployed/configured | Require an exact deploy-time ceiling; false denies new commerce before Firestore. Commands passing it and every refund use a fresh server-only global/domain/resource admission read. Keep webhook/mail independent; missing controls and resource flags mean disabled. | Paid/free/volunteer, merchandise, comp, late-registration, and refund allow/deny tests prove fixed failures and no command side effect; Rules tests deny every browser role; continuity and race-boundary tests pass. |
| CONFIG-001B2 | blocked owner/operator; B1, AUTH-003/ADMIN-001, PAY-002/PAY-004/PAY-005, CI-001 | Add a recent-auth capability-protected writer, append-only audit, active-provider-object recovery, protected deployment, and private disable/restore drill. | Named owners safely disable and restore synthetic staging commerce without code changes; in-flight and existing Stripe objects are reconciled; private provider/Firebase evidence is recorded. |
| PROMO-001 | source/tests complete in [#102](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/102); provider inventory and deployment remain owner action; PAY-001A for future enablement | Disable promotion entry and automatic tax in both Session creators; require a complete Stripe breakdown; quarantine unknown or nonzero discount, tax, or shipping adjustments. | Exact Session payload assertions and signed zero/partial/full/malformed/failed/expired adjustment tests pass; pre-change Session/provider inventory and live verification remain open. |
| PAY-001A | ready; CI-001A | Add shared strict-object, bounds/depth, integer-cents/currency/date/URL/email primitives, safe errors, and redacted logging. | Prototype/deep/Unicode/money/unknown-key tests prove no external call. |
| PAY-001A | source/tests tracked in live [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157); CI-001A; no endpoint adoption/deployment | Add shared strict-object, root-budget, bounded array/string, integer-cents/currency/date/URL/email, fixed-error, and closed-enum safe-log primitives. | Node 20 prototype/proxy/deep/Unicode/money/unknown-key/log-canary tests prove immutable outputs and no external or logger call; exact merge/CI evidence belongs to #157. |
| PAY-001B | proposed; PAY-001A | Apply race/volunteer/free schemas, validate server event custom fields/options, and persist price/waiver snapshots. | Positive/hostile dynamic-field and snapshot tests. |
| PAY-001C | proposed; PAY-001A | Apply merchandise/variant/quantity schemas and immutable merchandise price snapshots. | Variant/quantity/money/payload tests. |
| PAY-001D | proposed; PAY-001A, AUTH-003A | Apply bounded schemas to lookup/refund/cancel/substitute/late/comp/role/tracking/export commands. | Endpoint matrix with hostile/boundary/no-side-effect tests. |
Expand Down
4 changes: 3 additions & 1 deletion IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ Exit gate:
- Sensitive callables enforce App Check at the Firebase runtime.
- All public/admin request shapes are strict, bounded, server-validated, and covered by hostile-input tests.

**Current partial boundary:** PAY-001A is tracked in live [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157). It provides pure strict-object, shared-budget, scalar, fixed-error, and safe-log primitives with synthetic hostile-input tests. No current endpoint imports them, so PAY-001B/C/D endpoint schemas, immutable monetary snapshots, deployment, and live protection remain **NOT AVAILABLE YET**.

### Phase 2 — Build the payment integrity core

**Issues:** PROMO-001, PAY-002, PAY-003, RACE-001, MERCH-001
Expand Down Expand Up @@ -211,7 +213,7 @@ The first tranche deliberately combines one urgent safety repair with the most c
3. **SEC-001 — Firestore trust boundaries:** #100 merged through [PR #123](https://github.com/Run-MPRC/Run-MPRC.github.io/pull/123) at `a7fc301e85b0aeabe396e771faea21d3fc8e7b2b`. Source and 295 Rules tests remove recursive browser-admin authority. Firebase deployment explicitly skipped, so deployed/live Rules remain unproven under #105.
4. **PROMO-001 — fail-safe monetary policy:** [#102](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/102) disables promotion entry and automatic tax in both current creators, adds exact payload tests, and quarantines unknown or nonzero discount/tax/shipping adjustments on success, failure, and expiry. The private pre-change Session/provider inventory, protected deployment, provider readback, and live verification remain owner actions; no discount, tax, or shipping feature is authorized.
5. **Identity/config next:** AUTH-001A [#98](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/98) merged at `ce22c110`, proving source/tests for unverified-target rejection at the existing role-grant endpoints. Its Firebase deployment skipped, so backend-live status is unproven and the remaining AUTH-001 parent work stays open. CONFIG-001A merged through [#149](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/149) / PR #150 as `2c62b8dd`, but remains undeployed. CONFIG-001B1 is tracked in [#151](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/151) for fail-closed read-only admission; B2 retains the protected audited operator control, provider-object recovery, and drill. Follow the live issues and do not duplicate these slices.
6. **Then:** PAY-001/PAY-002 so checkout creation, refunds, and every later handler share strict schemas and idempotent state.
6. **PAY-001/PAY-002:** PAY-001A source/tests are tracked in [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157) as the shared validation/logging foundation. PAY-001B/C/D must still wire exact endpoint schemas and immutable snapshots before PAY-002 can make checkout creation, refunds, and later handlers idempotent.
7. **Then:** RACE-001 and MERCH-001 transactional reservations.

Why this order: SAFETY-001 removes immediate accidental-production and callback hazards without schema impact. PAY-003 closes the most dangerous “unpaid looks paid” and replay gaps while establishing test fixtures. The subsequent trust-boundary and command/state work completes the surrounding architecture; no live launch is authorized by the partial webhook patch alone.
Expand Down
1 change: 1 addition & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ These entries are implementation evidence, not a production risk-acceptance deci

| Risks | Source result | Remaining closure evidence |
| --- | --- | --- |
| RISK-017 | PAY-001A is tracked in live [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157). The source slice adds dependency-free strict-root-object, root-budget, bounded string/array, integer-cents, fixed-currency, calendar-date, canonical-URL, conservative email, fixed-error, and closed-enum safe-log primitives. Synthetic hostile-input tests prove deep immutable copies and reject prototypes, accessors, and unknown configured root keys. The libraries contain no network, Firebase, Stripe, logger, clock, or random dependency and make no such call themselves; a supplied array item parser must be trusted, pure, and synchronous. | This library is not imported by an endpoint and is not deployed. PAY-001B/C/D must define exact race, merchandise, lookup, refund, admin, nested-object, and custom-field schemas; apply smaller business limits before every write/provider call; store immutable schema/price snapshots; and add endpoint no-side-effect tests. Safe-log primitives do not replace approved observability purpose, retention, access, transport, or provider controls. |
| RISK-001, RISK-002, RISK-034 | PAY-003A [#101](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/101) source merged as `87bd1210575882cdd06214bcb98ed38ce00f71c2`, adding durable Stripe Event deduplication, transactional transition/processed marking, paid/amount/currency/Checkout-mode/reference-shape and explicitly configured livemode checks, async outcomes, monotonic refund/terminal guards, quarantine, generic signature failures, and a webhook-secret-only binding. | Firebase was not deployed. Complete CONFIG/PAY-001/PAY-002 contracts, metadata schema allowlist/migration, canonical reducers/reservations/outbox, retry/dead-letter/TTL/alerts, emulator integration, Stripe test-mode rehearsal, protected deploy, and reconcile. |
| RISK-006, part of RISK-024/RISK-032 | #100 merged at `a7fc301e85b0aeabe396e771faea21d3fc8e7b2b`. OAuth secrets and server-owned financial/operational collections are denied; current catalog writes are restricted to inert drafts/display fields. | Firebase deployment skipped. Stage/deploy the exact Rules revision under #105, verify synthetic deny behavior, then move remaining catalog mutation to scoped APIs under ADMIN-001. |
| RISK-009 | #99 preserves same-origin path, query, and fragment state through the Pages fallback, clears temporary state, rejects unsafe targets, and suppresses monitoring startup on initial capability callbacks. #126 adds the standalone suite as the named blocking `Run SPA callback safety tests` hosted step. | Keep exact hosted evidence on #126; verify exact website publication and later run approved test-mode Stripe/Strava callbacks; WEB-001 still owns controlled hosting. |
Expand Down
13 changes: 13 additions & 0 deletions STRIPE_COMMERCE_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,19 @@ The backend should remain correct if a delayed method appears accidentally:
- Keep Stripe IDs as references, not proof: Session, PaymentIntent, Charge, Refund, Product, Price, and Event IDs each have different semantics.
- Do not put PII, waiver text, emergency contacts, or secrets in Stripe metadata. Use opaque local IDs and a schema version.

### Shared request-safety primitives (PAY-001A)

PAY-001A is tracked in live issue [#157](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/157). It adds two pure CommonJS libraries for later server endpoint work:

- `requestValidation` accepts an exact root plain object with own data properties, rejects unknown configured root keys and dangerous keys anywhere, returns a new deeply frozen value, and applies one technical budget across a strict-object tree. Nested values are data-only and budgeted; every nested object still needs an endpoint-owned exact schema. The hard ceilings are depth 6, 100 object/array entries, 50 items per array, 128 code points/512 bytes per key, 2,000 code points/8,192 bytes per string, and 64 KiB serialized. Every endpoint must define a smaller business limit where appropriate.
- Its scalar helpers accept only nonnegative integer cents (maximum 100,000,000 technical cents, with a lower endpoint limit expected), launch currency `usd`, canonical calendar dates, canonical HTTPS DNS URLs, explicitly enabled canonical test/development loopback URLs, and conservative bounded ASCII email syntax. URL syntax validation is not an outbound-host authorization or SSRF allowlist. Email syntax is not proof of identity, membership, or delivery.
- `safeLogging` creates only a new frozen five-field projection—event, operation, outcome, code, and environment—from fixed low-cardinality values. It cannot copy request bodies, arbitrary keys, IDs, URLs, contact details, addresses, Stripe/OAuth material, or raw errors, and it does not call a logger.
- Failures expose one fixed message and a fixed reason category. Supplied values and provider details are not included.

The libraries contain no Firebase, Stripe, provider, logger, network, clock, or random dependency and make no such call themselves. `parseBoundedArray` deliberately invokes a supplied item parser; that parser must be trusted, pure, synchronous, and endpoint-owned.

These helpers are a source/test foundation only. No checkout, refund, admin, webhook, Firebase, or Stripe endpoint imports them in PAY-001A. Endpoint schemas, immutable business-price snapshots, deployment, and production behavior remain **NOT AVAILABLE YET** under PAY-001B/C/D and later payment issues.

## 5. Catalog model

### Race pricing
Expand Down
Loading
Loading