Security and Permissions¶
Unlike a lot of PostgreSQL extensions, pg_relay_notifier does not rely on schema USAGE as its only real gate. Every table and sequence privilege is revoked from PUBLIC at install time, and every function's default EXECUTE-to-PUBLIC grant is revoked too — the whole extension is closed by default, and access is re-granted deliberately through two helper functions.
The two grant helpers¶
SELECT pgrelay_notifier.grant_sender('app_role'); -- send + inspect status
SELECT pgrelay_notifier.grant_admin('ops_role'); -- + profiles, channels, purge
Both are superuser-only to call.
grant_sender gives a role schema USAGE plus:
compose,attach,attach_text,dispatch,send— and the Oracle UTL_MAIL-stylesend_mail/send_mail_attach_raw/send_mail_attach_textfamilyget_status,list_notifications,get_history,get_trace
That's the complete sender surface. A sender cannot create or edit a profile, create a channel, or purge anything.
grant_admin calls grant_sender internally, then adds:
validate_profile,create_profile,update_profile,delete_profile,get_profile,list_profileslist_profile_defaults,update_profile_defaultscreate_channelpurge,purge_debug
Nobody — sender or admin — ever gets direct table access. The tables (profiles, notifications, attachments, status_history, debug_trace) are private by design; every read and write goes through a function.
The pg_relay role¶
The pg_relay Processor connects as a specific role (conventionally pgrelay). That role holds exactly four grants — the interface functions — set up automatically by CREATE EXTENSION:
GRANT USAGE ON SCHEMA pgrelay_notifier TO pgrelay;
GRANT EXECUTE ON FUNCTION pgrelay_notifier.interface_version() TO pgrelay;
GRANT EXECUTE ON FUNCTION pgrelay_notifier.fetch(bigint) TO pgrelay;
GRANT EXECUTE ON FUNCTION pgrelay_notifier.set_status(bigint, text, text, text, integer, integer) TO pgrelay;
GRANT EXECUTE ON FUNCTION pgrelay_notifier.debug_log(bigint, text, text) TO pgrelay;
It cannot read notifications directly, manage profiles, or send — only fetch what it's told to deliver and report back what happened. See the Technical Reference for the full interface contract these four functions implement.
interface_version() is the one public exception¶
interface_version() alone carries EXECUTE for PUBLIC — a compatibility probe, not a privileged operation. Any role that already has schema USAGE (granted by either helper above) can call it without a separate grant, matching the convention pg_relay itself uses for list_applications().