diff --git a/OPERATIONS_RUNBOOK.md b/OPERATIONS_RUNBOOK.md index c9a8765c..d492848f 100644 --- a/OPERATIONS_RUNBOOK.md +++ b/OPERATIONS_RUNBOOK.md @@ -522,4 +522,6 @@ On the isolated #99 branch rebased over #124, Node 20 local evidence is: 10/10 s The #134 remediation-ledger entry is source/test evidence only. For OBS-001A1 [#134](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/134) and [PR #137](https://github.com/Run-MPRC/Run-MPRC.github.io/pull/137), keep six evidence states separate: **source/tests** means the exact reviewed Sentry source plus mocked synthetic-canary results; **merge** means the resulting `main` SHA; **website** means a hosting publication record plus a separate check that `runmprc.com` serves that exact revision; **Firebase** is unchanged by this issue, so no Firebase deployment may be inferred; **Sentry provider** remains unverified for transport/ingestion, IP handling, retention, access, consent, deletion, and vendor terms; **live behavior** remains unverified unless an approved no-PII synthetic check proves the expected bounded event at the exact website revision. Never use member data or intentionally trigger an error in a real member flow. A green check, merged PR, preview, or website publication proves only its named surface and does not prove a later provider or live state. +For OBS-001A2 [#139](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/139), keep the same evidence discipline: **source/tests** means application runtime source and public HTML/JavaScript entrypoints contain no Firebase Analytics import, initialization, or emission and synthetic mocked/static tests pass; **merge** means the resulting `main` SHA; **website publication** means the exact revision has a hosting publication record; **`runmprc.com` verification** separately proves the live host serves that revision; **Firebase deployment** is unchanged and not required for this source-only issue; **Analytics provider configuration** remains unchanged and unverified for collection, cookies/storage, prior provider data, access, retention, consent, and deletion; **live network behavior** remains unverified until an approved public-page check at the exact website revision observes no Analytics request or cookie without signing in or using member data. Removing source calls does not delete provider history or browser storage. Do not use a production-configured preview for this 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. diff --git a/SECURITY.md b/SECURITY.md index 90537908..db13a598 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -102,7 +102,7 @@ These entries are implementation evidence, not a production risk-acceptance deci | RISK-013 | PROMO-001 sets both current Checkout creators to `allow_promotion_codes: false`; the webhook quarantines nonzero discounts plus unconfigured tax/shipping totals. | Add exact creator-payload tests, inventory pre-change Sessions/provider promotion configuration, keep the guard through staging/deploy, and implement an authoritative discount/tax/shipping contract before ever enabling it. | | Part of RISK-014 | SUPPLY-001A [#127](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/127) removes the unused direct `gpxparser` dependency and 50 lockfile entries without changing any retained package version, source URL, or integrity hash. A fresh Node 20 install lowers the root production audit from 33 findings (3 critical, 9 high) to 22 (1 critical, 8 high), and the optimized production asset hashes remain identical. | Remediate or time-bound the remaining root and Functions findings through the separately tested router, Firebase, Stripe, build-system, and scanning slices; do not use a forced audit upgrade. | | Part of RISK-024 | SEC-001 protects token documents from every browser client. | OAUTH-001 must still add transactional refresh/versioning, scope/account binding, disconnect/revocation, IAM/encryption decision, and redacted lifecycle audit. | -| Part of RISK-027 | #99 blocks App Check, Firebase Analytics, and Sentry in local/test and on initial capability-callback startup. OBS-001A1 [#134](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/134) source disables Sentry replay, tracing, browser session tracking, client reports, member user context, breadcrumbs, attachments, transactions, and unapproved default integrations. Its fail-closed allowlist retains only strictly validated non-content event metadata, generic exception types, and compiled-bundle path/line metadata; synthetic tests use a mocked Sentry client and make no provider call. | #111 still owns Firebase Analytics allowlisting and any residual hosted telemetry boundary. Source/tests and merge evidence do not prove website publication, the exact `runmprc.com` revision, Sentry transport/ingestion or provider IP handling, retention, access, consent, deletion, or vendor terms; verify those separately under #110. Callback protected handoffs remain with ABUSE-001A, DATA-001A, and OAUTH-001C in #88. | +| Part of RISK-027 | #99 blocks App Check, Firebase Analytics, and Sentry in local/test and on initial capability-callback startup. OBS-001A1 [#134](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/134) source disables Sentry replay, tracing, browser session tracking, client reports, member user context, breadcrumbs, attachments, transactions, and unapproved default integrations. OBS-001A2 [#139](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/139) source removes every application runtime Firebase Analytics import, initialization, and emission, preserves existing wrapper calls as provider-free no-ops, and removes the direct Waiver SDK bypass. Synthetic tests use mocks/canaries and scan CRA runtime source plus public HTML/JavaScript entrypoints; they make no provider call. | #110/#111 still own any future approved Analytics purpose, consent, event/parameter schema, provider settings, and residual hosted telemetry boundary. Source/tests and merge evidence do not prove website publication, the exact `runmprc.com` revision, provider transport/collection, IP/cookie behavior, historical data deletion, retention, access, consent, deletion, or vendor terms. Sentry provider behavior is likewise unverified. Callback protected handoffs remain with ABUSE-001A, DATA-001A, and OAUTH-001C in #88. | | Part of RISK-035 | The Jest environment is repaired, the stale frontend smoke test is replaced, #124 adds the complete frontend suite as a named blocking hosted step, and #126 adds the standalone SPA callback suite as its own named blocking step. | Keep exact hosted evidence on #124/#126; make lint non-mutating/fail-closed, prove required branch checks, and add the broader TEST-001 suite. | | RISK-026, RISK-036 | #135 merged through PR #138 as `9eafab1217aff7058c42240aaba72d7b93f8ed24`, replacing automatic frontend-first/fail-open GitHub deployment with a tested manual exact-current-commit gate. Post-merge staging and synthetic production probes failed closed before authentication or mutation, and published neither Firebase nor Pages. | #133 must configure protected environments and least-privilege OIDC/WIF; #136 must prove staged/target deployment and clearing/readback of the existing Pages `runmprc.com` claim; a protected WEB-001 child must establish Netlify publication and rollback. No Firebase, Pages, live-host, or provider-setting change is proven by source/static tests alone. | | RISK-039 | The #118 source slice uses an empty authenticated callable request, bounded Firebase Auth identity fields, one transactional create-only helper shared with signup, constant responses, generic failures, and a UI that hides Edit until setup and the Rules-protected read succeed. Signup and recovery never change custom claims; browser profile creation remains denied. | Source review/merge is not deployment. Under #105, deploy the exact #100 Rules plus both `createMemberOnSignUp` and `ensureMemberProfile` before the website, prove App Check policy, use a synthetic staged account, verify rollback, then record website, Function, Rules, and live behavior separately. Never repair a real profile manually. | diff --git a/SYSTEM_DESIGN.md b/SYSTEM_DESIGN.md index 8817370a..dd35c8f1 100644 --- a/SYSTEM_DESIGN.md +++ b/SYSTEM_DESIGN.md @@ -59,7 +59,7 @@ flowchart LR Mail["Firestore Email extension\nand mail provider"] Strava["Strava OAuth and API"] Sentry["Sentry"] - Analytics["Firebase Analytics"] + Analytics["Firebase Analytics\nNOT INITIALIZED in #139 source"] Visitor --> Web Admin --> Web @@ -73,9 +73,10 @@ flowchart LR FS --> Mail Fn --> Strava Web --> Sentry - Web --> Analytics ``` +Text alternative: browsers can use the React app, Auth, Firestore, Functions, Stripe, email, Strava, and the separately bounded Sentry path; #139 source has no browser-to-Firebase-Analytics data path, but website publication and provider behavior are not proven here. + ### Current component inventory | Layer | Current implementation | Primary locations | Assessment | @@ -87,7 +88,7 @@ flowchart LR | Payments | Stripe Checkout Sessions, Payment Links, refunds, signed webhook | `functions/createCheckoutSession.js`, `createMerchCheckout.js`, `stripeWebhook.js` | Not ready for live payments until P0 issues are complete. | | Hosting and release | Netlify currently answers `runmprc.com`. GitHub Pages still reports the same custom domain, so its default URL redirects to the Netlify-served name instead of providing an independent copy. #135 source stops automatic releases, pauses Git-triggered Netlify production builds, and removes the Pages CNAME from future protected artifacts. | `netlify.toml`, `.github/workflows/deploy.yml`, `public/404.html` | Split and conflicting as verified 2026-07-13. The existing Pages provider setting is not cleared until a controlled #136/WEB-001 release and readback prove it. #133 authority, #136 release evidence, Netlify provider triggers, DNS, headers, and rollback remain open. | | Email | Firestore `mail` outbox designed for the Firebase Trigger Email extension | `functions/sendConfirmationEmail.js` | Extension/provider deployment is unverified; outbox creation is not transactionally idempotent and HTML needs escaping. | -| Observability | Optional Sentry and Firebase Analytics | `src/services/monitoring`, `src/services/analytics` | Local/test initialization is disabled by #99 source. Hosted redaction, replay, consent, retention, and provider configuration remain unverified under #111. | +| Observability | Optional Sentry; Firebase Analytics configuration remains but its runtime is not initialized by #139 source | `src/services/monitoring`, `src/services/analytics` | #134 source bounds Sentry payloads. #139 source removes every application runtime Firebase Analytics import, initialization, and emission while preserving no-op call compatibility. Website publication, provider collection/cookies and historical data, consent, retention, access, deletion, and vendor configuration remain unverified under #110/#111. | | Third-party fitness | Strava OAuth tokens and statistics | `functions/strava.js`, `src/services/strava` | Functional prototype. The #100 source Rules deny browser token access, but Firebase deployment is unproven and transactional refresh, scopes/revocation, IAM/encryption decision, and audit remain OAUTH-001. | The former workflow automatically published Pages before attempting Firebase and could finish green after skipping Firebase. #135 replaces that source path with a manual exact-current-commit request, exact latest CI checks, one fixed backend plan, protected short-lived identity wiring, provider readback, and Firebase-before-Pages publication. Missing authority or failed/partial verification is red. Git-triggered Netlify production builds stop, while build hooks and protected Netlify publication remain unverified. No source test clears the current Pages custom-domain claim, configures #133, deploys #136, or proves `runmprc.com`; those remain separate provider states. The App Engine synchronization script is another surface that must be documented as active or retired. @@ -396,7 +397,7 @@ flowchart LR Text alternative: the local browser uses only the three loopback Firebase emulators. A Function can still call an outside provider, so Firebase emulator readiness alone does not authorize checkout, refund, email, or Strava testing. -#99 source selects a fully synthetic Firebase configuration for development/test, connects Auth, Firestore, and Functions to the loopback ports above, stops startup when connection setup fails, and leaves App Check, Analytics, and Sentry off locally. The Firebase CLI must still report all three emulators ready before the app is opened. Mocked endpoint tests alone do not prove listening processes. +#99 source selects a fully synthetic Firebase configuration for development/test, connects Auth, Firestore, and Functions to the loopback ports above, stops startup when connection setup fails, and leaves App Check, Analytics, and Sentry off locally. #139 additionally keeps Firebase Analytics off in every source environment and removes the direct Waiver SDK bypass pending an approved #110 policy. The Firebase CLI must still report all three emulators ready before the app is opened. Mocked endpoint tests alone do not prove listening processes, website publication, provider behavior, or deletion of earlier provider data/cookies. Optimized builds—including current Netlify previews and a locally served `build/` directory—use `NODE_ENV=production` and still target production Firebase. They are restricted to public, read-only visual review until #105/CONFIG establishes a separate staging configuration. Do not sign in, open private/admin pages, or test Firebase/provider actions in those previews. diff --git a/src/pages/joinUs/Waiver.jsx b/src/pages/joinUs/Waiver.jsx index 56096e44..6bd18e34 100644 --- a/src/pages/joinUs/Waiver.jsx +++ b/src/pages/joinUs/Waiver.jsx @@ -1,9 +1,7 @@ import React, { useState } from 'react'; import PropTypes from 'prop-types'; -import { logEvent } from 'firebase/analytics'; import FlexColumnContainer from '../../components/FlexColumnContainer'; import './waiver.css'; -import { useServiceLocator } from '../../services/ServiceLocatorContext'; import { WAIVER_FORM_LINK } from '../../text/externalLinks'; const WAIVER_INTRO = 'Regardless of membership, participants are required to read and complete the waiver form below before joining our runs.'; @@ -11,15 +9,8 @@ const WAIVER_TITLE = 'Club Activity Waiver'; function Waiver({ onWaiverSubmit }) { const [hasConfirmed, setHasConfirmed] = useState(false); - const { services } = useServiceLocator(); const handleContinue = () => { - const { analytics } = services?.firebaseResources || {}; - if (analytics) { - logEvent(analytics, 'signed_waiver', { - signed: true, - }); - } localStorage.setItem('waiverSigned', 'true'); onWaiverSubmit(); }; @@ -43,8 +34,9 @@ function Waiver({ onWaiverSubmit }) {
-