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
2 changes: 1 addition & 1 deletion .github/scripts/verify-firebase-release.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const FUNCTION_SPECS = Object.freeze({
});

const REGION = 'us-central1';
const RUNTIME = 'nodejs20';
const RUNTIME = 'nodejs22';
const FIRESTORE_RELEASE_REQUEST = 'cloud.firestore/(default)';
const FIRESTORE_RELEASE_CANONICAL = 'cloud.firestore';
const PROJECT_PATTERN = /^[a-z][a-z0-9-]{4,28}[a-z0-9]$/;
Expand Down
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,37 @@ jobs:
# firebase-admin so no emulator is needed.
- run: npm run test:run

functions-node22:
name: Node 22 backend compatibility
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
- name: Install committed root dependencies
run: npm ci --legacy-peer-deps --ignore-scripts
- name: Install committed Functions dependencies
run: npm --prefix functions ci --ignore-scripts
- name: Run Node 22 backend tests with profile persistence
env:
REQUIRE_MEMBER_PROFILE_EMULATOR: '1'
run: >-
npx --no-install firebase emulators:exec
--project demo-functions-test
--only firestore,auth
"npm --prefix functions run test:run -- --runInBand"

commerce-command-journal:
name: Commerce command journal emulator
runs-on: ubuntu-latest
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ jobs:
for required_job in \
"Frontend lint + build" \
"Cloud Functions lint + test" \
"Node 22 backend compatibility" \
"Commerce command journal emulator" \
"Test artifact scrubber" \
"Firestore security-rules tests"
Expand Down Expand Up @@ -290,7 +291,7 @@ jobs:
- name: Set up locked Node runtime
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: '20'
node-version: '22'
cache: npm
cache-dependency-path: |
package-lock.json
Expand Down Expand Up @@ -402,6 +403,7 @@ jobs:
for required_job in \
"Frontend lint + build" \
"Cloud Functions lint + test" \
"Node 22 backend compatibility" \
"Commerce command journal emulator" \
"Test artifact scrubber" \
"Firestore security-rules tests"
Expand Down
12 changes: 12 additions & 0 deletions GITHUB_ISSUES.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ Published foundation mapping:

Before creating or claiming anything from this catalog, search GitHub, confirm the predecessor is merged, then follow the timestamped claim protocol in the live issue.

## Current runtime prerequisite

RUNTIME-001 [#691](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/691) prepares the initial profile backend for Node 22. Scope: Functions engine and lock metadata; exact staging guard/provider readback; a required sixth CI job; backend builder runtime; a fixed immutable redacted error stack; and officer handoff. Existing Node 20 checks, first-generation triggers, schema, auth, create-once semantics, two-Function scope, and #683 limits stay unchanged. No dependency versions or migrations change. #113/#133/#136, billing, hosted checks, and existing security advisories remain open; this is not a release or runner-matching activation. GitHub holds exact review/merge/CI evidence.

Officer impact: no website or account behavior changes until a separately approved deployment.

Officer documentation: `OFFICER_START_HERE.md`, `docs/officers/README.md`, `docs/officers/LOW_COST_COMMUNITY.md`, and `docs/officers/PUBLISH_AND_CHECK.md` distinguish runtime source preparation from hosted proof and explain the supported-runtime undo requirement.

Deployment evidence: source/test work only; no website publication, `runmprc.com` change, Firebase deployment, provider configuration, or production behavior verification in #691.

The 2026-09-27 production-dependency audit remains nonzero: root 5 findings (1 low, 2 moderate, 2 high: `browserslist`/`minimatch`); Functions 12 (11 moderate, 1 high: `sharp`). The lockfile differs only in the root engine field; no dependency finding is fixed or accepted as safe by this runtime update.

## Backlog conventions

### Labels
Expand Down
4 changes: 4 additions & 0 deletions IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

This plan turns the target architecture into a dependency-ordered delivery program. It is deliberately staged: payment correctness and trust boundaries come before features, and a controlled pilot comes before a broad launch.

### Initial profile release runtime prerequisite

RUNTIME-001 [#691](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/691) prepares Node 22 before the two-Function profile release under #136. Keep the five existing Node 20 checks and require a sixth, separate Node 22 backend/profile-emulator job in both protected-release CI checks. Match manifest, lock metadata, deployment builder, and provider runtime readback. Preserve CommonJS, first-generation triggers, create-once behavior, schema, and #683 resource limits; no backfill is needed. A fixed immutable error stack is the only backend logic adaptation. Node 22 source and passing synthetic tests do not resolve billing, #113 estate disposition, #133 authority, hosted behavior, or existing dependency advisories. Do not merge or deploy runner matching as part of this runtime prerequisite.

## 1. Program outcome

MPRC can open a race or merchandise item for sale only when the platform can:
Expand Down
2 changes: 2 additions & 0 deletions OFFICER_START_HERE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

Attach the exact wording, public link, or approved photo when you have it. The AI should ask questions if anything is unclear.

**Backend maintenance, 2026-09-27:** [#691](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/691) prepares a supported server runtime, Node 22, in source. It does not publish a website, deploy Functions, or add billing. The first backend release is still on hold. Follow the [low-cost review](./docs/officers/LOW_COST_COMMUNITY.md) and ask a maintainer for separate hosted proof; no officer terminal work is needed.

## Choose the closest task

| What you need | Open this short guide |
Expand Down
8 changes: 8 additions & 0 deletions OPERATIONS_RUNBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ This runbook explains how to operate the website, Firebase services, and Stripe

Club officers and backup maintainers should start with [OFFICER_START_HERE.md](./OFFICER_START_HERE.md). It converts this technical runbook into short request, approval, verification, access, and emergency steps without terminal commands.

### Node 22 profile release prerequisite — hosted behavior NOT AVAILABLE YET

RUNTIME-001 [#691](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/691) changes source runtime selection, not a hosted service. The protected backend builder uses Node 22; frontend and baseline CI remain Node 20. Both pre-approval and post-approval checks require all six named jobs, including `Node 22 backend compatibility`. That job requires local Auth and Firestore and runs the profile create-once persistence test; it does not prove hosted Auth or App Check.

Before any approved #136 release, the platform maintainer must obtain exact-main CI, the named environment approval, private billing/cost-control decisions, #113/#133 evidence, and a compatible rollback or roll-forward. Deploy only the two profile Functions and the separately reviewed Rules scope. Read back `nodejs22` on both Functions plus min 0/max 2/256 MB/30 seconds; then perform the approved synthetic hosted checks. Do not use Node 20 as an assumed fallback after Google's scheduled October 30, 2026 decommissioning. No package versions, trigger generation, data format, or migration changes are included here. Officers use the [low-cost review](./docs/officers/LOW_COST_COMMUNITY.md), not terminal commands.

Read-only check on 2026-09-27: `runmprc@gmail.com` could access zero billing accounts; staging billing remained disabled, and Functions, Cloud Build, and Artifact Registry APIs remained disabled. No billing, IAM, API, hosted runtime, website, or production behavior was changed by #691.

## 1. Ownership roster

Complete this table in the private operations system before live payments. Do not put personal phone numbers or recovery codes in this public repository.
Expand Down
6 changes: 6 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ This is both the repository security policy and the current engineering risk reg

The public informational website can continue operating with normal care. **Live race or merchandise payments should remain disabled until every P0 launch blocker below is closed and verified in a staging dress rehearsal.** The existing payment implementation is a useful prototype, but several correctness defects could mark unpaid transactions paid, lose payment callbacks, oversell race capacity, fail to reconcile late-payment links, or allow overly broad administrative access.

### Runtime prerequisite — source only, 2026-09-27

RUNTIME-001 [#691](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/691) targets Node.js 22 without changing first-generation triggers, permissions, profile schema, deployment scope, or resource limits. [Google schedules Node 20 decommissioning for October 30, 2026](https://docs.cloud.google.com/functions/docs/runtime-support). Both protected-release CI reads now require the separate Node 22 backend/profile-persistence job, and provider verification rejects either profile Function unless its runtime is exactly `nodejs22`. The original Node 20 baseline checks remain required.

The dual-runtime run exposed a Node 22 error-stack accessor that remained writable despite `Object.freeze`. The unused Checkout observation projector now replaces that accessor with a fixed non-enumerable, non-writable data property before freezing; the regression test also rejects a stack-formatting hook. No raw provider value or stack frame is retained in that diagnostic. Existing malformed-input, proxy/getter, no-output, and redaction tests remain intact. This is runtime compatibility, not payment activation or a dependency-audit fix. #113/#133/#136, existing dependency findings, and hosted verification remain separate release gates.

## 2. Reporting a vulnerability

Do not disclose a suspected vulnerability, secret, customer record, payment reference, or exploit in a public GitHub issue. Until MPRC publishes a dedicated security address:
Expand Down
6 changes: 4 additions & 2 deletions SYSTEM_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ The owner requests a simpler, low-cost community experience and is willing to su

COST-001 [#683](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/683) explicitly binds both profile Functions to zero reserved instances, maximum two instances each, 256 MB memory and a 30-second execution timeout. The release verifier requires matching provider readback. It records the v1 API's documented omitted-zero encoding for minimum instances; missing nonzero settings and malformed evidence remain unverified. Source and tests do not make these settings live or guarantee a bill ceiling. Cold-start, saturation, uncertain-timeout/retry and public-page availability checks remain required before release. The [officer guide](./docs/officers/LOW_COST_COMMUNITY.md) records scope, cost-control limits, proof, and recovery. Node runtime maintenance and existing provider/release gates remain open; no schema, role, price, domain, or deployed service changes in this slice.

RUNTIME-001 [#691](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/691) prepares Node.js 22 in the Functions manifest and lock metadata, staging source guard, backend release builder, and provider verifier. First-generation triggers, names, schema, authorization, create-once semantics, and all four COST-001 limits are unchanged. Existing Node 20 CI remains the baseline; a separate required Node 22 job exercises the backend and synthetic profile persistence. The immutable redacted Checkout observation error now uses a fixed stack data property because Node 22 otherwise leaves a mutable stack setter on frozen errors. This changes no checkout decision or provider call. No dependency version, billing, IAM, API, deployment, or data migration changes are included; hosted runtime and service quality remain unverified.

### Goals

- Publish public club content, events, and merchandise.
Expand Down Expand Up @@ -59,7 +61,7 @@ flowchart LR
Web["React single-page app\nNetlify live; Pages domain conflict unresolved"]
Auth["Firebase Authentication"]
FS["Cloud Firestore"]
Fn["Firebase Cloud Functions\nNode.js 20"]
Fn["Firebase Cloud Functions\nNode.js 22 source; hosted runtime unverified"]
Stripe["Stripe-hosted Checkout\nand Stripe API"]
Hook["Stripe webhook endpoint"]
Mail["Firestore Email extension\nand mail provider"]
Expand All @@ -81,7 +83,7 @@ flowchart LR
Web --> Sentry
```

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.
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. Functions source targets Node 22, but website publication, hosted runtime, and provider behavior are not proven here.

### Current component inventory

Expand Down
15 changes: 9 additions & 6 deletions docs/officers/LOW_COST_COMMUNITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

**Approver:** Dave Liu for the current simplification request. Any release still uses the named platform/security reviewers. Regular club expenditure needs the club's finance approval; willingness to supply a personal card is not an unlimited club budget.

**Checked:** 2026-09-11. This is a scope and source-review guide, not proof that the new settings are live.
**Checked:** 2026-09-27. This is a scope and source-review guide, not proof that the new settings are live.

## What we are prioritizing

Expand All @@ -31,11 +31,13 @@ The first profile backend remains exactly two server operations: create a missin

These are resource settings, **not a maximum monthly bill**. Google can briefly exceed the instance limit during traffic surges. A busy HTTP operation can queue requests and return a temporary busy response. Persistent storage, deployment files, database use, and other services can still cost money. The profile remains create-once so retrying an uncertain result does not overwrite existing information or grant membership.

No budget, spending cap, artifact-cleanup policy, billing account, Function, or new host is configured by this source change. Billing was separately checked as disabled/unlinked on 2026-09-11. A personal card has been offered as fallback; card details belong only in Google's secure payment form.
No budget, spending cap, artifact-cleanup policy, billing account, Function, or new host is configured by this source change. Billing was separately checked as disabled/unlinked on 2026-09-27; the club account could access zero billing accounts. A personal card has been offered as fallback; card details belong only in Google's secure payment form.

[Issue #691](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/691) prepares Node 22, the program that runs the server code. Google schedules the old Node 20 runtime to be taken out of service on October 30, 2026. The update keeps the same two operations and resource limits. It adds automated compatibility and made-up profile checks, but does not deploy anything or fix every dependency warning. Hosted Node 22 behavior is **NOT AVAILABLE YET**.

## Review before a low-cost release

**Prerequisites:** issue #683 and its reviewed pull request; the exact release source and test results; a named release approver; a private billing/payment-owner decision; and a platform maintainer. The existing release dependencies still apply. Never put payment details, passwords, or member records in an issue.
**Prerequisites:** issues #683 and #691 and their reviewed pull requests; the exact release source and test results; a named release approver; a private billing/payment-owner decision; and a platform maintainer. The existing release dependencies still apply. Never put payment details, passwords, or member records in an issue.

```mermaid
flowchart LR
Expand All @@ -51,8 +53,8 @@ Text alternative: confirm the small scope, review source, verify provider contro

1. Confirm the public pages to keep and the two profile operations to deploy.
2. Confirm the release adds no payment, email, photo, or synchronization service.
3. Ask the maintainer for the exact merged source and passing tests.
4. Ask for separate provider evidence of all four resource settings on each Function. Google may leave out a zero minimum-instance value; the maintainer must show that this was decoded using Google's documented format. Other missing or malformed settings are not proof of safe defaults.
3. Ask the maintainer for the exact merged source and all six passing checks, including “Node 22 backend compatibility.”
4. Ask for separate provider evidence of Node 22 and all four resource settings on each Function. Google may leave out a zero minimum-instance value; the maintainer must show that this was decoded using Google's documented format. Other missing or malformed settings are not proof of safe defaults.
5. Ask for the agreed alert recipients and budget amount. Alerts do not stop charges.
6. Ask whether a service spending cap is available and configured. It does not guarantee a whole-project bill ceiling or instant shutdown.
7. Ask for deployment-file cleanup and storage-retention evidence. Do not delete database backups as a cost shortcut.
Expand All @@ -66,12 +68,13 @@ Text alternative: confirm the small scope, review source, verify provider contro

**Success proof:** a reviewed source/CI record plus separate provider readback and synthetic quality evidence. Source tests alone cannot prove lower bills or a good hosted experience.

**Undo:** before release, hold the change. After release, ask the platform maintainer to use the reviewed compatible rollback or safe roll-forward. Reverting the limits can raise spending exposure and requires review. Do not edit a profile, widen permissions, switch off billing, or delete resources as an improvised fix.
**Undo:** before release, hold the change. After release, ask the platform maintainer to use the reviewed compatible rollback or safe roll-forward on a supported runtime. Do not assume the old Node 20 version can be redeployed after its retirement date. Reverting the limits can raise spending exposure and requires review. Do not edit a profile, widen permissions, switch off billing, or delete resources as an improvised fix.

**Escalation:** platform/security owner for reliability or access; treasurer/finance approver for recurring club costs; cardholder for payment authority. A specialist is still needed for provider setup, release, and rollback. This guide does not claim independent officer deployment is available.

## References

- [Google's server runtime support dates](https://docs.cloud.google.com/functions/docs/runtime-support)
- [Firebase resource settings and saturation behavior](https://firebase.google.com/docs/functions/1st-gen/manage-functions-1st)
- [Google maximum-instance caveat](https://docs.cloud.google.com/functions/docs/reference/rest/v1/projects.locations.functions)
- [Google's zero-value response format](https://protobuf.dev/programming-guides/json/#presence-and-default-values)
Expand Down
Loading
Loading