diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md index 80fbac7..fe4bdcd 100644 --- a/IMPLEMENTATION_PLAN.md +++ b/IMPLEMENTATION_PLAN.md @@ -28,7 +28,7 @@ MPRC can open a race or merchandise item for sale only when the platform can: 3. Schema changes are additive first. Backfills are idempotent, dry-runnable, and report counts/anomalies. 4. Backend/rules/indexes deploy before dependent clients. Legacy reads remain until migration evidence is complete. 5. No issue requires production secrets for development or CI. -6. Live-mode enabling is a separate protected operation. #135 supplies a manual, exact-commit, backend-first source gate and pauses ordinary Git-triggered Netlify production builds. WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) is a temporary web-only exception that requires one exact `main` parent and independently verifies one pinned source commit/tree; it must be disabled after verification and does not authorize Firebase, commerce, or a reusable release path. Protected environment/OIDC configuration, staged/live proof, fail-closed lint, required checks, and a protected live-Netlify path remain open under #105/#133/#136/WEB-001. +6. Live-mode enabling is a separate protected operation. #135 supplies a manual, exact-commit, backend-first source gate and pauses ordinary Git-triggered Netlify production builds. WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) used one temporary web-only exception that required one exact `main` parent and independently verified one pinned source commit/tree. After dated live verification, its manifest was disabled and its release source retired. It did not authorize Firebase, commerce, or a reusable release path. Protected environment/OIDC configuration, staged/live proof, fail-closed lint, required checks, and a protected live-Netlify path remain open under #105/#133/#136/WEB-001. 7. A provider Console setting is not complete until its non-secret configuration and verification evidence are recorded privately. 8. Security controls fail closed in hosted environments and remain developer-friendly only in explicit local/CI environments. 9. Do not trade payment integrity for UI responsiveness. Confirmation may say “processing”; it must not guess “paid.” diff --git a/OFFICER_START_HERE.md b/OFFICER_START_HERE.md index 3e5bb09..1d2259d 100644 --- a/OFFICER_START_HERE.md +++ b/OFFICER_START_HERE.md @@ -46,6 +46,6 @@ Use the club's approved password manager for access. Share only a public link or - **Website live:** Did Netlify identify that commit, and was the exact change then seen on [runmprc.com](https://runmprc.com)? - **Outside service verified:** If Stripe, Netlify, DNS, Google, or email changed, was that service checked separately? -As of **2026-07-22**, a merge runs checks but does not start the GitHub release. The protected release is **NOT AVAILABLE YET** until its short-lived cloud identity and named environment approvers are configured under issue #133. Ordinary Git-triggered Netlify production builds are paused. Issue #457 has one temporary platform-maintainer-only exception for its already reviewed page-header artifact; every other source, merge, and service remains blocked, and the exception must be disabled and its release source retired after live verification. This does not deploy Firebase or make commerce safe. GitHub Pages still reports `runmprc.com` as its custom domain even though Netlify serves that name; source removal is not provider proof. A green test or workflow does **not** by itself prove that GitHub Pages, `runmprc.com`, Firebase, or that domain setting changed. +As of **2026-07-23**, a merge runs checks but does not start the GitHub release. The protected release is **NOT AVAILABLE YET** until its short-lived cloud identity and named environment approvers are configured under issue #133. Ordinary Git-triggered Netlify production builds are paused. Issue #457 used one platform-maintainer-only exception for its reviewed page-header artifact; the manifest is now inactive and the release source is retired. The exact rollback source remains available to the platform owner. This did not deploy Firebase or make commerce safe. GitHub Pages still reports `runmprc.com` as its custom domain even though Netlify serves that name; source removal is not provider proof. A green test or workflow does **not** by itself prove that GitHub Pages, `runmprc.com`, Firebase, or that domain setting changed. For the concise handbook, see [OFFICER_HANDBOOK.md](./OFFICER_HANDBOOK.md). The expanded task index is [docs/officers/README.md](./docs/officers/README.md). diff --git a/OPERATIONS_RUNBOOK.md b/OPERATIONS_RUNBOOK.md index b2bb880..9d43a53 100644 --- a/OPERATIONS_RUNBOOK.md +++ b/OPERATIONS_RUNBOOK.md @@ -642,10 +642,12 @@ For expand-and-contract changes: The GitHub release workflow is now manual and exact-current-commit. After protected approval it rechecks `main`, the newest exact CI run, and the retained credential-free artifact before cloud authentication. It fails on missing protected configuration, uses a lockfile Firebase CLI, verifies reviewed Rules and two named profile Functions before publishing the Pages branch, and never gives cloud authority to website preparation or publication. Future Pages artifacts omit the `runmprc.com` CNAME, but the existing Pages provider setting still claims that Netlify-served name until #136/WEB-001 publish and read it back. The source gate is not usable until #133 configures protected environments/OIDC. It does not publish the live Netlify host. Treat the full pipeline as incomplete until #105 closes. -WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) uses a separate temporary **web-only** Netlify release. Its active manifest names the expected first parent of one `main` merge, release-specific source ref, exact reviewed source commit/tree, exact artifact file count/digest, and known rollback deploy. The release-control Deploy Preview and production both build that pinned source. Netlify continues production only for the exact-parent merge, fetches the public ref into a fresh temporary Git repository with provider/global Git configuration disabled, verifies both source hashes, installs the pinned lockfile with lifecycle scripts disabled, builds without the data-dependent sitemap prebuild or any React/provider variables, scans the output for credential markers, verifies the exact artifact digest, and publishes a public provenance marker. A wrong/missing context, branch, commit, parent, ref, tree, artifact, canonical manifest, build-hook marker, or inactive manifest stops without replacing the live deploy. This path changes no Firebase, Rules, Functions, provider configuration, or production data and does not complete WEB-001. +WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) used a separate temporary **web-only** Netlify release. Its manifest named the expected first parent of one `main` merge, release-specific source ref, exact reviewed source commit/tree, exact artifact file count/digest, and known rollback deploy. The release-control Deploy Preview and production both built that pinned source. Netlify continued production only for the exact-parent merge, fetched the public ref into a fresh temporary Git repository with provider/global Git configuration disabled, verified both source hashes, installed the pinned lockfile with lifecycle scripts disabled, built without the data-dependent sitemap prebuild or any React/provider variables, scanned the output for credential markers, verified the exact artifact digest, and published a public provenance marker. A wrong/missing context, branch, commit, parent, ref, tree, artifact, canonical manifest, build-hook marker, or inactive manifest stops without replacing the live deploy. This path changed no Firebase, Rules, Functions, provider configuration, or production data and did not complete WEB-001. For #457, prepare the manifest-disable pull request and exact previous-source Git rollback projection before merging the release. The current Git/Netlify identity cannot select Netlify's atomic restore control; a Netlify team owner remains the preferred fast rollback, while the pre-reviewed Git projection pinned to `e86a0f702cff6495f50630c5de3337290db8b8cb` is the available slower fallback. Freeze unrelated `main` merges until the Netlify deploy and public smoke checks finish, because a later merge invalidates the exact-parent gate and may supersede the provider build. Verify the pinned Deploy Preview marker and artifact digest before merge; after merge verify `/.well-known/run-mprc-release.json`, the Netlify deploy record, `/events`, `/shop`, and the signed-out `/account` route on phone and desktop sizes. If the release fails before publication, leave the prior deploy live and diagnose offline. If it publishes but verification fails, ask a Netlify team owner to restore deploy `6a54a3c93db9d300082e1f5f`; if that owner is unavailable, update the prepared rollback manifest's expected parent to the release merge, reverify its pinned previous-source preview, and merge it. A source-only disable is not rollback. After success, merge the disable pull request, confirm its production attempt is skipped, delete `codex/netlify-source-457-header`, and verify that ref is absent so a historical rebuild cannot fetch the hotfix source. The platform owner approves and performs this exception; officers do not run commands or handle credentials. +Dated result: on 2026-07-23 America/Los_Angeles, Netlify deploy `6a61c544171ea80008307623` published trigger commit `4f67e6cafb975a3f985fefc67f094b3a37526702`. The public marker matched source `ed1b0833f25822cee80c99ded8753722b5608a3f`, tree `878c6628d961f4484cb49208aef53f1e9f2e3b47`, 60 files, and digest `7570955c2a00926e5813aef135f1799172cfd046072ac89fb4e492bed0797092`. Signed-out checks passed at 1280px desktop and 390px phone widths. The release source was deleted and verified absent. The rollback source remains at `e86a0f702cff6495f50630c5de3337290db8b8cb`. + ### Production approvals Production commerce changes require: diff --git a/README.md b/README.md index 32bd85b..4807a5b 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Historical developer/content/LLM guides remain under [`docs/`](./docs/README.md) - `.github/workflows/`: frontend, Functions, Rules CI and deployment automation. - `public/404.html`, `public/index.html`, and `public/spa-navigation.js`: current tested GitHub Pages callback handoff. It preserves safe same-origin path, query, and fragment state. -**Deployment reality checked 2026-07-22:** merges run CI but do not start the manual release workflow. The protected gate accepts one exact current merged commit, rechecks its newest CI run after approval, uses one fixed Firebase target set, fails when protected authority/configuration is missing, verifies Firebase before publishing GitHub Pages, and gives no server credential to website preparation or publication. Ordinary Git-triggered Netlify production builds are paused. Issue #457 has one temporary exact-parent, exact-artifact web-only exception; it does not deploy Firebase and must be disabled and have its release source retired after verification. The source stops adding a Pages `CNAME`, but GitHub Pages currently still claims `runmprc.com` and its default URL redirects there; only a controlled #136/WEB-001 publication and provider readback can clear that conflict. Reusable protected publication to the live Netlify-served `runmprc.com` is not configured yet. Treat GitHub Pages, Netlify, `runmprc.com`, Firebase, and outside providers as separate states. +**Deployment reality checked 2026-07-23:** merges run CI but do not start the manual release workflow. The protected gate accepts one exact current merged commit, rechecks its newest CI run after approval, uses one fixed Firebase target set, fails when protected authority/configuration is missing, verifies Firebase before publishing GitHub Pages, and gives no server credential to website preparation or publication. Ordinary Git-triggered Netlify production builds are paused. Issue #457 used its temporary exact-parent, exact-artifact exception to publish Netlify deploy `6a61c544171ea80008307623`; its manifest is now inactive and its release source is retired. The exact rollback source remains available. This web-only release did not deploy Firebase. The source stops adding a Pages `CNAME`, but GitHub Pages currently still claims `runmprc.com` and its default URL redirects there; only a controlled #136/WEB-001 publication and provider readback can clear that conflict. Reusable protected publication to the live Netlify-served `runmprc.com` is not configured yet. Treat GitHub Pages, Netlify, `runmprc.com`, Firebase, and outside providers as separate states. ## Local setup status @@ -95,4 +95,4 @@ Business owners—not coding agents—must approve legal text, waiver/insurance ## Deployment warning -Pushing to `main` runs CI and does not start `.github/workflows/deploy.yml`. The manual workflow is fixed to an exact merged commit and reviewed target set, but it is **NOT AVAILABLE YET** until #133 configures protected environments and short-lived cloud authority. Ordinary Git-triggered Netlify production builds are paused; #457 temporarily permits only its exact-parent, exact-artifact frontend release, and a reusable protected live-Netlify publication path is still **NOT AVAILABLE YET**. Production changes still require protected approval, a compatible backend-first rollout, separate live-host proof, a named observer, and the runbook's post-deploy/reconciliation steps. +Pushing to `main` runs CI and does not start `.github/workflows/deploy.yml`. The manual workflow is fixed to an exact merged commit and reviewed target set, but it is **NOT AVAILABLE YET** until #133 configures protected environments and short-lived cloud authority. Ordinary Git-triggered Netlify production builds are paused. The completed #457 exception is inactive and cannot be reused because its release source was retired. A reusable protected live-Netlify publication path is still **NOT AVAILABLE YET**. Production changes still require protected approval, a compatible backend-first rollout, separate live-host proof, a named observer, and the runbook's post-deploy/reconciliation steps. diff --git a/SECURITY.md b/SECURITY.md index 7a971a9..55b8477 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -83,7 +83,7 @@ The findings below describe the repository at the start of the 2026-07-12 assess | 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 | The deterministic frontend Jest suite and standalone SPA callback suite run as separate blocking hosted CI steps. CI-001B4/#186 merged a non-mutating frontend lint gate as `bec7d5e365eacb418563a172029f241f660d9768`; exact PR and post-merge runs passed. CI-001B4A [#227](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/227) removes one reviewed `arrow-body-style` error, CI-001B4B [#239](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/239) removes one stale `AdminMembers` unknown-rule suppression record, and PAY-004C1 [#359](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/359) retires one `no-alert` warning plus two label-association errors with the unsafe reusable-link controls. Reviewed functional changes in [PR #391](https://github.com/Run-MPRC/Run-MPRC.github.io/pull/391) and [PR #392](https://github.com/Run-MPRC/Run-MPRC.github.io/pull/392) add one and two TypeScript files respectively while retiring two TSX errors each. CI-001B4C [#449](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/449) replaces the four remaining stale `react-hooks/exhaustive-deps` directives with ordinary same-line comments, without changing executable code or the gate. The current baseline scans 111 files and records 113 configured errors and 6 warnings after the lint process disables the repository's severity-masking `eslint-plugin-only-warn` hook. Branch protection, remaining lint-debt cleanup, and broader domain/integration coverage remain incomplete. | Continue reducing the reviewed finding baseline in focused changes, prove required branch checks, and add domain/integration coverage. Never regenerate the baseline merely to make CI green. | -| RISK-036 | #135 adds a manual exact-commit source gate, fixed profile-recovery targets, backend-first order, missing-config failure, and ordinary Git-triggered Netlify production containment. WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) adds a temporary web-only exception that accepts one exact `main` parent, fetches one release-specific public ref in a clean credential-free Git repository, verifies its pinned commit/tree and exact artifact count/digest, passes no React/provider or server credential inputs, scans the artifact, rejects build-hook metadata, and emits public provenance; every uncertain state stops. Its authorization is exact-merge scoped, so deletion of the release-specific source ref is required after verification to make later historical retries fail. Protected environments/OIDC, isolated staging, a reusable live-Netlify path, and dated publish/rollback evidence are still absent. | Use #457 only for its reviewed header hotfix, verify the exact pinned preview, public marker, and live pages, then disable its manifest and delete its release source ref. Keep the exact previous-source rollback ref and a reviewed Git rollback projection because the current identity cannot operate Netlify's atomic restore. Complete #133 and #136, provision isolated staging, protect the reusable Netlify release path under WEB-001, and rehearse provider rollback before broader production work. | +| RISK-036 | #135 adds a manual exact-commit source gate, fixed profile-recovery targets, backend-first order, missing-config failure, and ordinary Git-triggered Netlify production containment. WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) used a temporary web-only exception that accepted one exact `main` parent, fetched one release-specific public ref in a clean credential-free Git repository, verified its pinned commit/tree and exact artifact count/digest, passed no React/provider or server credential inputs, scanned the artifact, rejected build-hook metadata, and emitted public provenance; every uncertain state stopped. The manifest is now inactive and the release-specific source ref is deleted, so later historical retries fail. Protected environments/OIDC, isolated staging, a reusable live-Netlify path, and provider-owned atomic rollback remain unverified. | Preserve the dated #457 deploy/marker evidence and exact previous-source rollback ref. Do not reactivate the completed manifest. The reviewed Git rollback projection remains the available fallback because the current identity cannot operate Netlify's atomic restore. Complete #133 and #136, provision isolated staging, protect the reusable Netlify release path under WEB-001, and rehearse provider rollback before broader production work. | | 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. | | RISK-039 | Some authenticated accounts can lack `members/{uid}` after the Firebase cutover; the account screen hid the read failure and exposed an update that could only fail. Manual database/account repair could corrupt roles or private data. | Use an authenticated create-once server bootstrap, keep browser creation denied, fail the UI closed, and prove backend-first deployment with synthetic accounts. | diff --git a/SYSTEM_DESIGN.md b/SYSTEM_DESIGN.md index f3a7cc6..69c7964 100644 --- a/SYSTEM_DESIGN.md +++ b/SYSTEM_DESIGN.md @@ -86,12 +86,12 @@ Text alternative: browsers can use the React app, Auth, Firestore, Functions, St | Operational data | Cloud Firestore | `src/services`, `firestore.rules`, `firestore.indexes.json` | Appropriate for current scale; counters and state transitions require transactional design. | | Server API | First-generation Firebase callable/HTTP/trigger functions | `functions/` | Prototype covers most workflows; validation, idempotency, and isolation are incomplete. | | 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 ordinary automatic releases, pauses Git-triggered Netlify production builds, and removes the Pages CNAME from future protected artifacts. WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) adds one temporary web-only exception: an active manifest names one expected `main` parent, one release-specific source ref, one independently reviewed source commit/tree, and the exact artifact count/digest; both its preview and production build that same artifact and refuse every mismatch. | `netlify.toml`, `config/netlify-production-release.json`, `scripts/netlify-release-policy.js`, `.github/workflows/deploy.yml`, `public/404.html` | Split and conflicting as verified 2026-07-13. The #457 exception can publish only its pinned frontend artifact and must be disabled and have its release-specific source ref deleted after dated live verification. It does not deploy Firebase or complete the general protected host, ownership, DNS, header, or rollback work under #133/#136/WEB-001. | +| 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 ordinary automatic releases, pauses Git-triggered Netlify production builds, and removes the Pages CNAME from future protected artifacts. WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) used one temporary web-only exception: its manifest named one expected `main` parent, one release-specific source ref, one independently reviewed source commit/tree, and the exact artifact count/digest; its preview and production built that same artifact and refused every mismatch. The manifest is now inactive and the release source is retired. | `netlify.toml`, `config/netlify-production-release.json`, `scripts/netlify-release-policy.js`, `.github/workflows/deploy.yml`, `public/404.html` | Split and conflicting as verified 2026-07-23. Netlify deploy `6a61c544171ea80008307623` is the dated #457 web-only result. The exact rollback source remains, but #457 did not deploy Firebase or complete the general protected host, ownership, DNS, header, or rollback work under #133/#136/WEB-001. | | 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; 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. Ordinary Git-triggered Netlify production builds stop. The temporary #457 web-only path continues only for a production `main` merge with the exact first parent in the active manifest, then independently fetches and verifies the pinned source commit and tree before building; a later merge, disabled manifest, wrong branch/context/ref/tree/artifact, build-hook metadata, or any uncertainty stops. The pinned build receives no React/provider or server credential environment, and its release PR builds the same exact artifact as production. The authorization is exact-merge scoped rather than durable one-time state: duplicate attempts of the armed merge can build the same artifact until the release-specific source ref is deleted; deleting that ref after verification makes later retries fail at source fetch. Build hooks and a reusable protected Netlify publication path 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. +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. Ordinary Git-triggered Netlify production builds stop. The temporary #457 web-only path continued only for a production `main` merge with the exact first parent in its active manifest, then independently fetched and verified the pinned source commit and tree before building; a later merge, disabled manifest, wrong branch/context/ref/tree/artifact, build-hook metadata, or any uncertainty stopped. The pinned build received no React/provider or server credential environment, and its release PR built the same exact artifact as production. The authorization was exact-merge scoped rather than durable one-time state. The manifest is now inactive and the release-specific source ref is deleted, so later retries fail. Build hooks and a reusable protected Netlify publication path remain unverified. No source test clears the current Pages custom-domain claim, configures #133, or deploys #136; those remain separate provider states. The App Engine synchronization script is another surface that must be documented as active or retired. ```mermaid flowchart TD @@ -107,13 +107,13 @@ flowchart TD Verify -- "No" --> Stop Verify -- "Yes" --> Pages["Publish Pages branch without a CNAME"] Merge -. "Ordinary Git production build paused" .-> Netlify["Netlify / runmprc.com\nreusable protected publication not available"] - Merge -. "Only active exact-parent manifest" .-> WebGate{"Pinned source commit and tree match?"} + Merge -. "Inactive #457 manifest" .-> WebGate{"Manifest active and release source present?"} WebGate -- "No" --> Stop WebGate -- "Yes" --> WebOnly["Publish pinned web-only artifact"] WebOnly --> Netlify ``` -Text alternative: ordinary merges run CI and do not publish Netlify; the temporary web-only gate accepts only the exact manifest merge and pinned source tree, while the separate protected workflow still requires approval and verified Firebase before publishing its Pages copy. +Text alternative: ordinary merges run CI and do not publish Netlify; the completed #457 gate is inactive and its release source is absent, while the separate protected workflow still requires approval and verified Firebase before publishing its Pages copy. ### GitHub Pages callback handoff diff --git a/config/netlify-production-release.json b/config/netlify-production-release.json index af56da0..832794d 100644 --- a/config/netlify-production-release.json +++ b/config/netlify-production-release.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, - "active": true, + "active": false, "releaseId": "WEB-UX-001A-2026-07-22", "issueNumber": 457, "previewBranch": "codex/issue-457-netlify-release", diff --git a/docs/officers/ACCESS_CONTINUITY.md b/docs/officers/ACCESS_CONTINUITY.md index f8cb465..0cbd0b5 100644 --- a/docs/officers/ACCESS_CONTINUITY.md +++ b/docs/officers/ACCESS_CONTINUITY.md @@ -84,7 +84,7 @@ For each system, record only: 10. Confirm a normal merge does not start the GitHub release. 11. Confirm missing release authority becomes a red failure before backend installation, cloud authentication, deployment, or website publication. A public website artifact may be prepared without cloud authority. 12. Confirm Firebase verification must finish before the GitHub Pages publication job can start. -13. Confirm ordinary Netlify Git-triggered production builds remain paused. While #457 is active, confirm only its exact-parent, exact-artifact merge can publish and that the maintainer will disable it and retire its source after verification. +13. Confirm ordinary Netlify Git-triggered production builds remain paused. Confirm the completed #457 manifest is inactive, its release source is absent, and only its exact rollback source remains. 14. Confirm reviewers reject release requests older than 24 hours and request the current `main` commit again. 15. **NOT AVAILABLE YET:** complete the synthetic role-boundary drill below after the reviewed database, Function, and website revisions are safely available in protected staging. diff --git a/docs/officers/PUBLISH_AND_CHECK.md b/docs/officers/PUBLISH_AND_CHECK.md index aeb98c2..816f8ed 100644 --- a/docs/officers/PUBLISH_AND_CHECK.md +++ b/docs/officers/PUBLISH_AND_CHECK.md @@ -10,7 +10,7 @@ **Protected release status:** **NOT AVAILABLE YET.** Issue #135 provides the fail-closed source gate. Issue #133 must still configure protected `staging` and `production` environments, their named reviewers, and a short-lived cloud identity. Public browser build values must be named repository or organization variables because artifact preparation has no protected-environment access; #133/#136 must record and verify them separately. Do not add a long-lived Firebase key as a shortcut. -**Live Netlify publication status:** a reusable protected release is **NOT AVAILABLE YET**. Ordinary Git-triggered production builds are paused by repository configuration. Issue #457 has one temporary, platform-maintainer-only web release pinned to one reviewed source commit, tree, and artifact digest; it cannot deploy Firebase or authorize commerce, and it must be disabled and have its release source retired after dated live verification. GitHub Pages currently still claims the same custom domain; future source omits that claim, but #136/WEB-001 must publish and verify its removal. +**Live Netlify publication status:** a reusable protected release is **NOT AVAILABLE YET**. Ordinary Git-triggered production builds are paused by repository configuration. Issue #457 completed one platform-maintainer-only web release pinned to one reviewed source commit, tree, and artifact digest. Netlify deploy `6a61c544171ea80008307623` was verified on 2026-07-23 America/Los_Angeles; its manifest is inactive and its release source is retired. The exact rollback source remains. This did not deploy Firebase or authorize commerce. GitHub Pages currently still claims the same custom domain; future source omits that claim, but #136/WEB-001 must publish and verify its removal. ## The release gate @@ -56,7 +56,7 @@ As of **2026-07-13**, with the internal tooling note below checked from source o - `runmprc.com` is served by Netlify, not GitHub Pages. - GitHub Pages currently reports `runmprc.com` as its custom domain and redirects its normal address there. It is not an independently reachable copy today. - Future source stops writing that Pages domain claim. Only provider readback after #136/WEB-001 can prove it cleared. -- Ordinary Git-triggered Netlify production builds are paused. The active #457 manifest permits only one exact-parent merge and one pinned source/artifact. Build hooks bypass Netlify's ignore check, so the production wrapper separately rejects build-hook metadata and every wrong commit or inactive manifest. A duplicate attempt of the armed merge can build the same artifact until the maintainer deletes its release-specific source ref. +- Ordinary Git-triggered Netlify production builds are paused. The #457 manifest is inactive, and its retired release source makes a duplicate attempt of the historical armed merge fail during source fetch. Build hooks bypass Netlify's ignore check, so the production wrapper separately rejects build-hook metadata and every wrong commit or inactive manifest. - Live race signup, merchandise payments, and refunds remain unavailable. - CONFIG-001B1 [#151](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/151) adds source enforcement for a server-only commerce pause. It is not in the fixed profile-recovery release plan, is not deployed, and has no approved officer control. A future reviewed plan must deploy the complete guarded Function set with the deploy ceiling and every runtime/resource flag off, then prove signed webhooks still work. Do not widen the current plan by hand. @@ -119,6 +119,8 @@ If a member or officer sees **Server configuration is unavailable**: **Purpose:** publish only the already reviewed Events, Shop, and My Account header tree without publishing the unrelated application work now on `main`. +**Completed status:** production deploy `6a61c544171ea80008307623`, trigger commit `4f67e6cafb975a3f985fefc67f094b3a37526702`, and the public marker were verified on 2026-07-23 America/Los_Angeles at 1280px desktop and 390px phone widths. Events and Shop showed their images and readable headings below the navigation. Signed-out `/account` redirected to the readable image-backed Login page. Firebase and outside providers were unchanged. The release source was then retired; this procedure is retained as dated evidence, not as an available release button. + **Approver:** Dave Liu as platform owner. This is not an officer-operated control. **Prerequisites:** issue #457 approval; green checks; a successful pinned Netlify Deploy Preview; exact source commit `ed1b0833f25822cee80c99ded8753722b5608a3f`; exact source tree `878c6628d961f4484cb49208aef53f1e9f2e3b47`; exact 60-file artifact digest `7570955c2a00926e5813aef135f1799172cfd046072ac89fb4e492bed0797092`; prior live deploy `6a54a3c93db9d300082e1f5f`; release source `codex/netlify-source-457-header`; rollback source `codex/netlify-source-457-rollback`; a prepared manifest-disable pull request; a reviewed exact Git rollback projection; and no other `main` merge until verification ends. The current identity cannot click Netlify's atomic restore, so a Netlify team owner is preferred for fast rollback and the exact Git projection is the available fallback. diff --git a/docs/officers/README.md b/docs/officers/README.md index 14892a6..8c8ab41 100644 --- a/docs/officers/README.md +++ b/docs/officers/README.md @@ -63,7 +63,7 @@ In words: approve the merge, request one exact release, and approve its protecte Never shorten several of these states to “done.” -Independent officer publishing to the live Netlify host is **NOT AVAILABLE YET**. Issue #457 has one temporary platform-maintainer-only, exact-artifact web release; it is not a general officer control and must be disabled and have its release source retired after verification. Use a platform maintainer until the Netlify connection and rollback path are documented and tested. +Independent officer publishing to the live Netlify host is **NOT AVAILABLE YET**. Issue #457 completed one platform-maintainer-only, exact-artifact web release. Its manifest is inactive and its release source is retired, so it is not a reusable officer control. Use a platform maintainer until the Netlify connection and rollback path are documented and tested. The protected GitHub release is also **NOT AVAILABLE YET** until #133 configures the environment approvers and short-lived cloud identity. Missing authority stops the release with a red failure before Firebase or website publication. diff --git a/docs/officers/REQUEST_A_CHANGE.md b/docs/officers/REQUEST_A_CHANGE.md index c17734a..7765dda 100644 --- a/docs/officers/REQUEST_A_CHANGE.md +++ b/docs/officers/REQUEST_A_CHANGE.md @@ -34,7 +34,7 @@ Have one of these ready: If you open GitHub yourself, use the [canonical repository on `main`](https://github.com/Run-MPRC/Run-MPRC.github.io/tree/main), then select **Issues**. `main` is now the repository default. Do not use the legacy `dev` branch as the source for a new request. -The GitHub release is manual. A `main` merge runs checks but does not publish the GitHub Pages copy or deploy Firebase. Ordinary Git-triggered Netlify production builds are paused by repository configuration. Issue #457 temporarily permits only its exact-parent, exact-artifact web release; Netlify provider settings remain separately unverified. Stop and escalate any other publication. +The GitHub release is manual. A `main` merge runs checks but does not publish the GitHub Pages copy or deploy Firebase. Ordinary Git-triggered Netlify production builds are paused by repository configuration. Issue #457 completed its one exact-parent, exact-artifact web release; its manifest is inactive and its release source is retired. Netlify provider settings remain separately unverified. Stop and escalate any other publication. ## If you cannot open an AI assistant diff --git a/docs/officers/SYSTEM_MAPS.md b/docs/officers/SYSTEM_MAPS.md index d28ce35..51c313e 100644 --- a/docs/officers/SYSTEM_MAPS.md +++ b/docs/officers/SYSTEM_MAPS.md @@ -59,7 +59,7 @@ flowchart TD Rules --> Functions["Deploy and verify named Functions"] Functions --> Pages["Pages branch without Netlify's domain claim"] Main -. "Ordinary Git production build paused" .-> Netlify - Main -. "Temporary #457 exact parent" .-> WebGate{"Pinned source and artifact match?"} + Main -. "Inactive #457 manifest" .-> WebGate{"Manifest active and release source present?"} WebGate -- "No" --> Stop WebGate -- "Yes" --> Netlify Netlify["Netlify — current live host; reusable protected publication unavailable"] --> Live["runmprc.com"] @@ -67,7 +67,7 @@ flowchart TD Dev["dev — legacy branch"] -. "do not use for new release work" .-> PR ``` -In words: merge, release request, and protected approval are separate; a missing or failed Firebase gate publishes nothing; ordinary merges cannot publish Netlify, while temporary #457 can publish only its pinned frontend artifact; the future Pages branch must stop claiming the Netlify domain, and both hosts still need separate proof. +In words: merge, release request, and protected approval are separate; a missing or failed Firebase gate publishes nothing; ordinary merges cannot publish Netlify, and completed #457 is inactive with its release source retired; the future Pages branch must stop claiming the Netlify domain, and both hosts still need separate proof. ## Account and permission ownership diff --git a/tests/release-workflow.test.js b/tests/release-workflow.test.js index a641ece..d47d98f 100644 --- a/tests/release-workflow.test.js +++ b/tests/release-workflow.test.js @@ -205,10 +205,10 @@ test('Netlify production is an exact-artifact release while previews remain avai }); }); -test('Netlify manifest pins the reviewed hotfix source and rollback', () => { +test('Netlify manifest pins the reviewed hotfix source and is paused', () => { const loaded = loadManifest(NETLIFY_MANIFEST_PATH); assert.equal(loaded.ok, true); - assert.equal(loaded.manifest.active, true); + assert.equal(loaded.manifest.active, false); assert.equal(loaded.manifest.issueNumber, 457); assert.equal( loaded.manifest.expectedProductionParent, @@ -250,6 +250,7 @@ test('Netlify production authorization is exact-merge scoped', () => { const loaded = loadManifest(NETLIFY_MANIFEST_PATH); assert.equal(loaded.ok, true); const { manifest } = loaded; + const activeManifest = { ...manifest, active: true }; const mergeCommit = { sha: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', head: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', @@ -269,7 +270,7 @@ test('Netlify production authorization is exact-merge scoped', () => { evaluateProductionRelease({ commit: mergeCommit, env: environment, - manifest, + manifest: activeManifest, }), { ok: true, reason: 'release_authorized' }, ); @@ -304,7 +305,7 @@ test('Netlify production authorization is exact-merge scoped', () => { assert.equal( evaluateProductionRelease({ ...failure, - manifest, + manifest: activeManifest, }).ok, false, ); @@ -313,7 +314,7 @@ test('Netlify production authorization is exact-merge scoped', () => { evaluateProductionRelease({ commit: mergeCommit, env: environment, - manifest: { ...manifest, active: false }, + manifest, }).ok, false, ); @@ -342,6 +343,7 @@ test('Netlify production authorization survives a shallow merge checkout and blo runGit(source, ['switch', '-c', 'release']); const manifest = JSON.parse(fs.readFileSync(NETLIFY_MANIFEST_PATH, 'utf8')); + manifest.active = true; manifest.expectedProductionParent = base; fs.mkdirSync(path.join(source, 'config')); fs.writeFileSync( @@ -459,7 +461,7 @@ test('Netlify manifest file rejects duplicate-key or noncanonical JSON', () => { fs.writeFileSync( duplicatePath, canonical.replace( - ' "active": true,', + / "active": (?:true|false),/, ' "active": false,\n "active": true,', ), );