Skip to content

fix(#929): let the monolithic migration provision a newly-created Supabase project - #930

Merged
TortoiseWolfe merged 1 commit into
mainfrom
fix/monolithic-migration-new-cloud-project
Aug 22, 2026
Merged

fix(#929): let the monolithic migration provision a newly-created Supabase project#930
TortoiseWolfe merged 1 commit into
mainfrom
fix/monolithic-migration-new-cloud-project

Conversation

@TortoiseWolfe

Copy link
Copy Markdown
Owner

Closes #929.

The one path every fork must take was the one path nothing tested

Applying supabase/migrations/20251006_complete_monolithic_setup.sql to a project created today aborts with 42501: permission denied for schema auth, and because the file is a single BEGIN; … COMMIT;, leaves zero tables. Forking is supposed to end with the fork pointing at its own Supabase project; it could not.

Found while giving TortoiseWolfe/geolarp its own backend (geolarp PR #20).

Cause: one statement, needed only by the local profile

CREATE OR REPLACE FUNCTION auth.jwt() ...

It forward-fills a stub for the local supabase/postgres image, where GoTrue has not booted and CREATE POLICY would fail at parse time — that reasoning is still correct, so the statement is guarded, not removed. It now runs only where auth.jwt() is genuinely absent: identical locally, no-op on Cloud.

fresh cloud project long-lived project
auth.jwt() exists yes (owner supabase_auth_admin) yes
postgres has USAGE on auth yes yes
postgres has CREATE on auth no
migration applies no — aborted yes

postgres cannot work around it: not a superuser, and SET ROLE supabase_auth_admin is denied.

Not the cause, though it looks like it: the on_auth_user_created trigger on auth.users is fine — postgres holds TRIGGER there (verified with a create/drop probe), and it is present on the new project after the fix.

Verified on a genuinely new project

new geoLARP project this repo's production project
tables 19 19
policies 75 75
functions / triggers 25 / 13

The regression guard, and why it is trustworthy

scripts/__tests__/migration-provisions-a-new-cloud-project.test.js splits the file into real top-level statements — dollar-quote aware, comments stripped — and fails if one creates or alters an object inside the auth schema.

It ships with its own falsifiers, because a guard that greps source has bitten this repo repeatedly:

  • an unguarded CREATE … auth.jwt() must be caught ✅
  • auth.uid() in a CREATE POLICY body must not trip it (97 mentions) ✅
  • CREATE TRIGGER … ON auth.users must not trip it ✅
  • a commented-out copy of the old statement must not trip it ✅ — the exact way a guard passes after the code it guards is deleted

Mutation-tested against the real file, not just synthetic strings: reverting the guard fails the suite, restoring it passes, file byte-identical.

531/531  pnpm test:scripts

What this does not fix

Nothing here provisions a throwaway project in CI — that would cost a slot on a two-project account. The failure is fully determined by the SQL text, so the text is what is checked. If a future statement needs a Cloud privilege postgres lacks in some other schema, this test will not see it.

…abase project

Applying supabase/migrations/20251006_complete_monolithic_setup.sql to a project
created today aborted with

    42501: permission denied for schema auth

and, because the file is one BEGIN;...COMMIT;, left ZERO tables. Forking is
supposed to end with the fork pointing at its own Supabase project, so this broke
the one path every fork must take.

One statement needed CREATE on schema auth:

    CREATE OR REPLACE FUNCTION auth.jwt() ...

It exists only to forward-fill a stub for the LOCAL supabase/postgres image, where
GoTrue has not booted and CREATE POLICY would otherwise fail at parse time. That
reasoning is correct and still applies, so the statement is guarded rather than
removed -- it now runs only where auth.jwt() is genuinely absent. Identical local
behaviour; a no-op on Cloud, where the function already exists and is owned by
supabase_auth_admin.

Not the cause, though it looks like it: the on_auth_user_created trigger on
auth.users is fine. postgres holds TRIGGER on that table, verified by a create/drop
probe on a fresh project, and the trigger is present there after the fix.

Verified end to end on a genuinely new project (us-east-1): 19 tables and 75
policies, identical counts to this repo's production project, plus 25 functions and
13 triggers.

Also adds scripts/__tests__/migration-provisions-a-new-cloud-project.test.js, which
splits the file into real top-level statements -- dollar-quote aware, comments
stripped -- and fails if any of them creates or alters an object inside the auth
schema. It carries its own falsifiers: auth.uid() in a policy body and a trigger ON
auth.users must NOT trip it, a commented-out copy of the old statement must NOT trip
it, and an unguarded CREATE ... auth.jwt() MUST. Mutation-tested against the real
file: reverting the guard fails the suite, restoring it passes byte-identical.

Closes #929

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@TortoiseWolfe
TortoiseWolfe merged commit d0975ae into main Aug 22, 2026
49 of 50 checks passed
@TortoiseWolfe
TortoiseWolfe deleted the fix/monolithic-migration-new-cloud-project branch August 22, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Monolithic migration aborts on a newly-created Supabase project (42501 on schema auth), so no fork can provision its own backend

2 participants