Skip to content
Ritesh FirodiyaGet in touch

Work / Chitragupt / Wiki / Decisions

2026-06-28-disputes-evidence-storage-scope

Decisioncanonicalverified 2026-06-28

DECISION.2026-06-28.DISPUTES-EVIDENCE-STORAGE-SCOPE

disputes/{disputeId}/evidence storage rule scoped to dispute participants

Decision

firebase/storage.rules for disputes/{disputeId}/evidence/{allPaths=**} now gates both read and write on dispute participation, derived via a firestore.get() of disputes/{disputeId} and a comparison against request.auth.uid matching either client_uid or ca_uid. Admins still get unconditional read + write (write also requires verified email + image-or-PDF + size cap, unchanged).

The previous rule allowed any signed-in user to upload to disputes/{disputeId}/evidence/*, deferring the participant check to the callable that issued the upload URL. That broke the principle that storage rules are the actual gate, since a leaked dispute id was enough for a third party to attach evidence.

Why

Phase 7a exit criterion (.context/features/index.md §7a) requires the storage rule itself to be scoped, not the callable that wraps it. The cost is one extra firestore.get() per upload — acceptable because dispute evidence uploads are rare and the dispute doc is the same one the participant's UI is already subscribed to.

Impact

  • firebase/storage.rules — new disputeParticipant(disputeId) helper; match /disputes/{disputeId}/evidence/{allPaths=**} gates read + write on isAdmin() || disputeParticipant(disputeId).
  • No callable-side change required; the new wiring is strictly tighter than the old behaviour.
  • Existing dispute participants (client + CA on the dispute) keep their upload flow unchanged.

Status

Active.

Sources

  • .context/features/index.md — Phase 7a exit criterion
  • firebase/firestore.rules — disputes/{disputeId} participant rule (mirror of the storage check)

Every project of mine is written down like this.

Read the résumé