Skip to content

Commit ff04e12

Browse files
authored
fix: rescope pg_graphql and pg_cron event triggers during pg_upgrade (#2478)
* rescope pg_graphql and pg_cron event triggers during pg_upgrade Old projects still have these event triggers scoped to CREATE FUNCTION / CREATE SCHEMA while the fleet-updated grant functions only act on CREATE EXTENSION events, so the post-upgrade extension recreation never re-applies their wiring. Rescope in initiate.sh before the extensions are dropped (the fixed triggers travel through pg_upgrade) and again in complete.sh before the generated SQL runs, as a safety net. * drop the complete.sh rescope; retry the initiate.sh one instead Both instances download the same target-version script bundle, so the older-bundle scenario the complete.sh safety net guarded against doesn't occur in practice. Keep the single rescope in initiate.sh and wrap it in retry, since it is fail-soft and a skipped rescope silently loses the extension wiring. * note when the trigger rescope can be removed * review: TODO-style comment, tab-indented heredoc
1 parent c935e0b commit ff04e12

4 files changed

Lines changed: 97 additions & 1 deletion

File tree

‎ansible/files/admin_api_scripts/pg_upgrade_scripts/common.sh‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,66 @@ function run_sql {
6969
psql -h localhost -U supabase_admin -d postgres "$@"
7070
}
7171

72+
# TODO: Drop once all projects have been upgraded past 17.6.1.111, 15.14.1.111
73+
#
74+
# Old projects still have grant-access event triggers scoped to the tags
75+
# their original seed used while the grant functions themselves (updated
76+
# fleet-wide) only act on CREATE EXTENSION events.
77+
#
78+
# * issue_pg_graphql_access on CREATE FUNCTION before build 17.6.1.111 /
79+
# 15.14.1.111
80+
# * issue_pg_cron_access on CREATE SCHEMA before 15.1.0.130
81+
#
82+
# With this mismatch, recreating the extension never re-applies its wiring
83+
# (graphql_public.graphql wrapper, cron grants). Rescope the triggers so
84+
# the CREATE EXTENSION statements that re-enable the extensions after
85+
# pg_upgrade fire them.
86+
#
87+
# Trigger definitions kept identical to migrations
88+
# 20260421000001_rescope_pg_graphql_access_trigger.sql and
89+
# 20231020085357_revoke_writes_on_cron_job_from_postgres.sql. This is a
90+
# no-op on projects that already have the CREATE EXTENSION scope.
91+
function rescope_extension_event_triggers {
92+
local sql
93+
sql=$(
94+
cat <<-'EOF'
95+
do $rescope$
96+
begin
97+
if exists (
98+
select 1
99+
from pg_proc p
100+
join pg_namespace n on p.pronamespace = n.oid
101+
where n.nspname = 'extensions' and p.proname = 'grant_pg_graphql_access'
102+
) then
103+
execute 'drop event trigger if exists issue_pg_graphql_access';
104+
execute $q$
105+
create event trigger issue_pg_graphql_access
106+
on ddl_command_end
107+
when tag in ('CREATE EXTENSION')
108+
execute procedure extensions.grant_pg_graphql_access()
109+
$q$;
110+
end if;
111+
112+
if exists (
113+
select 1
114+
from pg_proc p
115+
join pg_namespace n on p.pronamespace = n.oid
116+
where n.nspname = 'extensions' and p.proname = 'grant_pg_cron_access'
117+
) then
118+
execute 'drop event trigger if exists issue_pg_cron_access';
119+
execute $q$
120+
create event trigger issue_pg_cron_access
121+
on ddl_command_end
122+
when tag in ('CREATE EXTENSION')
123+
execute procedure extensions.grant_pg_cron_access()
124+
$q$;
125+
end if;
126+
end $rescope$;
127+
EOF
128+
)
129+
run_sql -c "$sql"
130+
}
131+
72132
# Wrap a db name in dbname='...' (escaping \ and ') so characters special to -d
73133
# parsing (=, spaces, quotes) stay part of a literal name, not a conninfo fragment.
74134
# psql parses a -d value containing '=' as a full conninfo string, so a customer

‎ansible/files/admin_api_scripts/pg_upgrade_scripts/initiate.sh‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ ALTER SYSTEM SET jit = off;
204204
SELECT pg_reload_conf();
205205
EOF
206206

207+
# Rescope before dropping extensions: the fixed triggers are carried into the new
208+
# cluster by pg_upgrade, so both the post-upgrade re-enable and the failure-path
209+
# re-enable below fire them. Fail-soft: a broken rescope should not block the
210+
# upgrade — but retry first, since a skipped rescope means the recreation of
211+
# these extensions silently loses their wiring.
212+
retry 3 rescope_extension_event_triggers || log "WARNING: failed to rescope extension event triggers"
213+
207214
# Disable extensions if they're enabled
208215
# Generate SQL script to re-enable them after upgrade
209216
for EXTENSION in "${EXTENSIONS_TO_DISABLE[@]}"; do

‎tests/pg_upgrade/tests/01-schema.sql‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CREATE EXTENSION IF NOT EXISTS pgtap;
22

33
BEGIN;
4-
SELECT plan(15);
4+
SELECT plan(18);
55

66
select has_schema('public');
77
select has_schema('auth');
@@ -22,5 +22,18 @@ SELECT has_column('public', 'countries', 'continent', 'Column continent should e
2222

2323
SELECT has_materialized_view('public', 'european_countries', 'Materialized view european_countries should exist');
2424

25+
SELECT is(
26+
(SELECT evttags FROM pg_event_trigger WHERE evtname = 'issue_pg_graphql_access'),
27+
ARRAY['CREATE EXTENSION']::text[],
28+
'issue_pg_graphql_access should be rescoped to CREATE EXTENSION by the upgrade');
29+
SELECT is(
30+
(SELECT evttags FROM pg_event_trigger WHERE evtname = 'issue_pg_cron_access'),
31+
ARRAY['CREATE EXTENSION']::text[],
32+
'issue_pg_cron_access should be rescoped to CREATE EXTENSION by the upgrade');
33+
SELECT ok(
34+
(SELECT prosrc LIKE '%graphql.resolve%' FROM pg_proc
35+
WHERE proname = 'graphql' AND pronamespace = 'graphql_public'::regnamespace),
36+
'graphql_public.graphql should be the real wrapper after upgrade, not the placeholder');
37+
2538
SELECT * FROM finish();
2639
ROLLBACK;

‎tests/pg_upgrade/tests/99-fixtures.sql‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,19 @@ with no data;
1010
refresh materialized view public.european_countries;
1111

1212
select count(*) from public.european_countries;
13+
14+
-- simulate a project created before the trigger rescope migrations: the
15+
-- fleet-wide function updates left these projects with triggers still scoped
16+
-- to their original tags, so recreating the extensions no longer re-applies
17+
-- their wiring (graphql_public.graphql wrapper, cron grants). The upgrade
18+
-- must rescope both to CREATE EXTENSION.
19+
drop event trigger if exists issue_pg_graphql_access;
20+
create event trigger issue_pg_graphql_access
21+
on ddl_command_end
22+
when tag in ('CREATE FUNCTION')
23+
execute procedure extensions.grant_pg_graphql_access();
24+
drop event trigger if exists issue_pg_cron_access;
25+
create event trigger issue_pg_cron_access
26+
on ddl_command_end
27+
when tag in ('CREATE SCHEMA')
28+
execute procedure extensions.grant_pg_cron_access();

0 commit comments

Comments
 (0)