Skip to content

AUTH-PROFILE-001: recover missing member profiles safely - #132

Merged
daliu merged 4 commits into
mainfrom
codex/issue-118-profile-bootstrap
Jul 13, 2026
Merged

AUTH-PROFILE-001: recover missing member profiles safely#132
daliu merged 4 commits into
mainfrom
codex/issue-118-profile-bootstrap

Conversation

@daliu

@daliu daliu commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Outcome

Prepare the safe fix for signed-in accounts that have no members/{uid} profile after the Firebase cutover. The server now creates one pending profile at most once, and the account page keeps editing hidden unless setup and the normal Firestore read both succeed.

This source pull request completed its rebased hosted review. #135 is now merged: merging this source runs CI only and publishes neither the website nor Firebase. Issue #118 stays open until the protected staging and live evidence is complete.

What changed

  • Add authenticated callable ensureMemberProfile with an empty request body.
  • Derive UID, email, name, phone, provider, and verification state from Firebase Auth on the server.
  • Share one transactional create-if-missing helper between signup and recovery.
  • Never overwrite an existing profile and never set, remove, or replace custom claims.
  • Keep browser profile creation denied; retain the existing name/phone-only update allowlist.
  • Make profile loading, retry, editing, save confirmation, registrations, and Strava fail closed.
  • Replace raw Firebase errors with short member-safe messages.
  • Add exact boundary, concurrency, emulator, UI, service, and Rules tests.
  • Add system and officer diagrams plus the protected release/rollback procedure.

Security invariants

  • App Check policy is evaluated before authentication; authentication is required before request validation.
  • The caller cannot choose a UID, role, claim, payment/membership state, timestamp, or profile field.
  • Existing profiles remain byte-for-byte unchanged during setup retries and trigger/callable races.
  • Missing profiles start with the profile mirror role: unverified; recovery does not grant or remove actual access.
  • Signup and recovery never call setCustomUserClaims; only the explicit role-grant workflow may change authority.
  • No real member record, production write, provider call, secret, or private screenshot was used.

Local verification

Node v20.20.2, npm 10.8.2, Java 17, rebased head 6381907a6e243335094cb25122ef773943f7f19d:

  • npm --prefix functions run lint — passed.
  • npm --prefix functions run test:run -- --runInBand — 36 passed; the emulator-only test was intentionally skipped.
  • npm --prefix functions test — 5 suites / 37 tests passed against demo-only Auth and Firestore emulators.
  • CI=true npm test -- --watchAll=false --runInBand — 6 suites / 62 tests passed.
  • npm run test:rules — 4 suites / 298 tests passed against the demo-only Firestore emulator.
  • npm run test:spa-navigation — 10/10 passed.
  • Changed account/service ESLint with --max-warnings=0 — passed.
  • CI=true DISABLE_ESLINT_PLUGIN=true npx --no-install react-scripts build — compiled successfully.
  • git diff --check and relative Markdown target checks — passed.
  • Exact-head hosted CI run 29241330054 passed Frontend/build, Functions, and Rules; the Netlify preview also passed.\n- Two independent read-only reviews approved the authorization, concurrency, claim preservation, error redaction, officer procedure, and exact backend-first release order.

Existing React Router future-flag and stale Browserslist warnings remain unchanged. No dependency or lockfile changed.

Required release order — provider blocker

#135 merged through #138 as 9eafab1217aff7058c42240aaba72d7b93f8ed24. A normal merge now runs CI only; it cannot publish this frontend or mutate Firebase. Post-merge staging and synthetic production probes also proved that missing configuration or cloud authority ends red before authentication, Firebase mutation, or Pages publication.

That makes the source merge safe. It does not make profile recovery live. The remaining order is:

  1. Merge this exact reviewed source after its refreshed checks pass. Keep AUTH-PROFILE-001 — Restore safe profile setup and editing after the Firebase cutover #118 open.
  2. Under BACKEND-001 — Audit the Firebase cutover and approve legacy data disposition #113/CI-001C — Configure protected short-lived Firebase deployment identity #133, name an isolated staging project and configure protected approvers plus short-lived OIDC/WIF authority. Do not add a downloadable cloud key.
  3. Under CI-001D — Prove backend-first staging and deploy the profile repair #136, deploy the exact merged SEC-001 — Replace the Firestore admin catch-all with resource-specific rules #100 Rules plus both revised createMemberOnSignUp and ensureMemberProfile to isolated staging.
  4. Prove App Check policy, synthetic missing-profile creation, retries, existing-profile/claim preservation, denial cases, and rollback or safe roll-forward.
  5. Deploy and verify that exact backend set in the approved target Firebase project. Never deploy the callable while the old signup trigger remains.
  6. Permit the dependent website artifact only after exact backend readback. Publish and verify runmprc.com through the separately protected WEB-001/Netlify path.
  7. Stop and restore or safely roll forward if any target backend, website, domain, or synthetic behavior is partial or mismatched.

Compatibility and rollback

  • No data migration or backfill is performed.
  • Existing documents, even incomplete ones, are preserved rather than “fixed” silently.
  • A newly recreated profile can expose an existing claim/profile mismatch; officers must stop and escalate instead of copying claims or editing production data.
  • Roll back the website independently if needed. Treat the two Functions and exact Rules as one compatible backend set; rehearse its rollback or safe roll-forward before live release.

Officer impact: A member will get a plain retry/sign-out path instead of a raw permission error. Officers must not create profiles, delete accounts, or grant roles as a repair.

Officer documentation: docs/officers/EVENTS_SHOP_MEMBERS.md, docs/officers/EMERGENCY_AND_RECOVERY.md, and docs/officers/SYSTEM_MAPS.md; engineering context in SYSTEM_DESIGN.md, SECURITY.md, and OPERATIONS_RUNBOOK.md.

Deployment evidence: Source only. A merge of this PR will run CI and publish nothing. Firebase Rules/Functions not deployed; website not published from this branch; runmprc.com behavior not verified; outside-provider configuration not changed or verified. The draft PR/preview and green checks are source evidence only.

Tracks #118. Do not close #118 from source merge alone.

@netlify

netlify Bot commented Jul 13, 2026

Copy link
Copy Markdown

Deploy Preview for luminous-fox-7c393f ready!

Name Link
🔨 Latest commit 6381907
🔍 Latest deploy log https://app.netlify.com/projects/luminous-fox-7c393f/deploys/6a54b7c5e432e40008b23133
😎 Deploy Preview https://deploy-preview-132--luminous-fox-7c393f.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@daliu

daliu commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

EXACT-HEAD REVIEW / HOSTED EVIDENCE at 2026-07-13T08:50:52Z for c982bcd752ed9b6eb1d443103d09996ac2541ea7:

  • Hosted CI run 29236561507 passed.
  • Run frontend Jest tests: 6 suites / 62 tests passed.
  • Run SPA callback safety tests: 10/10 passed.
  • Functions lint/tests: 4 suites passed, 36 tests passed, and the one emulator-only integration test was intentionally skipped in hosted unit CI.
  • Firestore Rules: 4 suites / 298 tests passed against the demo-only emulator.
  • Production build compiled successfully.
  • Netlify preview is ready at the exact PR head. It was not used to sign in, access Firebase/provider data, or claim production behavior.
  • Two independent read-only reviews approved the final source and documentation: create-only concurrency, no claim writes, generic no-PII errors/logs, fail-closed UI, officer continuity, and the target-backend-before-website procedure.

No source/check blocker remains. The PR stays draft because deployment safety is a separate blocker: current automation is frontend-first and Firebase authority is absent. #135, #133, and #136 now represent the owner release-model decision, short-lived deployment identity, and exact staged/backend-first release. Do not merge #132 until those gates make the required release order possible.

@daliu
daliu force-pushed the codex/issue-118-profile-bootstrap branch from c982bcd to 1228558 Compare July 13, 2026 10:01
@daliu
daliu marked this pull request as ready for review July 13, 2026 10:05
@daliu
daliu merged commit 13ccc1b into main Jul 13, 2026
7 checks passed
@daliu
daliu deleted the codex/issue-118-profile-bootstrap branch July 13, 2026 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AUTH-PROFILE-001 — Restore safe profile setup and editing after the Firebase cutover

1 participant