

-- 2. Grant the predefined read-all-stats role. This is the least
--    privilege that exposes the pg_stat_* views the adapter polls.
--    It does NOT grant SELECT on user tables; the allow-listed
--    queries never touch them.
GRANT pg_read_all_stats TO dsfb_observer;

-- 3. Pin this role's default transaction mode to read-only. This is
--    the session-level layer of the code-audit contract: even if a
--    client bug bypassed the type-level surface, the engine would
--    refuse any write.
ALTER ROLE dsfb_observer SET default_transaction_read_only = on;

-- 4. Statement-level timeout. A poll that hangs past this budget is
--    aborted by the engine. 500 ms is ample for pg_stat_statements
--    snapshots on databases with up to ~1e6 distinct queries; tune
--    upward only after measuring actual poll distributions on your
--    instance.
ALTER ROLE dsfb_observer SET statement_timeout = '500ms';

-- 5. Idle-in-transaction timeout. The adapter never holds an
--    explicit transaction, but a buggy client could. This bound
--    ensures that even in the pathological case the observer
--    releases locks within one second.
ALTER ROLE dsfb_observer SET idle_in_transaction_session_timeout = '1s';

-- 6. No GRANT on any user-created schema. This is a non-action, but
--    documented here to make the omission explicit: the observer
--    has no access to user data, only to the stats views.

-- OPTIONAL hardening: restrict connections to the local socket.
-- Add this to `pg_hba.conf` to forbid TCP connections for this role:
--
--     local   all   dsfb_observer   peer
--     host    all   dsfb_observer   0.0.0.0/0   reject
--
-- Combined with the above role settings, this yields a three-layer
-- access posture: type-level (crate code), session-level
-- (PostgreSQL role), and network-level (pg_hba.conf).
