feat(db): grant grafana_ro read access to reporting.* (Phase 0 role)
migrations/18_grant_reporting_ro.sql — grants USAGE + SELECT on the reporting.* layer to grafana_ro, with DEFAULT PRIVILEGES so future reporting views are auto-readable. grafana_ro is the read-only role the staging dashboard_api connects as; it read tracksolid.* but never reporting.* (the prod dashboard_api uses the app role), surfacing as "permission denied for view v_filter_drivers / v_daily_summary" on the staging /analytics/* endpoints. Read-only only — no write/REFRESH. Registered 18 in run_migrations.py. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
478fb0e707
commit
8ddbd7b745
2 changed files with 25 additions and 0 deletions
24
migrations/18_grant_reporting_ro.sql
Normal file
24
migrations/18_grant_reporting_ro.sql
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
-- 18_grant_reporting_ro.sql
|
||||||
|
-- Read-only access to the reporting.* layer for grafana_ro.
|
||||||
|
--
|
||||||
|
-- grafana_ro is the read-only role the STAGING dashboard_api connects as (it reads
|
||||||
|
-- the prod DB but must be physically unable to write — see
|
||||||
|
-- docs/STAGING_FLEETOPS_ARCHITECTURE.md §6). It already reads tracksolid.* (Grafana
|
||||||
|
-- + the migration-07 analytics views), but was never granted SELECT on the
|
||||||
|
-- reporting.* map/analytics layer (migration 11) — the prod dashboard_api connects
|
||||||
|
-- as the app/superuser role, so the gap went unnoticed until the read-only staging
|
||||||
|
-- instance hit "permission denied for view v_filter_drivers / v_daily_summary".
|
||||||
|
--
|
||||||
|
-- This grants USAGE + SELECT across reporting.* and sets DEFAULT PRIVILEGES so any
|
||||||
|
-- future reporting view/table is auto-readable by grafana_ro (no re-grant needed).
|
||||||
|
-- Read-only only: no INSERT/UPDATE/DELETE, so grafana_ro still cannot write or
|
||||||
|
-- REFRESH. Guarded + idempotent -> safe to re-apply.
|
||||||
|
|
||||||
|
DO $grants$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'grafana_ro') THEN
|
||||||
|
GRANT USAGE ON SCHEMA reporting TO grafana_ro;
|
||||||
|
GRANT SELECT ON ALL TABLES IN SCHEMA reporting TO grafana_ro; -- includes views
|
||||||
|
ALTER DEFAULT PRIVILEGES IN SCHEMA reporting GRANT SELECT ON TABLES TO grafana_ro;
|
||||||
|
END IF;
|
||||||
|
END $grants$;
|
||||||
|
|
@ -41,6 +41,7 @@ MIGRATIONS = [
|
||||||
"15_map_exclude_cost_centres.sql", # hide personal/management/mtn vehicles from the live map
|
"15_map_exclude_cost_centres.sql", # hide personal/management/mtn vehicles from the live map
|
||||||
"16_live_feed_vehicle_type.sql", # add vehicle_type + fleet_segment to fn_live_positions feed
|
"16_live_feed_vehicle_type.sql", # add vehicle_type + fleet_segment to fn_live_positions feed
|
||||||
"17_fleetops_fuel_view.sql", # reporting.v_fuel_daily — FleetOps GET /analytics/fuel source
|
"17_fleetops_fuel_view.sql", # reporting.v_fuel_daily — FleetOps GET /analytics/fuel source
|
||||||
|
"18_grant_reporting_ro.sql", # grant SELECT on reporting.* to grafana_ro (staging read-only role)
|
||||||
]
|
]
|
||||||
|
|
||||||
# ── Tables that must exist before the service is allowed to start ─────────────
|
# ── Tables that must exist before the service is allowed to start ─────────────
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue