No automated deploy path for Firestore rules — they can regress silently after every fix #51
Closed
opened 2026-08-23 18:11:14 -04:00 by logan
·
5 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#51
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.
Split out of #13. #13 is the one-time operational task (get the current rules live). This issue is the durable gap: even after #13 is done, nothing keeps the deployed ruleset in sync with the repo.
Verified 2026-08-23
Server/infra/firestore/firestore.rules,firebase.jsonandfirestore.indexes.jsonare in source control..gitea/workflows/deploy.ymlhas nofirebase deploy,firebase-tools, orfirestore:rulesstep. Its only Firestore reference isNEXT_PUBLIC_FIRESTORE_DATABASEas a frontend build-arg (line 65).*.md,*.yml,*.yaml,*.shand Makefile underServer/returns zero matches forfirebase deployorfirestore:rules. No script, no make target, no runbook.main. Firestore rules specifically fall outside that, which makes the gap easy to miss — the reasonable assumption is that everything deploys.Why this outlives #13
The rules are the only access control on browser direct-reads (
useCalls,useIncidents, etc. read Firestore from the client, soauth.pyis not in the read path). A security boundary that is edited in the repo but applied by hand will drift again the first time someone changes it and forgets — and the failure is silent in the safe direction for the reviewer (repo looks correct) and unsafe in production.What done looks like
firestore.rules(and indexes) frommain, ideally indeploy.ymlso it shares the existing trigger.firestore.indexes.jsonhas already drifted from the live database and duplicates two indexes. Deploying indexes blindly may error; sequence this after #33 or scope this issue to rules only.Links
logan referenced this issue2026-08-25 09:28:41 -04:00
The concrete casualty:
useUnacknowledgedAlertsthrowsrequires an indexon every pagedrb-frontend/lib/useAlerts.tsuseUnacknowledgedAlerts()runswhere(org_id ==) where(acknowledged == false) orderBy(triggered_at desc) limit(100)onalert_events. No matching composite index is live, so it fails withFirebaseError: The query requires an indexon every page load, and the/watch"Triggered Alerts" tab is dead. This is #13/#51's manual-deploy gap biting a user-visible surface.File change (branch
fix/51-alert-events-index, commit8a0412b, offmain)Added one entry to
infra/firestore/firestore.indexes.json:Field tuple +
triggered_at DESCENDINGare copied verbatim from the consolecreate_compositelink in the live error, so agcloud/console create and afirebase deployconverge on the same index (the ASC-vs-DESC split is exactly what caused #33).Two caveats for whoever reconciles this — do NOT treat as blockers here, they belong to #33:
COLLECTION, notCOLLECTION_GROUP. The hook usescollection(db, "alert_events"), and the error'screate_compositepayload decodes toqueryScope = 1(COLLECTION). ThecollectionGroups/segment in that URL is Firestore's path naming for both scopes, not the scope itself.COLLECTION, fieldsorg_id, acknowledged, triggered_atall ASC) that was never deployed. The new entry matches Firestore's own generated spec for the failing query; the old one is now redundant/overlapping. Reconciling the two (and dropping the pre-tenancy livealert_events(acknowledged, triggered_at)index) is #33's job, not this change's.Not deployed — no GCP creds on the authoring machine, which is the point of this issue.
Deploy options (any one)
1. gcloud (headless over SSH from the prod VM, which is authed as the project SA):
(
--query-scopevalues are lowercase-hyphenated:collection/collection-group/collection-recursive;collectionis also the default. Verified against the current gcloud reference.)2. firebase CLI — from
Server/infra/firestore/(firebase.jsonpinsdatabase: c2-server):This will also prompt to delete the three indexes the file's
//drift-2026-08-23note lists — that note still says answer YES to those three only.3. Console link from the error:
https://console.firebase.google.com/v1/r/project/discord-radio-bot-461301/firestore/databases/c2-server/indexes?create_composite=Cl1wcm9qZWN0cy9kaXNjb3JkLXJhZGlvLWJvdC00NjEzMDEvZGF0YWJhc2VzL2MyLXNlcnZlci9jb2xsZWN0aW9uR3JvdXBzL2FsZXJ0X2V2ZW50cy9pbmRleGVzL18QARoQCgxhY2tub3dsZWRnZWQQARoKCgZvcmdfaWQQARoQCgx0cmlnZ2VyZWRfYXQQAhoMCghfX25hbWVfXxAC
Index build is a few minutes on an empty/small
alert_events; the hook and the Triggered Alerts tab recover on their own once it'sREADY.Index still not deployed — this is now the top UI blocker. PR #121 (merged,
bc3251e8) declaresalert_events (acknowledged ASC, org_id ASC, triggered_at DESC)ininfra/firestore/firestore.indexes.json, but there is still no deploy automation (the core of this issue), so the livec2-serverDB does not have it./watchTriggered Alerts + the site-wideuseUnacknowledgedAlertsnav badge both stay dead until it is applied.VM action (GCP service-account authed host): from the repo checkout,
Server/infra/firestore/:firebase deploy --only firestore:indexes --project discord-radio-bot-461301Answer YES to the 3 deletion prompts per the
//drift-2026-08-23note. This also reconciles the whole index set, which may fix the Archive 503 (#33) if that is a missingcalls(org_id, started_at DESC).Resolved. Root cause was NOT the alert_events index alone — the whole
firestore.indexes.jsondeclared ASC-only indexes fororderBy(x,'desc')queries, which Firestore does not reverse-scan for these shapes. Createdalert_events (org_id, triggered_at DESC)+(acknowledged, org_id, triggered_at DESC)+calls (org_id, started_at DESC)onc2-servervia gcloud (2026-09-08). PR #124 (merged, deploy7f4d684) rewrites the file to DESC and adds a CIfirebase deploy --only firestore:rules,firestore:indexesstep so it can't regress silently. /watch Triggered Alerts + the nav alert badge both load now. VM prereq for the CI step:npm i -g firebase-toolsonce.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.Fixed in
9b83f0e: rules job now authenticates with the drb-ci-firestore-deploy service account (FIREBASE_SA_KEY). Run 633 — all jobs green, rules deployed to c2-server (aircraft/vessels reads confirmed working in prod).