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>
24 lines
1.3 KiB
SQL
24 lines
1.3 KiB
SQL
-- 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$;
|