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
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ npm ci --legacy-peer-deps
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:rules
CI=true DISABLE_ESLINT_PLUGIN=true npx --no-install react-scripts build
```
Expand All @@ -103,7 +104,8 @@ 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.
- A trustworthy frontend Jest baseline/quality gate — owned by #103.

The deterministic frontend Jest baseline is available through the command above. It is not yet a required CI quality gate; workflow enforcement remains **NOT AVAILABLE YET** 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.

Expand Down
4 changes: 2 additions & 2 deletions GITHUB_ISSUES.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ Do not redesign routing or hosting in this issue; WEB-001 owns that. Do not incl
## CI-001 — Repair test gates and secure the deployment pipeline

**Labels:** `priority:P0`, `type:security`, `type:testing`, `area:ci`, `size:L`, `needs-external-config`
**Status:** Published as tracker [#105](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/105); CI-001A [#103](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/103) is claimed and queued. The current workflow remains non-compliant.
**Status:** Published as tracker [#105](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/105); focused child [#103](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/103) owns the deterministic local frontend Jest baseline. The live issue records its merge state. Required workflow gating and protected deployment remain open under #105, so the current workflow is still non-compliant.
**Depends on:** SAFETY-001

### Problem

Frontend tests fail because the Jest environment lacks `TextEncoder`. CI runs a mutating `lint:fix` command and ignores failure with `|| true`. Deployment runs independently of CI, gives a full Firebase service-account JSON to the frontend build, installs `firebase-tools@latest`, deploys frontend before backend, and can succeed while silently skipping Firebase deployment.
Before #103, frontend tests failed because the Jest environment lacked `TextEncoder`. The focused child repairs that local baseline, but CI still runs a mutating `lint:fix` command, ignores failure with `|| true`, and does not require frontend Jest. Deployment runs independently of CI, gives a full Firebase service-account JSON to the frontend build, installs `firebase-tools@latest`, deploys frontend before backend, and can succeed while silently skipping Firebase deployment.

### Scope

Expand Down
2 changes: 1 addition & 1 deletion GITHUB_ISSUE_SLICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ An agent-ready child has one observable outcome, one trust boundary, explicit de

| ID | Status/dependency | Bounded deliverable | Close evidence |
| --- | --- | --- | --- |
| CI-001A | ready; SAFETY-001 | Add non-mutating fail-closed frontend lint and one deterministic local/CI quality gate for SPA, frontend, Functions, Rules, and build. | Deliberate lint/test failure blocks; clean-worktree check; all local suites pass. |
| CI-001A | published as #103; local baseline slice | Repair Jest browser globals and replace the stale starter test with a deterministic, no-provider-network MPRC app smoke test. Required workflow gating remains under #105. | Node 20 focused/full frontend tests, changed-file lint, clean diff, and diagnostic build pass; do not claim a required CI gate. |
| CI-001B | owner_action; CI-001A | Protect backend-first staging/production deployment; pin tools/Actions; remove frontend service-account JSON; configure OIDC/WIF, approvals, missing-config failure, smoke and roll-forward. | 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 Down
7 changes: 5 additions & 2 deletions OPERATIONS_RUNBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,10 @@ Trigger or complete test-mode Checkout through the application when testing end-
```bash
npm --prefix functions run lint
npm --prefix functions run test:run -- --runInBand
CI=true npm test -- --watchAll=false --runInBand
```

The SPA navigation command is **NOT AVAILABLE YET** and belongs to #99. A dependable frontend Jest baseline/quality gate is **NOT AVAILABLE YET** and belongs to [#103](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/103).
The SPA navigation command is **NOT AVAILABLE YET** and belongs to #99. The frontend Jest command is a dependable local baseline, but a required CI quality gate is **NOT AVAILABLE YET** and remains under [#105](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/105).

### Firestore Rules

Expand Down Expand Up @@ -460,6 +461,8 @@ The earlier combined pre-extraction working tree reported 7 frontend tests, 4 SP

Each isolated issue must publish its own exact base commit, commands, counts, and results. A documentation-only #104 branch starts from `main` with the merged #98 role-grant behavior; it must not claim the queued emulator, webhook, Rules, or frontend-test outcomes.

On the isolated #104 branch based at `ce22c110`, Functions lint and 17/17 Functions tests pass, 97/97 Firestore Rules tests pass with Java 17, and the diagnostic production build passes. Frontend Jest runs 15 Login tests but the App suite fails on the known missing `TextEncoder`; #103 owns that baseline repair. These are branch checks, not deployment evidence.
On the isolated #104 branch based at `ce22c110`, Functions lint and 17/17 Functions tests pass, 97/97 Firestore Rules tests pass with Java 17, and the diagnostic production build passes. At that point, frontend Jest ran 15 Login tests but the App suite failed on the known missing `TextEncoder`. These are historical branch checks, not deployment evidence.

On the isolated #103 branch based at `0e03ac1`, Node 20 focused App tests pass 1/1 and the complete frontend suite on the branch passes 16/16. Changed-file lint, diff checks, and the diagnostic production build also pass. Service initialization and provider-network paths are prevented by test mocks; this was not a socket-monitored provider test, and the separately owned #99 Firebase/Sentry tests are not present on the branch. A separate read-only Node 20 compatibility run against the preserved #99 working tree passed those two suites 6/6, but that is not #103 branch or merge coverage. This proves a deterministic local baseline only. It does not prove a required CI gate, website publication, Firebase deployment, provider configuration, or production behavior.

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.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,12 @@ After #99 merges, the runbook and this section must be updated from its merged t
```bash
npm --prefix functions run lint
npm --prefix functions run test:run -- --runInBand
CI=true npm test -- --watchAll=false --runInBand
npm run test:rules
CI=true DISABLE_ESLINT_PLUGIN=true npx --no-install react-scripts build
```

Rules tests require Java 17. The direct `react-scripts build` command is useful for a diagnostic compile because the normal `npm run build` runs the sitemap generator and may intentionally update `public/sitemap.xml`. The SPA navigation command belongs to queued #99, and a trustworthy frontend Jest baseline belongs to queued [#103](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/103); do not claim either from this documentation pull request.
Rules tests require Java 17. The direct `react-scripts build` command is useful for a diagnostic compile because the normal `npm run build` runs the sitemap generator and may intentionally update `public/sitemap.xml`. The SPA navigation command remains queued under #99. The frontend Jest command now provides a deterministic local baseline, but current CI does not run it as a required gate; [#105](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/105) owns that remaining workflow work.

## Working on the platform

Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ The findings below describe the repository at the start of the 2026-07-12 assess
| RISK-032 | `auditLog` arrays grow within primary documents and are editable by broad admins. | Move to append-oriented, immutable-by-client audit records with retention/export rules. |
| RISK-033 | CSV export mitigates formula injection, but roster export has no explicit re-auth, download audit, row limit/streaming limit, or data-minimization profiles. | Add scoped exports, reason/re-auth, audit, minimum columns, safe filename IDs, and large-export controls. |
| RISK-034 | Webhook error response includes the Stripe library's signature error detail. | Return generic client errors; keep sanitized structured diagnostics server-side. |
| RISK-035 | Frontend tests currently fail because `TextEncoder` is absent in Jest; CI's frontend lint step is allowed to fail with `|| true`; Functions have only seven unit tests and about 20% line coverage. | Repair the harness, make non-mutating lint/test gates mandatory, and add domain/integration coverage. |
| RISK-035 | The local frontend Jest baseline is deterministic, but CI does not run it as a required gate; CI's frontend lint step is still allowed to fail with `|| true`, and broader domain/integration coverage remains incomplete. | Make non-mutating lint/test gates mandatory and add domain/integration coverage. |
| RISK-036 | Production and staging deployment topology is inconsistent in docs/workflows; backend deploy follows frontend and can silently skip when a secret is absent. | Define environment-protected deployments, deploy compatible backend first, fail required production stages closed, and add rollback evidence. |
| RISK-037 | Account/registration deletion, export, retention, backup, and restore procedures are incomplete. | Approve retention matrix, automate minimization, support access/deletion requests, and test backup restoration. |
| RISK-038 | Source-controlled secret scan is ad hoc; no continuous secret scanner, dependency update bot, SBOM, provenance, or branch protection is documented. | Add secret/dependency/code scanning, reviewed lockfile updates, protected environments/branches, and artifact provenance appropriate to project scale. |
Expand Down
38 changes: 35 additions & 3 deletions src/App.test.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,41 @@
/* eslint-env jest */

import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
jest.mock('./services/ServiceLocatorProvider', () => function TestServiceLocatorProvider({
children,
}) {
return children;
});

jest.mock('./services/ServiceLocatorContext', () => ({
useServiceLocator: () => ({ services: null, isReady: false }),
}));

jest.mock('./services/hooks/useAuth', () => ({
useAuth: () => ({
user: null,
isLoading: false,
isAuthenticated: false,
isMember: false,
isAdmin: false,
signIn: jest.fn(),
signOut: jest.fn(),
register: jest.fn(),
}),
}));

test('renders the MPRC home route without contacting Firebase', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
expect(screen.getByRole('heading', {
level: 1,
name: /mid-peninsula running club/i,
})).toBeInTheDocument();
expect(screen.getByRole('link', { name: /skip to content/i })).toHaveAttribute(
'href',
'#main-content',
);
expect(screen.getByRole('main')).toHaveAttribute('id', 'main-content');
});
22 changes: 22 additions & 0 deletions src/setupTests.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
/* eslint-env jest */

// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

// Firebase Functions' Node test bundle pulls in undici, which expects the Web
// Encoding globals that Jest's jsdom environment does not provide by default.
// Use Node's standards-compatible implementations in tests only.
const { TextDecoder, TextEncoder } = require('util');
const {
ReadableStream,
TransformStream,
WritableStream,
} = require('stream/web');

global.TextDecoder = TextDecoder;
global.TextEncoder = TextEncoder;
global.ReadableStream = ReadableStream;
global.TransformStream = TransformStream;
global.WritableStream = WritableStream;

// jsdom does not implement scrolling. App smoke tests need a harmless test-only
// shim because ScrollToTop invokes this API after route changes.
global.scrollTo = jest.fn();
Loading