Repository navigation
AUTH-001B — Require verified email for role-based Firestore access #196
Description
Officer impact: After deployment, an officer or member whose account email is not verified cannot use role-only access to private member content or admin records. They can still sign in, view/update their own permitted profile fields, and use the documented verification recovery path.
Officer documentation: Update docs/officers/ACCESS_CONTINUITY.md, docs/officers/EVENTS_SHOP_MEMBERS.md, and the matching system-map text/diagram if the access flow changes. Mark the rule as source-only until Firebase Rules deployment and staged/live proof are complete.
Deployment evidence: None at issue creation. Closure of the source slice requires deterministic Rules emulator tests, merged source, exact hosted CI, and separate evidence that Firebase Rules were or were not deployed. It must not claim website, provider, mailbox, or live-member verification.
Problem
Current Firestore Rules treat a custom role value of member or admin as sufficient for role-based access. They do not also require Firebase Auth's authoritative email_verified token claim. A stale, forged-in-test, or otherwise unverified role-bearing token can therefore satisfy private member/admin Rules even though AUTH-001 requires both facts.
Atomic outcome
Require request.auth.token.email_verified == true for every role-based Firestore authorization decision while preserving identity-only self-service access needed to verify and recover an account.
flowchart LR
A["Signed-in Firebase identity"] --> B{"Own safe profile action?"}
B -->|"Yes"| C["Use UID-based self-service rule"]
B -->|"No; role access"| D{"Verified email and allowed role?"}
D -->|"Yes"| E["Allow the specific member/admin operation"]
D -->|"No"| F["Deny"]
Text alternative: Safe self-service profile actions remain tied to the signed-in UID. Every private member or admin action requires both a verified-email token and the allowed role.
Invariants
- A
memberoradminrole string alone never authorizes a private read or browser-admin operation. - Only the authoritative token boolean
email_verified == truecounts; profile fields and request data do not override it. - Missing, false, string, number, or other malformed verification values deny role-based access.
- An unverified signed-in person retains only existing UID-bound self-service reads/updates and cannot gain another user's access.
- Anonymous and public event/product reads remain unchanged.
- This change does not grant a role after verification and does not treat verification as membership.
Scope
firestore.rules- Existing Firestore Rules tests under
tests/firestore-rules/needed to prove the role/verification matrix - Minimum authoritative engineering/officer status documentation
Acceptance criteria
- Shared Rules helpers require exact boolean verified-email state for member/admin role access.
- An unverified or missing-claim admin is denied every browser-admin surface currently guarded by
isAdmin(). - An unverified or missing-claim member/admin is denied members-only documents and events.
- Verified member/admin behavior remains allowed only where the existing role permits it.
- Unverified users can still perform the existing UID-bound safe profile recovery/edit operations, without cross-user access.
- Profile
emailVerifieddata, forged request fields, or malformed token values cannot satisfy the rule. - Existing public/anonymous behavior is unchanged.
- Focused and full Rules emulator suites pass with explicit verified state in every privileged test context.
- Source, tests, merge, Firebase deployment, and live behavior are reported as separate states.
Dependencies and coordination
- SEC-001 — Replace the Firestore admin catch-all with resource-specific rules #100 / SEC-001 source is merged and provides the resource-specific Rules baseline.
- AUTH-001A — Reject unverified targets at existing role-grant endpoints #98 / AUTH-001A is merged and separately owns verification at existing role-grant endpoints.
- AUTH-MAIL-002 — Make account-email delivery states honest and recoverable #120/AUTH-MAIL-002C2 — Handle verification links safely without exposing action codes #194 own account-email recovery/action UI; preserve its verification-only and no-auto-membership boundaries.
- CI-001 — Establish trustworthy quality gates and protected deployment #105/CI-001C — Configure protected short-lived Firebase deployment identity #133/CI-001D — Prove backend-first staging and deploy the profile repair #136 own protected Rules/Functions/website deployment and live evidence.
- MEMBERS-IDENTITY-001 — Define authoritative membership and external-account state #81 may consume this as part of its AUTH-001 prerequisite after remaining Functions, verification-mirror, and revocation slices are completed.
Explicitly out of scope
- Cloud Functions authorization changes, role grants, profile verification-mirror reconciliation, token revocation, MFA/recent-auth, account linking, provider configuration, email templates, Firebase deployment, or production-data inspection.
- Removing UID-bound self-service access required for account setup/recovery.
- Granting membership or admin rights because an email becomes verified.
Claim protocol
Creation is not a claim. Before editing, assign the issue, post CLAIMED by <canonical agent> at <UTC>; branch <branch>, and re-read live comments. Keep the change to this Rules authorization outcome.
Activity
daliu commentedon Jul 14, 2026
CLAIMED by /root at 2026-07-14T00:39:54Z; branch codex/issue-196-verified-role-rules; exact base e76b1ee.
This is AUTH-001B, not a multi-mode AUTH-MAIL action-handler slice. Active source ownership is limited to firestore.rules and the minimum tests/firestore-rules role-matrix files required by the failing proof. Minimum AUTH-001/security/officer status hunks will be named after the failing-test audit. It excludes #194 action/Identity/App files, Functions, profile-mirror reconciliation, token revocation, packages, workflows, providers, deployment, and production data.
Invariant: UID-bound safe self-service remains available; every member/admin role-based Firestore decision additionally requires exact boolean token email_verified == true. Verification never grants membership.
daliu commentedon Jul 14, 2026
SCOPE AMENDMENT after failing-test audit — 2026-07-14T00:44:07Z
Exact implementation/test paths are now: firestore.rules; tests/firestore-rules/setup.js; tests/firestore-rules/members-only.test.js; tests/firestore-rules/members.test.js; tests/firestore-rules/events.test.js; tests/firestore-rules/shop-and-locked.test.js. The red proof was 30 expected-denial failures against the old role-only Rules; the focused fixed proof is 4 suites / 348 tests.
Minimum status/continuity paths reserved for #196: SECURITY.md, IMPLEMENTATION_PLAN.md, GITHUB_ISSUES.md, GITHUB_ISSUE_SLICES.md, OPERATIONS_RUNBOOK.md, docs/officers/ACCESS_CONTINUITY.md, and docs/officers/SYSTEM_MAPS.md.
Coordination: #197 owns functions/memberProfile.js plus its two tests and only the SYSTEM_DESIGN/account-profile and docs/officers/EVENTS_SHOP_MEMBERS phone-copy sections. #196 will not edit those #197 paths. All #194 action/Identity/App paths remain excluded.
daliu commentedon Jul 14, 2026
EXTRACTION FINISHED — 2026-07-14T00:50:45Z
PR #198 is ready for review at exact head
2da7bfa824fdc2be635f27ec577150940cf6a303.The exact staged diff
b681c561bbf55017f14d9caad8a3cdb411c34606ee84637c51c6cd9db891b6a5was independently approved by security, test, and officer-documentation reviewers. Local evidence includes the red proof (30 new denials failed before the Rules fix), full Rules 348/348, frontend 198/198, Functions 990/990 non-emulator tests, SPA 11/11, release/workflow/artifact 42/42, lint, build, and diff checks.Hosted PR checks are running. No Firebase deployment was attempted; #196 remains source/test-only and is not live. The claim stays active until controlled merge, post-merge evidence, and explicit release.
daliu commentedon Jul 14, 2026
COMPLETE / CLAIM RELEASED — 2026-07-14T00:55:02Z
PR #198 merged as exact
maincommita8801770e97cf21d81f3307f5893734115140d8f.Evidence:
29297012945passed frontend lint/Jest/SPA/build, Functions lint/tests, Firestore Rules, commerce-journal, and artifact safety. The Netlify PR preview also passed.29297116454passed every blocking job ona8801770e97cf21d81f3307f5893734115140d8f.Deployment state:
The #196 claim on its 13 paths is released. Remaining AUTH-001 work still includes Functions/Admin SDK authorization, verification-mirror reconciliation, token refresh/revocation behavior, protected Firebase deployment, and live readback. Verification continues to grant no role or membership by itself.