Skip to content

fix(cli): restore postgres after role reverts (CLI-2205) - #6246

Merged
avallete merged 3 commits into
developfrom
7ttp/cli-2205-db-push-passwordless-login-role-path-migration-containing
Aug 18, 2026
Merged

fix(cli): restore postgres after role reverts (CLI-2205)#6246
avallete merged 3 commits into
developfrom
7ttp/cli-2205-db-push-passwordless-login-role-path-migration-containing

Conversation

@7ttp

@7ttp7ttp commented Aug 18, 2026

Copy link
Copy Markdown
Member

TL;DR

Passwordless db push --linked breaks on any migration containing reset role:
the login role path relies on a session level SET SESSION ROLE postgres that the migration itself undoes.
File runners now re-assert the step-down immediately after each role-reverting statement, at the end of each file, and before every CLI owned ledger write, so the whole file behaves the same on both auth paths.

whats biting?

The passwordless path connects as a temp cli_login_* role and steps down to postgres once at connect. A migration's reset role reverts the session to the login role, so:

  • the appended history insert fails with permission denied for schema supabase_migrations (SQLSTATE 42501) and rolls the migration back, even though every user statement succeeded
  • authored transaction and pg-delta no-transaction files commit their statements but never record, so the next push re-applies them
  • statements between the reset role and the end of the same file run as the login role, so granted by current_user cleanup silently no-ops while the push exits 0 (reproduced on staging: the stale pg_auth_members grant survives)
  • later files and the seed_files upsert run as the login role too

fixed now by:

  • LegacyDbSession.restoreRoleSql (set only when the step-down ran) is injected by every file runner right after each top-level role revert (RESET ROLE, SET [SESSION] ROLE [TO|=] NONE|DEFAULT including a case-sensitively quoted 'none', RESET SESSION AUTHORIZATION, SET SESSION AUTHORIZATION DEFAULT, DISCARD ALL), and again at end of file and before the history insert and both seed_files upserts, so current_user matches a password session for the whole file
  • injected restores never shift At statement: N and are never recorded in the history row; deliberate set role <x> choreography is untouched, and password, local and plain --db-url sessions see a byte identical statement stream
  • the residual (dynamic SQL, SET LOCAL ROLE NONE, session_user itself) is documented in docs/go-cli-divergences.md with the end-of-file restore protecting every CLI owned write; both SIDE_EFFECTS.md tables record the new statements

ref:

@7ttp
7ttp requested a review from a team as a code ownerAugust 18, 2026 08:27
@7ttp7ttp self-assigned this Aug 18, 2026
@github-actions

github-actionsBot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Supabase CLI preview

npx --yes https://pkg.pr.new/supabase/cli/supabase@802bece9ff819ad3c02181f842ffe3337ef78f92

Preview package for commit 802bece.

@avalleteavallete left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank's for looking into this !

One issue raised by Claude on this one, dug a bit:

The end-of-file restoreRoleSql correctly fixes the filed bug: after RESET ROLE, the history insert no longer dies with 42501 and later files start as postgres. Password / local / non-stepped-down --db-url streams stay byte-identical. That part is good.

An issue is residual in go-cli-divergences.md as the product behavior.

Statements betweenRESET ROLE and the end of the same file still run as the login role. For the class of migrations in #6236 (SET ROLE / RESET ROLE / REVOKE … GRANTED BY current_user), this PR changes the failure mode the wrong way:

  • before: fail-closed — 42501, migration not recorded, retryable
  • after: succeed, history row written, grant leftover, stderr WARN: that CI will ignore

The pooler rationale does not apply here. You do not need a connection-time role=postgres default. restoreRoleSql is already SET SESSION ROLE postgres. Inject it after each top-levelRESET ROLE / SET ROLE NONE / SET SESSION ROLE NONE in the same batch/sequence, keep recording the original statements, and keep the trailing restore as a backstop. At statement: N should skip those internal ops the same way the trailing restore already does.

I reproduced this on a real passwordless db push --linked against staging (Initialising login role…, login role cli_login_postgres, NOINHERIT):

createtableif not exists public.dogfood_probe (
at textprimary key,
current_user_name textnot null,
session_user_name textnot null
);
insert intopublic.dogfood_probevalues ('start', current_user, session_user);
create role repro_writer nologin;
grant repro_writer to postgres;
grant usage on schema public to repro_writer;
grant insert onpublic.dogfood_probe to repro_writer;
set role repro_writer;
insert intopublic.dogfood_probevalues ('as_writer', current_user, session_user);
reset role;
revoke repro_writer from postgres granted by current_user;

Result: WARN: statements after RESET ROLE…, exit 0, schema_migrations recorded dogfood_reset_role. Probe at start was current_user=postgres / session_user=cli_login_postgres. After the push, pg_auth_members still had repro_writerpostgresgrantor postgres. The same REVOKE … GRANTED BY current_user on the password path (current_user actually postgres, no login-role init) dropped that row.

The warn can stay as defense-in-depth for dynamic SQL / siblings the detector misses. It should not be the answer for a static RESET ROLE already in the statement list.

Request: mid-file restore, then this is good to land.

@7ttp7ttp changed the title fix(cli): restore postgres after reset role (CLI-2205)fix(cli): restore postgres after role reverts (CLI-2205)Aug 18, 2026
@avallete
avallete added this pull request to the merge queueAug 18, 2026
Merged via the queue into develop with commit 0c72179Aug 18, 2026
30 checks passed
@avallete
avallete deleted the 7ttp/cli-2205-db-push-passwordless-login-role-path-migration-containing branch August 18, 2026 13:56
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants

@7ttp@avallete