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
12 changes: 5 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Split an issue before implementation if it cannot be safely reviewed as one focu
- `firestore.rules`: browser access boundary. Admin SDK bypasses it, so also review server IAM/code.
- `tests/firestore-rules/`: required allow/deny tests for every rule change.
- `.github/workflows/`: CI and deployment trust boundary.
- `public/404.html` and `public/index.html`: current GitHub Pages SPA fallback. `public/spa-navigation.js` is queued #99 work and is **NOT AVAILABLE YET** on `main`.
- `public/404.html`, `public/index.html`, and `public/spa-navigation.js`: current same-origin GitHub Pages SPA callback bridge and its shared tested logic.
- `docs/`: historical/developer/content context.
- `docs/officers/`: current plain-language officer procedures, maps, continuity, and emergency guidance.

Expand All @@ -94,20 +94,18 @@ npm --prefix functions ci
npm --prefix functions run lint
npm --prefix functions run test:run -- --runInBand
CI=true npm test -- --watchAll=false --runInBand
npm run test:spa-navigation
npm run test:rules
CI=true DISABLE_ESLINT_PLUGIN=true npx --no-install react-scripts build
```

The Rules suite needs Java 17. The direct `react-scripts build` command is preferred for a diagnostic build because normal `npm run build` regenerates the sitemap. Run dependency audits for security/dependency issues, but do not apply forced automatic upgrades.

The following are **NOT AVAILABLE YET** on `main`:

- `npm run emulators` and fail-closed Auth/Firestore/Functions isolation — owned by #99.
- `npm run test:spa-navigation` — owned by #99.

The deterministic frontend Jest baseline is available through the command above. Hosted CI runs that command as the blocking `Run frontend Jest tests` step under #124. This proves the suite ran for that commit; it does not prove branch protection, website publication, Firebase deployment, provider configuration, or production behavior. The remaining fail-closed lint and deployment work stays open under #105.

Do not run Firebase-backed local development against the current production-configured client. Do not describe queued working-tree commands as merged or available.
For Firebase-backed local development, run `npm run emulators` first and wait until Auth, Firestore, and Functions are ready under `demo-mprc-local`. In a second terminal, run `npm start` and use `http://localhost:3000`. Stop if any browser Firebase request uses a non-loopback host. The emulator suite does not isolate Stripe, Strava, email, or other provider calls made by Functions; those flows remain forbidden until their test configuration and safe sink are separately proven.

Optimized builds and current deploy previews still use production Firebase configuration. Do not sign in, open private/admin pages, or exercise Firebase/provider behavior in a preview. Safe staging and provider isolation remain **NOT AVAILABLE YET** under #105/CONFIG.

For Stripe lifecycle work, tests must include relevant negative and retry cases: invalid signature, duplicate/out-of-order Event, unpaid completion, amount/currency/environment mismatch, terminal-state protection, async success/failure, expiration, cancellation, and refund retry. Capacity/inventory work must include concurrent final-unit tests.

Expand Down
73 changes: 47 additions & 26 deletions GITHUB_ISSUES.md

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions GITHUB_ISSUE_SLICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ An agent-ready child has one observable outcome, one trust boundary, explicit de
| ID | Status/dependency | Bounded deliverable | Close evidence |
| --- | --- | --- | --- |
| CI-001A | merged/closed as #103 | Repair Jest browser globals and replace the stale starter test with a deterministic, no-provider-network MPRC app smoke test. | Node 20 focused/full frontend tests, changed-file lint, clean diff, and diagnostic build pass. |
| CI-001B1 | published as #124; CI-001A | Run the complete committed frontend Jest suite as a named blocking step in the hosted frontend CI job; update exact officer/engineering truth. | Local Node 20 suite/build plus exact pull-request and post-merge hosted step evidence; no production/provider claim. |
| CI-001B1 | merged/closed as #124; CI-001A | Run the complete committed frontend Jest suite as a named blocking step in the hosted frontend CI job; update exact officer/engineering truth. | Exact pull-request and post-merge hosted steps passed; Firebase skipped and Netlify exact production commit remained unverified. |
| CI-001B1A | published as #126; #99 and CI-001B1 | Run the standalone same-origin SPA callback suite as a separate blocking hosted frontend step. | Local deliberate-failure proof plus the named hosted step passing on the exact pull-request and post-merge commits; no provider callback claim. |
| CI-001B2 | owner_action; CI-001B1 | Protect backend-first staging/production deployment; make lint/remaining checks fail closed; pin tools/Actions; remove frontend service-account JSON; configure OIDC/WIF, approvals, missing-config failure, smoke and roll-forward. | Required PR gate and negative credential run; private two-owner IAM review; staging deployment evidence. |
| SUPPLY-001A | ready; CI-001A | Prove `gpxparser` unused and remove its obsolete transitive chain. | `rg`/tree proof, before/after audits, root lockfile diff, full frontend checks. |
| SUPPLY-001B | ready; CI-001A | Patch React Router within compatible 6.x and resolve/test future flags without route redesign. | Navigation/callback tests, audit delta, build. |
Expand All @@ -37,7 +38,8 @@ An agent-ready child has one observable outcome, one trust boundary, explicit de
| AUTH-003D | proposed; AUTH-003B/C | Migrate admin UI/routes/token refresh, prove parity, then remove legacy alias. | Route/capability/demotion tests and staged operator sign-off. |
| OAUTH-001A | proposed; SEC-001, AUTH-003B | Implement server-only, transaction/version-safe Strava token refresh so rotated refresh tokens cannot be lost. | Concurrent refresh/retry/conflict emulator tests. |
| OAUTH-001B | owner_action; OAUTH-001A | Minimize scopes, implement disconnect/provider revocation, record encryption decision, and add access/refresh/revoke audit. | Test-provider revoke/refresh evidence and approved threat decision. |
| ABUSE-001A | ready; CI-001A | Replace custom fail-open App Check on an agreed sensitive-callable group with native runtime enforcement and explicit emulator behavior. | Missing/invalid/valid tests plus staged metrics before enforcement. |
| OAUTH-001C | proposed; #99 | Create a server-safe Strava callback handoff that keeps `code`/`state` out of third parties while allowing App Check-protected `stravaExchangeCode`; retain state verification and server-only token exchange. | Encoded/case/trailing callback tests, wrong/replayed state denial, missing/invalid/valid App Check tests, and test-provider-only exchange evidence. |
| ABUSE-001A | ready; CI-001A | Replace custom fail-open App Check on an agreed sensitive-callable group with native runtime enforcement and explicit emulator behavior. Inventory every callable; defer `lookupRegistration`/`lookupOrder` to DATA-001A and `stravaExchangeCode` to OAUTH-001C until safe handoffs merge. | Missing/invalid/valid tests plus staged metrics; source inventory test proves the three callback callables remain excluded until their dependency and regression evidence exist. |
| ABUSE-001B | proposed; PAY-001A | Replace raw IP/email rate keys with versioned HMAC, trusted address extraction, multi-scope transactional limits, rotation, and TTL-compatible records. | Spoof/boundary/concurrency/rotation tests; no raw identifiers. |
| ABUSE-001C | owner_action; A/B | Configure instance/concurrency/timeouts, budgets, TTL, and App Check/rate/cost alerts. | Synthetic alert and private cloud-setting review. |

Expand Down
6 changes: 3 additions & 3 deletions IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Exit gate:
- Unused vulnerable dependency chains are removed and direct safe patches applied.
- Live checkout remains disabled and placeholder policies are visible as a launch blocker.

**Assessment snapshot, not current `main`:** the combined working tree contains a locally verified SAFETY-001 candidate, but issue [#99](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/99) is queued behind #104. Until #99 is isolated, reviewed, merged, and reverified, callback/emulator behavior is **NOT AVAILABLE YET**.
**Current source boundary:** issue [#99](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/99) provides the isolated callback and local Firebase safety slice: a same-origin path/query/fragment bridge, a fully synthetic local Firebase namespace, loopback Auth/Firestore/Functions routing, fail-closed setup, and local monitoring shutdown. Its exact issue/PR record remains the status source. This does not create staging, isolate provider calls made by Functions, prove a production callback, or repair a member profile.

### Phase 1 — Establish trust boundaries

Expand Down Expand Up @@ -206,9 +206,9 @@ Use structured correlation across checkout request, business record, Stripe Sess

The first tranche deliberately combines one urgent safety repair with the most complex payment foundation:

1. **SAFETY-001 — callback and emulator isolation:** preserve path/query/hash through GitHub Pages and connect local Functions to the emulator. This prevents paid/OAuth callbacks from breaking and local code from reaching production unexpectedly.
1. **SAFETY-001 — callback and emulator isolation:** #99 supplies the source/test boundary for same-origin callback preservation and loopback Auth/Firestore/Functions development. Provider calls, optimized previews, staging, and live callbacks remain separately gated.
2. **PAY-003 — webhook event inbox and safe reducer:** add event replay protection, async-aware payment confirmation, expected total/currency validation, direct metadata lookup, terminal-state guards, and lifecycle tests.
3. **SEC-001 — Firestore trust boundaries:** remove recursive browser-admin authority, protect secrets/financial state, retain only allowlisted catalog administration, and reverse unsafe rule tests. This is implemented locally and awaits review/deployment evidence.
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:** disable promotion entry and quarantine unexplained discount/tax/shipping adjustments. This safety default is implemented locally; creator tests/provider inventory remain.
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. Continue CONFIG-001 and the uncompleted AUTH-001 guards/Rules/refresh/audit scope without duplicating #98.
6. **Then:** PAY-001/PAY-002 so checkout creation, refunds, and every later handler share strict schemas and idempotent state.
Expand Down
59 changes: 45 additions & 14 deletions OPERATIONS_RUNBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Maintain an internal inventory with project/account IDs and console links:

| Environment | Firebase project | Stripe mode/account | Web domain | GitHub environment | Status |
| --- | --- | --- | --- | --- | --- |
| Local | Emulator project ID | Test + Stripe CLI | `localhost:3000` | None | **NOT AVAILABLE YET** — blocked on #99 fail-closed emulator isolation |
| Local source runtime | `demo-mprc-local` emulators | Providers remain separately gated | `localhost:3000` | None | Available for synthetic Firebase work after all three loopback emulators report ready |
| CI | Demo/emulator project | Fixtures/test only | None | CI | Partially implemented |
| Staging | **Create dedicated project** | Test/sandbox + unique endpoint | `dev.runmprc.com` | `staging` | Launch blocker |
| Production | `mid-peninsula-running-club` (verify) | Live + unique endpoint | `runmprc.com` | `production` | Informational site only until gates close |
Expand Down Expand Up @@ -139,33 +139,61 @@ STRAVA_CLIENT_ID=test-or-development-id
STRAVA_CLIENT_SECRET=development-secret
```

### Start emulators and app — NOT AVAILABLE YET
### Start emulators and app — available for synthetic Firebase work

Issue [#99](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/99) owns the demo-project script, Auth/Firestore/Functions emulator wiring, local monitoring isolation, and fail-closed startup. Those changes exist only in queued working-tree work and are not part of the current `main` baseline.
**Purpose:** start the browser against the local Auth, Firestore, and Functions emulators without a production Firebase fallback.

Until #99 merges, do not start the app for Firebase-backed account, admin, member, event, shop, payment, or private-data testing. The current client can inherit production Firebase configuration. Historical commands are not a safe workaround.
1. Confirm the terminal is at the repository root.
2. Confirm Node.js 20 is active.
3. In terminal 1, run:

After #99 merges, replace this warning with the exact merged commands and proof. The finished procedure must confirm the demo project and all three emulator connections before test data is created.
```bash
npm run emulators
```

4. Wait for the CLI to name project `demo-mprc-local`.
5. Wait for Auth on `127.0.0.1:9099`.
6. Wait for Firestore on `127.0.0.1:8080`.
7. Wait for Functions on `127.0.0.1:5001`.
8. Stop if any emulator fails, uses another project, or reports a production resource.
9. In terminal 2, run:

```bash
npm start
```

### Forward Stripe events
10. Open only `http://localhost:3000`.
11. Use synthetic records only.
12. Stop if browser Firebase traffic uses a host other than `127.0.0.1` or `localhost`.

Use the Stripe CLI logged into the intended test workspace:
Expected result: the browser uses a fully synthetic Firebase configuration, Auth/Firestore/Functions use loopback, and App Check, Analytics, and Sentry remain off. A failed emulator-connection setup stops app initialization.

The CLI readiness messages prove the three processes listened during that run. Mocked frontend tests prove endpoint selection, not process readiness. If an emulator later stops, requests fail locally; do not change the project or disable the guard.

Optimized builds are different. Netlify previews and a locally served `build/` directory use `NODE_ENV=production` and currently target production Firebase. Use them only for public, read-only visual checks. Do not sign in or open account, member, admin, event-registration, shop-purchase, or provider flows.

### Forward Stripe events — NOT AVAILABLE YET for end-to-end use

Firebase emulation does not isolate Stripe, Strava, email, or any other provider called by a Function. Do not run provider-facing flows until the owning issue proves the correct test account/key, safe email sink, configuration fail-closed behavior, and synthetic fixtures.

When that gate is complete, the intended Stripe test-mode command is:

```bash
stripe listen --forward-to http://127.0.0.1:5001/demo-mprc-local/us-central1/stripeWebhook
```

Copy the CLI's temporary webhook signing secret only into the ignored local secret override. Do not use the Dashboard production endpoint secret locally.
Copy the CLI's temporary test webhook signing secret only into the ignored local secret override. Do not use a Dashboard production endpoint secret locally.

Trigger or complete test-mode Checkout through the application when testing end-to-end. Synthetic webhook triggers are useful for individual handlers but do not replace a real test Checkout flow with metadata and totals.
Do not trigger Checkout from the current app merely because the Firebase emulators are running. PAY/CONFIG/TEST issues own the later test-mode rehearsal.

### Local safety checks

- Browser/network calls target localhost for Auth, Firestore, and Functions.
- Stripe objects show test mode.
- The CLI names `demo-mprc-local` and all three expected loopback ports.
- Browser Firebase calls target only localhost/127.0.0.1.
- App Check, Analytics, and Sentry do not initialize locally.
- No production customer email, address, DOB, or emergency-contact data is copied into local Firestore.
- Email extension is disabled or points to a safe sink/test mailbox.
- Sentry and analytics use development environments or are disabled.
- No checkout, refund, email, Strava, or other provider flow runs until its separate test configuration and safe sink are proven.
- No optimized preview/build is used for sign-in or private/Firebase behavior.

## 6. Verification commands

Expand All @@ -175,9 +203,10 @@ Trigger or complete test-mode Checkout through the application when testing end-
npm --prefix functions run lint
npm --prefix functions run test:run -- --runInBand
CI=true npm test -- --watchAll=false --runInBand
npm run test:spa-navigation
```

The SPA navigation command is **NOT AVAILABLE YET** and belongs to #99. The frontend Jest command is a dependable local baseline and hosted CI runs it as the blocking `Run frontend Jest tests` step under [#124](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/124). Required branch protection, fail-closed lint, and protected deployment remain **NOT AVAILABLE YET** under [#105](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/105).
The frontend Jest command is a dependable local baseline and hosted CI runs it as the blocking `Run frontend Jest tests` step under [#124](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/124). The SPA command is a separate Node suite; hosted enforcement is still **NOT AVAILABLE YET** and belongs to [#126](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/126). Required branch protection, fail-closed lint, and protected deployment remain **NOT AVAILABLE YET** under [#105](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/105).

### Firestore Rules

Expand Down Expand Up @@ -467,4 +496,6 @@ On the isolated #103 branch based at `0e03ac1`, Node 20 focused App tests pass 1

Issue #124 adds that complete committed frontend suite to the hosted frontend job as the named, blocking `Run frontend Jest tests` step. Its pull-request and post-merge runs are the proof that the exact commits executed Jest. Even a green step does not prove branch protection, website publication, Firebase deployment, provider configuration, or production behavior.

On the isolated #99 branch rebased over #124, Node 20 local evidence is: 10/10 standalone SPA navigation/referrer-policy tests; 31/31 focused Firebase/monitoring tests; 4 frontend suites / 47 tests; 17/17 Functions tests; a clean diagnostic build; and a demo-only CLI smoke in which Auth, Firestore, and Functions listened on the three documented loopback ports. No browser account flow, production callback, Stripe/Strava/email call, Firebase deployment, or production data was used. The standalone SPA suite is not yet hosted under #124; #126 owns that separate check.

Provider configuration, production secrets, Netlify publication, Firebase deployment, and live behavior always require separate dated evidence. Local tests and a green GitHub summary do not prove them.
Loading
Loading