Firestore rules and indexes are in source control but never deployed #13
Open
opened 2026-08-19 22:06:55 -04:00 by logan
·
6 comments
No Branch/Tag Specified
Labels
Clear labels
area/ai-pipeline
area/auth
area/billing
area/correlation
area/discord
area/frontend
area/governance
area/growth
area/infra-deploy
area/legal
area/map
area/mqtt
area/node-ota
area/osint
area/recording-audio
area/sdr-radio
area/transcription
board
board:agenda
minutes:draft
minutes:final
role:ceo
role:cfo
role:cio
role:ciso
role:cmo
role:coo
role:cto
Scene/entity extraction, summarizer, AI providers, embeddings
AuthN/Z, roles, tenancy/org scoping, API keys, credentials
Plans, entitlements, AI spend accounting and caps
Incident correlation, linking, lifecycle, severity, corr_debug
Discord bot, radio bots, voice streams, bot tokens, webhooks
Web UI: Next.js app and the edge-node local dashboard
Board process, minutes, unattended runner, agent tooling
Go-to-market, outreach, cold email, discovery conversations
CI/CD, VM, registry, Firestore rules/indexes deploy, Terraform/Caddy
ToS, retention, licences/DAAs, CAN-SPAM, E&O, name suppression
Live map: pins, paths, tiles, legend, geocoding
Node-C2 MQTT, checkins, commands, node sweeper, dynsec
Node install, enrollment, OTA updater, image skew
External feeds: cameras, 511, ADS-B, AIS, outages, and their licences
Call capture, boundaries, PulseAudio, ring buffer, trimming, attribution
OP25 decode, SDR hardware/tuning, conventional, second SDR, mesh radio
STT, transcript correction, place verification, name accuracy
Board process: minutes and board-filed items
Needs board scoping at the next sitting; CEO removes the label once scoped
One exec pre-read, closed by CEO
CEO ruling; open until enacted
Filed by the CEO
Filed by the CFO
Filed by the CIO
Filed by the CISO
Filed by the CMO
Filed by the COO
Filed by the CTO
kind
behavior-bug
Wrong product behavior; the instrument reads it correctly
kind
measurement-bug
Corrupts the recording/instrument (debug data, evals, health checks), not behavior
priority
p0
Drop everything: prod broken, live exposure, or owner-ruled P0
priority
p1
Next up: blocks a gate, a customer, or core incident quality
priority
p2
Normal: real defect or planned work, schedule in turn
priority
p3
Low: minor, cosmetic, or someday
status
blocked
Waiting on an external party, spend, or another issue
status
in-progress
Branch or PR open against it
status
needs-decision
Waiting on an owner or board ruling before work
status
needs-info
Root cause or repro unknown; needs a reading first
type
bug
Something built is wrong: code, data, or a measurement
type
chore
Maintenance, refactor, tests, pinning, cleanup: no user-visible change
type
decision
A ruling to make or record: board minutes, owner calls, legal reviews
type
docs
Docs, runbooks, CLAUDE.md, skills, SOPs
type
feature
New capability or an extension of an existing one
type
security
Security, privacy, credential or tenant-isolation exposure
type
tracking
Tracker, checklist, initiative or punch-list spanning several changes
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: logan/server-26#13
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
infra/firestore/firestore.rulesandfirestore.indexes.jsonlanded during the tenancy pass but have not been deployed — deployment is a manual step documented inside the files themselves.Until that happens, the rules actually enforcing browser direct-reads are whatever is live in the Firebase console, not what is in the repo. The repository and production are silently out of sync on a security boundary, which is the worst kind of drift: reviewing the repo gives false assurance.
Also unverified: whether Firestore genuinely requires the composite index for
org_id ==combined witharray_containsthat was included defensively.Confirmed live in prod (drb.cusano.net, git_sha
861ea41, 2026-08-23 02:07 EDT) — both halves of this are still undeployed and now cause visible, misleading UI failures:Indexes.
useIncidentsfails on every load of/incidents:That index IS declared in
infra/firestore/firestore.indexes.json(incidents: org_id ASC + started_at ASC). It has never been pushed. The consequence is worse than a blank page:app/incidents/page.tsxrenders the empty state "No incidents recorded yet / Incidents appear automatically once calls start correlating." while the real cause is a failed query. The page lies about the state of the system. Same shape is waiting forcalls(org_id+started_at, org_id+incident_ids) and bothalert_eventsindexes.Rules.
useUnacknowledgedAlerts: FirebaseError: Missing or insufficient permissions.fires from the root layout on every page load, so every route in the app logs an error.firestore.rules:98does grantallow read: if docInMyOrg()onalert_events— so this is the rules file not being deployed, ordocInMyOrg()failing because livealert_eventsdocs predateorg_id.Deploy command is in the header comment of the indexes file:
firebase deploy --only firestore:indexes --project discord-radio-bot-461301(plusfirestore:rules).Secondary fix worth doing at the same time: the hooks swallow the error into an empty array, so
useIncidents/useCallsshould surfaceerrorto the page and the page should render an error state instead of "nothing recorded yet".Promoted to a hard revenue gate by board minutes #42 (2026-08-23) - this is Gate B condition B1.
The board ruled that no card is charged, no invoice is issued and no Founding Operator slot is sold until this issue is closed. It was the CISO's #1 finding (#39):
Server/infra/firestore/firestore.rulesis deny-by-default and correctly scoped onresource.data.org_id == request.auth.token.org_idin source, but undeployed - so the live tenant boundary is unknown, not known-good. Blast radius if the console still holds permissive rules: every signed-in user of every org reading every other org's calls, incidents, transcripts and geocoded addresses.To close, per the minutes: deploy
firestore.rulesand reconcilefirestore.indexes.json(see #33), then paste the deployed ruleset ID into this issue. The ruleset ID is the verification artefact - "I ran the deploy" is not, because this exact process has already drifted silently once (#33).Owner: the owner (WSL/console - not reachable from the authoring machine). Date: not set; this is one of the items blocking first revenue.
Verified 2026-08-23: rules do NOT auto-deploy on push to main.
Server/infra/firestore/firestore.rules(plusfirebase.json,firestore.indexes.json) exist in source, but.gitea/workflows/deploy.ymlhas nofirebase deploy/firebase-tools/firestore:rulesstep. The only Firestore reference in the whole workflow isNEXT_PUBLIC_FIRESTORE_DATABASEas a frontend build-arg (line 65). Grep across all*.md,*.yml,*.shand Makefiles inServer/returns zero matches forfirebase deployorfirestore:rules— there is no script, make target, or documented procedure that deploys them anywhere.So the deployed ruleset is whatever was last hand-set in the Firebase console, and nothing in the repo will ever change that. Writing the rules file did not close this issue; it only made the gap versionable.
Two things follow:
Raised at board minutes #42 (Gate B). Board context: the owner reasonably assumed "everything deploys on push to main"; that assumption holds for the three container images and not for Firestore rules.
Pulled forward by board minutes #62 (2026-08-24) as the single highest-leverage owner action this week, ahead of everything except the discovery conversations. Due 2026-08-31.
CTO (#60 rec. 10) and CISO (#61 finding 4) converged on this independently.
infra/firestore/firestore.rulesis deny-by-default, well-formed and committed - and has never been deployed. The frontend reads Firestore directly from the browser, so for reads the live console ruleset is the access control, notauth.py. What is enforcing it right now is whatever was hand-set in the console: unknown, unversioned, and unreviewed - while the unattended runner operates against production twice daily.This is the load-bearing blocker on Gate B tenant isolation, and it costs the owner minutes:
#51 (a CI step so it can never drift again) follows this and is engineering work, not owner work.
Deployed and verified 2026-08-25.
Ran from
Server/infra/firestore/:Output confirms the correct database target, which is the failure mode
firebase.jsonwarns about:firestore: deployed indexes in firestore.indexes.json successfully for c2-server databasefirestore: released rules firestore.rules to cloud.firestoreDeploy complete!The
"database": "c2-server"pin infirebase.jsondid its job — without it the CLI deploys to(default), reports success, and changes nothing the app can see.Note for the record: the CLI found 1 index in the live project that is not in
firestore.indexes.jsonand it was deleted during the deploy (prompt answered Yes). That was live-vs-repo drift, now reconciled in the repo's favour. If a query starts reporting "index required" against/databases/c2-server/, this is the first thing to check.This was named in board minutes #62 as the sole remaining blocker on tenant isolation, due 2026-08-31 — closed six days early. Closing.
Reopened per board minutes 2026-09-13 CIO draft (server-26#144): PR #124's "Closes #N" auto-closed this, but the CI firebase deploy step (
.gitea/workflows/deploy.yml:131-137) gates oncommand -v firebaseand the VM has no firebase-tools installed -- the step silently no-ops on every deploy. Firestore rules/indexes are NOT actually being applied in prod. See DEFERRED.md row 54. Fix: install firebase-tools on the VM, confirm next deploy log shows a realfirebase deployrun, not the WARNING line.