Skip to content

Commit e8ab263

Browse files
committed
chore: split bootstrap user switch script to global vs. in-database objs
1 parent 1211077 commit e8ab263

File tree

1 file changed

+123
-109
lines changed
  • ansible/files/admin_api_scripts/pg_upgrade_scripts

1 file changed

+123
-109
lines changed

ansible/files/admin_api_scripts/pg_upgrade_scripts/common.sh

+123-109
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,17 @@ set session authorization supabase_tmp;
109109
-- to handle snowflakes that happened in the past
110110
revoke supabase_admin from authenticator;
111111
112+
-- #incident-2024-09-12-project-upgrades-are-temporarily-disabled
112113
do $$
113114
begin
114-
if exists (select from pg_extension where extname = 'timescaledb') then
115-
execute(format('select %s.timescaledb_pre_restore()', (select pronamespace::regnamespace from pg_proc where proname = 'timescaledb_pre_restore')));
115+
if exists (select from pg_authid where rolname = 'pg_read_all_data') then
116+
execute('grant pg_read_all_data to postgres');
116117
end if;
117118
end
118119
$$;
120+
grant pg_signal_backend to postgres;
119121
122+
-- Swap postgres & supabase_admin on global objects (roles, role settings, etc.).
120123
do $$
121124
declare
122125
postgres_rolpassword text := (select rolpassword from pg_authid where rolname = 'postgres');
@@ -128,7 +131,82 @@ declare
128131
join pg_authid a on a.oid = s.setrole
129132
where a.rolname in ('postgres', 'supabase_admin')
130133
);
131-
event_triggers jsonb[] := (select coalesce(array_agg(jsonb_build_object('name', evtname)), '{}') from pg_event_trigger where evtowner = 'postgres'::regrole);
134+
rec record;
135+
obj jsonb;
136+
begin
137+
set local search_path = '';
138+
139+
alter role postgres rename to supabase_admin_;
140+
alter role supabase_admin rename to postgres;
141+
alter role supabase_admin_ rename to supabase_admin;
142+
143+
-- role grants
144+
for rec in
145+
select * from pg_auth_members
146+
loop
147+
execute(format('revoke %s from %s;', rec.roleid::regrole, rec.member::regrole));
148+
execute(format(
149+
'grant %s to %s %s granted by %s;',
150+
case
151+
when rec.roleid = 'postgres'::regrole then 'supabase_admin'
152+
when rec.roleid = 'supabase_admin'::regrole then 'postgres'
153+
else rec.roleid::regrole
154+
end,
155+
case
156+
when rec.member = 'postgres'::regrole then 'supabase_admin'
157+
when rec.member = 'supabase_admin'::regrole then 'postgres'
158+
else rec.member::regrole
159+
end,
160+
case
161+
when rec.admin_option then 'with admin option'
162+
else ''
163+
end,
164+
case
165+
when rec.grantor = 'postgres'::regrole then 'supabase_admin'
166+
when rec.grantor = 'supabase_admin'::regrole then 'postgres'
167+
else rec.grantor::regrole
168+
end
169+
));
170+
end loop;
171+
172+
-- role passwords
173+
execute(format('alter role postgres password %L;', postgres_rolpassword));
174+
execute(format('alter role supabase_admin password %L;', supabase_admin_rolpassword));
175+
176+
-- role settings
177+
foreach obj in array role_settings
178+
loop
179+
execute(format('alter role %I %s reset all',
180+
case when obj->>'role' = 'postgres' then 'supabase_admin' else 'postgres' end,
181+
case when obj->>'database' is null then '' else format('in database %I', obj->>'database') end
182+
));
183+
end loop;
184+
foreach obj in array role_settings
185+
loop
186+
for rec in
187+
select split_part(value, '=', 1) as key, substr(value, strpos(value, '=') + 1) as value
188+
from jsonb_array_elements_text(obj->'configs')
189+
loop
190+
execute(format('alter role %I %s set %I to %s',
191+
obj->>'role',
192+
case when obj->>'database' is null then '' else format('in database %I', obj->>'database') end,
193+
rec.key,
194+
-- https://github.com/postgres/postgres/blob/70d1c664f4376fd3499e3b0c6888cf39b65d722b/src/bin/pg_dump/dumputils.c#L861
195+
case
196+
when rec.key in ('local_preload_libraries', 'search_path', 'session_preload_libraries', 'shared_preload_libraries', 'temp_tablespaces', 'unix_socket_directories')
197+
then rec.value
198+
else quote_literal(rec.value)
199+
end
200+
));
201+
end loop;
202+
end loop;
203+
end
204+
$$;
205+
206+
-- Swap postgres & supabase_admin on in-database objects (schemas, tables, functions, etc.).
207+
do $$
208+
declare
209+
event_triggers jsonb[] := (select coalesce(array_agg(jsonb_build_object('name', evtname)), '{}') from pg_event_trigger where evtowner = 'supabase_admin'::regrole);
132210
user_mappings jsonb[] := (
133211
select coalesce(array_agg(jsonb_build_object('oid', um.oid, 'role', a.rolname, 'server', s.srvname, 'options', um.umoptions)), '{}')
134212
from pg_user_mapping um
@@ -219,70 +297,9 @@ begin
219297
alter event trigger pgsodium_trg_mask_update disable;
220298
end if;
221299
222-
alter role postgres rename to supabase_admin_;
223-
alter role supabase_admin rename to postgres;
224-
alter role supabase_admin_ rename to supabase_admin;
225-
226-
-- role grants
227-
for rec in
228-
select * from pg_auth_members
229-
loop
230-
execute(format('revoke %s from %s;', rec.roleid::regrole, rec.member::regrole));
231-
execute(format(
232-
'grant %s to %s %s granted by %s;',
233-
case
234-
when rec.roleid = 'postgres'::regrole then 'supabase_admin'
235-
when rec.roleid = 'supabase_admin'::regrole then 'postgres'
236-
else rec.roleid::regrole
237-
end,
238-
case
239-
when rec.member = 'postgres'::regrole then 'supabase_admin'
240-
when rec.member = 'supabase_admin'::regrole then 'postgres'
241-
else rec.member::regrole
242-
end,
243-
case
244-
when rec.admin_option then 'with admin option'
245-
else ''
246-
end,
247-
case
248-
when rec.grantor = 'postgres'::regrole then 'supabase_admin'
249-
when rec.grantor = 'supabase_admin'::regrole then 'postgres'
250-
else rec.grantor::regrole
251-
end
252-
));
253-
end loop;
254-
255-
-- role passwords
256-
execute(format('alter role postgres password %L;', postgres_rolpassword));
257-
execute(format('alter role supabase_admin password %L;', supabase_admin_rolpassword));
258-
259-
-- role settings
260-
foreach obj in array role_settings
261-
loop
262-
execute(format('alter role %I %s reset all',
263-
case when obj->>'role' = 'postgres' then 'supabase_admin' else 'postgres' end,
264-
case when obj->>'database' is null then '' else format('in database %I', obj->>'database') end
265-
));
266-
end loop;
267-
foreach obj in array role_settings
268-
loop
269-
for rec in
270-
select split_part(value, '=', 1) as key, substr(value, strpos(value, '=') + 1) as value
271-
from jsonb_array_elements_text(obj->'configs')
272-
loop
273-
execute(format('alter role %I %s set %I to %s',
274-
obj->>'role',
275-
case when obj->>'database' is null then '' else format('in database %I', obj->>'database') end,
276-
rec.key,
277-
-- https://github.com/postgres/postgres/blob/70d1c664f4376fd3499e3b0c6888cf39b65d722b/src/bin/pg_dump/dumputils.c#L861
278-
case
279-
when rec.key in ('local_preload_libraries', 'search_path', 'session_preload_libraries', 'shared_preload_libraries', 'temp_tablespaces', 'unix_socket_directories')
280-
then rec.value
281-
else quote_literal(rec.value)
282-
end
283-
));
284-
end loop;
285-
end loop;
300+
if exists (select from pg_extension where extname = 'timescaledb') then
301+
execute(format('select %s.timescaledb_pre_restore()', (select pronamespace::regnamespace from pg_proc where proname = 'timescaledb_pre_restore')));
302+
end if;
286303
287304
reassign owned by postgres to supabase_admin;
288305
@@ -352,10 +369,7 @@ begin
352369
loop
353370
if obj->>'role' in ('postgres', 'supabase_admin') or rec.grantee::regrole in ('postgres', 'supabase_admin') then
354371
execute(format('alter default privileges for role %I %s revoke %s on %s from %s'
355-
, case when obj->>'role' = 'postgres' then 'supabase_admin'
356-
when obj->>'role' = 'supabase_admin' then 'postgres'
357-
else obj->>'role'
358-
end
372+
, obj->>'role'
359373
, case when obj->>'schema' is null then ''
360374
else format('in schema %I', obj->>'schema')
361375
end
@@ -366,16 +380,11 @@ begin
366380
when obj->>'objtype' = 'T' then 'types'
367381
when obj->>'objtype' = 'n' then 'schemas'
368382
end
369-
, case when rec.grantee = 'postgres'::regrole then 'supabase_admin'
370-
when rec.grantee = 'supabase_admin'::regrole then 'postgres'
371-
when rec.grantee = 0 then 'public'
372-
else rec.grantee::regrole::text
373-
end
383+
, case when rec.grantee = 0 then 'public' else rec.grantee::regrole::text end
374384
));
375385
end if;
376386
end loop;
377387
end loop;
378-
379388
foreach obj in array default_acls
380389
loop
381390
for rec in
@@ -384,7 +393,10 @@ begin
384393
loop
385394
if obj->>'role' in ('postgres', 'supabase_admin') or rec.grantee::regrole in ('postgres', 'supabase_admin') then
386395
execute(format('alter default privileges for role %I %s grant %s on %s to %s %s'
387-
, obj->>'role'
396+
, case when obj->>'role' = 'postgres' then 'supabase_admin'
397+
when obj->>'role' = 'supabase_admin' then 'postgres'
398+
else obj->>'role'
399+
end
388400
, case when obj->>'schema' is null then ''
389401
else format('in schema %I', obj->>'schema')
390402
end
@@ -395,7 +407,11 @@ begin
395407
when obj->>'objtype' = 'T' then 'types'
396408
when obj->>'objtype' = 'n' then 'schemas'
397409
end
398-
, case when rec.grantee = 0 then 'public' else rec.grantee::regrole::text end
410+
, case when rec.grantee = 'postgres'::regrole then 'supabase_admin'
411+
when rec.grantee = 'supabase_admin'::regrole then 'postgres'
412+
when rec.grantee = 0 then 'public'
413+
else rec.grantee::regrole::text
414+
end
399415
, case when rec.is_grantable then 'with grant option' else '' end
400416
));
401417
end if;
@@ -405,15 +421,15 @@ begin
405421
-- schemas
406422
foreach obj in array schemas
407423
loop
408-
if obj->>'owner' = 'postgres' then
424+
if obj->>'owner' = 'supabase_admin' then
409425
execute(format('alter schema %s owner to postgres;', (obj->>'oid')::regnamespace));
410426
end if;
411427
for rec in
412428
select grantor, grantee, privilege_type, is_grantable
413429
from aclexplode((obj->>'acl')::aclitem[])
414430
where grantee::regrole in ('postgres', 'supabase_admin')
415431
loop
416-
execute(format('revoke %s on schema %s from %I', rec.privilege_type, (obj->>'oid')::regnamespace, case when rec.grantee = 'postgres'::regrole then 'supabase_admin' else 'postgres' end));
432+
execute(format('revoke %s on schema %s from %I', rec.privilege_type, (obj->>'oid')::regnamespace, rec.grantee::regrole));
417433
end loop;
418434
end loop;
419435
foreach obj in array schemas
@@ -423,22 +439,26 @@ begin
423439
from aclexplode((obj->>'acl')::aclitem[])
424440
where grantee::regrole in ('postgres', 'supabase_admin')
425441
loop
426-
execute(format('grant %s on schema %s to %s %s', rec.privilege_type, (obj->>'oid')::regnamespace, rec.grantee::regrole, case when rec.is_grantable then 'with grant option' else '' end));
442+
execute(format('grant %s on schema %s to %s %s'
443+
, rec.privilege_type
444+
, (obj->>'oid')::regnamespace
445+
, case when rec.grantee = 'postgres'::regrole then 'supabase_admin' else 'postgres' end
446+
, case when rec.is_grantable then 'with grant option' else '' end));
427447
end loop;
428448
end loop;
429449
430450
-- types
431451
foreach obj in array types
432452
loop
433-
if obj->>'owner' = 'postgres' then
453+
if obj->>'owner' = 'supabase_admin' then
434454
execute(format('alter type %s owner to postgres;', (obj->>'oid')::regtype));
435455
end if;
436456
for rec in
437457
select grantor, grantee, privilege_type, is_grantable
438458
from aclexplode((obj->>'acl')::aclitem[])
439459
where grantee::regrole in ('postgres', 'supabase_admin')
440460
loop
441-
execute(format('revoke %s on type %s from %I', rec.privilege_type, (obj->>'oid')::regtype, case when rec.grantee = 'postgres'::regrole then 'supabase_admin' else 'postgres' end));
461+
execute(format('revoke %s on type %s from %I', rec.privilege_type, (obj->>'oid')::regtype, rec.grantee::regrole));
442462
end loop;
443463
end loop;
444464
foreach obj in array types
@@ -448,14 +468,18 @@ begin
448468
from aclexplode((obj->>'acl')::aclitem[])
449469
where grantee::regrole in ('postgres', 'supabase_admin')
450470
loop
451-
execute(format('grant %s on type %s to %s %s', rec.privilege_type, (obj->>'oid')::regtype, rec.grantee::regrole, case when rec.is_grantable then 'with grant option' else '' end));
471+
execute(format('grant %s on type %s to %s %s'
472+
, rec.privilege_type
473+
, (obj->>'oid')::regtype
474+
, case when rec.grantee = 'postgres'::regrole then 'supabase_admin' else 'postgres' end
475+
, case when rec.is_grantable then 'with grant option' else '' end));
452476
end loop;
453477
end loop;
454478
455479
-- functions
456480
foreach obj in array functions
457481
loop
458-
if obj->>'owner' = 'postgres' then
482+
if obj->>'owner' = 'supabase_admin' then
459483
execute(format('alter routine %s(%s) owner to postgres;', (obj->>'oid')::regproc, pg_get_function_identity_arguments((obj->>'oid')::regproc)));
460484
end if;
461485
for rec in
@@ -471,7 +495,7 @@ begin
471495
end
472496
, (obj->>'oid')::regproc
473497
, pg_get_function_identity_arguments((obj->>'oid')::regproc)
474-
, case when rec.grantee = 'postgres'::regrole then 'supabase_admin' else 'postgres' end
498+
, rec.grantee::regrole
475499
));
476500
end loop;
477501
end loop;
@@ -490,7 +514,7 @@ begin
490514
end
491515
, (obj->>'oid')::regproc
492516
, pg_get_function_identity_arguments((obj->>'oid')::regproc)
493-
, rec.grantee::regrole
517+
, case when rec.grantee = 'postgres'::regrole then 'supabase_admin' else 'postgres' end
494518
, case when rec.is_grantable then 'with grant option' else '' end
495519
));
496520
end loop;
@@ -501,15 +525,15 @@ begin
501525
loop
502526
-- obj->>'oid' (text) needs to be casted to oid first for some reason
503527
504-
if obj->>'owner' = 'postgres' then
528+
if obj->>'owner' = 'supabase_admin' then
505529
execute(format('alter table %s owner to postgres;', (obj->>'oid')::oid::regclass));
506530
end if;
507531
for rec in
508532
select grantor, grantee, privilege_type, is_grantable
509533
from aclexplode((obj->>'acl')::aclitem[])
510534
where grantee::regrole in ('postgres', 'supabase_admin')
511535
loop
512-
execute(format('revoke %s on table %s from %I', rec.privilege_type, (obj->>'oid')::oid::regclass, case when rec.grantee = 'postgres'::regrole then 'supabase_admin' else 'postgres' end));
536+
execute(format('revoke %s on table %s from %I', rec.privilege_type, (obj->>'oid')::oid::regclass, rec.grantee::regrole));
513537
end loop;
514538
end loop;
515539
foreach obj in array relations
@@ -521,35 +545,25 @@ begin
521545
from aclexplode((obj->>'acl')::aclitem[])
522546
where grantee::regrole in ('postgres', 'supabase_admin')
523547
loop
524-
execute(format('grant %s on table %s to %s %s', rec.privilege_type, (obj->>'oid')::oid::regclass, rec.grantee::regrole, case when rec.is_grantable then 'with grant option' else '' end));
548+
execute(format('grant %s on table %s to %s %s'
549+
, rec.privilege_type
550+
, (obj->>'oid')::oid::regclass
551+
, case when rec.grantee = 'postgres'::regrole then 'supabase_admin' else 'postgres' end
552+
, case when rec.is_grantable then 'with grant option' else '' end));
525553
end loop;
526554
end loop;
527555
528-
if exists (select from pg_event_trigger where evtname = 'pgsodium_trg_mask_update') then
529-
alter event trigger pgsodium_trg_mask_update enable;
530-
end if;
531-
end
532-
$$;
533-
534-
do $$
535-
begin
536556
if exists (select from pg_extension where extname = 'timescaledb') then
537557
execute(format('select %s.timescaledb_post_restore()', (select pronamespace::regnamespace from pg_proc where proname = 'timescaledb_post_restore')));
538558
end if;
539-
end
540-
$$;
541559
542-
alter database postgres connection limit -1;
543-
544-
-- #incident-2024-09-12-project-upgrades-are-temporarily-disabled
545-
do $$
546-
begin
547-
if exists (select from pg_authid where rolname = 'pg_read_all_data') then
548-
execute('grant pg_read_all_data to postgres');
560+
if exists (select from pg_event_trigger where evtname = 'pgsodium_trg_mask_update') then
561+
alter event trigger pgsodium_trg_mask_update enable;
549562
end if;
550563
end
551564
$$;
552-
grant pg_signal_backend to postgres;
565+
566+
alter database postgres connection limit -1;
553567
554568
set session authorization supabase_admin;
555569
drop role supabase_tmp;

0 commit comments

Comments
 (0)