Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions ansible/files/admin_api_scripts/pg_upgrade_scripts/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,66 @@ function run_sql {
psql -h localhost -U supabase_admin -d postgres "$@"
}

# TODO: Drop once all projects have been upgraded past 17.6.1.111, 15.14.1.111
#
# Old projects still have grant-access event triggers scoped to the tags
# their original seed used while the grant functions themselves (updated
# fleet-wide) only act on CREATE EXTENSION events.
#
# * issue_pg_graphql_access on CREATE FUNCTION before build 17.6.1.111 /
# 15.14.1.111
# * issue_pg_cron_access on CREATE SCHEMA before 15.1.0.130
#
# With this mismatch, recreating the extension never re-applies its wiring
# (graphql_public.graphql wrapper, cron grants). Rescope the triggers so
# the CREATE EXTENSION statements that re-enable the extensions after
# pg_upgrade fire them.
#
# Trigger definitions kept identical to migrations
# 20260421000001_rescope_pg_graphql_access_trigger.sql and
# 20231020085357_revoke_writes_on_cron_job_from_postgres.sql. This is a
# no-op on projects that already have the CREATE EXTENSION scope.
function rescope_extension_event_triggers {
local sql
sql=$(
cat <<-'EOF'
do $rescope$
begin
if exists (
select 1
from pg_proc p
join pg_namespace n on p.pronamespace = n.oid
where n.nspname = 'extensions' and p.proname = 'grant_pg_graphql_access'
) then
execute 'drop event trigger if exists issue_pg_graphql_access';
execute $q$
create event trigger issue_pg_graphql_access
on ddl_command_end
when tag in ('CREATE EXTENSION')
execute procedure extensions.grant_pg_graphql_access()
$q$;
end if;

if exists (
select 1
from pg_proc p
join pg_namespace n on p.pronamespace = n.oid
where n.nspname = 'extensions' and p.proname = 'grant_pg_cron_access'
) then
execute 'drop event trigger if exists issue_pg_cron_access';
execute $q$
create event trigger issue_pg_cron_access
on ddl_command_end
when tag in ('CREATE EXTENSION')
execute procedure extensions.grant_pg_cron_access()
$q$;
end if;
end $rescope$;
EOF
)
run_sql -c "$sql"
}
Comment thread
imor marked this conversation as resolved.

# Wrap a db name in dbname='...' (escaping \ and ') so characters special to -d
# parsing (=, spaces, quotes) stay part of a literal name, not a conninfo fragment.
# psql parses a -d value containing '=' as a full conninfo string, so a customer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,13 @@ ALTER SYSTEM SET jit = off;
SELECT pg_reload_conf();
EOF

# Rescope before dropping extensions: the fixed triggers are carried into the new
# cluster by pg_upgrade, so both the post-upgrade re-enable and the failure-path
# re-enable below fire them. Fail-soft: a broken rescope should not block the
# upgrade — but retry first, since a skipped rescope means the recreation of
# these extensions silently loses their wiring.
retry 3 rescope_extension_event_triggers || log "WARNING: failed to rescope extension event triggers"

# Disable extensions if they're enabled
# Generate SQL script to re-enable them after upgrade
for EXTENSION in "${EXTENSIONS_TO_DISABLE[@]}"; do
Expand Down
15 changes: 14 additions & 1 deletion tests/pg_upgrade/tests/01-schema.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CREATE EXTENSION IF NOT EXISTS pgtap;

BEGIN;
SELECT plan(15);
SELECT plan(18);

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

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

SELECT is(
(SELECT evttags FROM pg_event_trigger WHERE evtname = 'issue_pg_graphql_access'),
ARRAY['CREATE EXTENSION']::text[],
'issue_pg_graphql_access should be rescoped to CREATE EXTENSION by the upgrade');
SELECT is(
(SELECT evttags FROM pg_event_trigger WHERE evtname = 'issue_pg_cron_access'),
ARRAY['CREATE EXTENSION']::text[],
'issue_pg_cron_access should be rescoped to CREATE EXTENSION by the upgrade');
SELECT ok(
(SELECT prosrc LIKE '%graphql.resolve%' FROM pg_proc
WHERE proname = 'graphql' AND pronamespace = 'graphql_public'::regnamespace),
'graphql_public.graphql should be the real wrapper after upgrade, not the placeholder');

SELECT * FROM finish();
ROLLBACK;
16 changes: 16 additions & 0 deletions tests/pg_upgrade/tests/99-fixtures.sql
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,19 @@ with no data;
refresh materialized view public.european_countries;

select count(*) from public.european_countries;

-- simulate a project created before the trigger rescope migrations: the
-- fleet-wide function updates left these projects with triggers still scoped
-- to their original tags, so recreating the extensions no longer re-applies
-- their wiring (graphql_public.graphql wrapper, cron grants). The upgrade
-- must rescope both to CREATE EXTENSION.
drop event trigger if exists issue_pg_graphql_access;
create event trigger issue_pg_graphql_access
on ddl_command_end
when tag in ('CREATE FUNCTION')
execute procedure extensions.grant_pg_graphql_access();
drop event trigger if exists issue_pg_cron_access;
create event trigger issue_pg_cron_access
on ddl_command_end
when tag in ('CREATE SCHEMA')
execute procedure extensions.grant_pg_cron_access();
Loading