fix(cli): provision platform baseline in declarative baseline catalog#5521
Conversation
The baseline catalog (catalog-baseline-<version>.json) was exported from a
bare shadow database before any platform setup ran. That same catalog is
reused by getMigrationsCatalogRef as the diff source when there are zero
local migrations. After the declarative target started provisioning the
Supabase platform baseline (auth/storage/realtime), the no-migrations sync
diffed an empty-image source against a platform-baseline + declarative
target, so platform-managed objects surfaced as spurious additions/drops in
generated migrations.
Provision the platform baseline in getGenerateBaselineCatalogRef before
exporting, so the baseline catalog consistently represents "platform
baseline, no user migrations" — identical to MigrateShadowDatabase with zero
migrations and in parity with the declarative target. The now-redundant
second setup call in Generate's cache-warm path is removed since the reused
shadow already has the baseline.
RED before fix:
expected: []string{"setup", "export"}
actual : []string{"export"}
Add a full-flow test driving Generate -> DiffDeclarativeToMigrations with no local migrations through the public command functions. It models pg-delta catalog content by shadow setup/apply state and stubs the Docker/pg-delta seams (the established cli-go pattern), so it runs in the standard `go test ./...` CI job. The test pins the regression fixed in the previous commit: generate must write the baseline catalog from the platform baseline, and a no-migration sync must reuse it as the diff source so platform-managed objects (auth/storage/realtime) cancel out instead of leaking into the generated migration. To diff through the public path without the real pg-delta runtime, diff.DiffPgDeltaRef is now an injectable package var (diffPgDeltaRef), matching the existing exportCatalog / declarativeExportRef / applyDeclarative seams. RED (pre-fix wiring) — generated migration leaked platform objects: "create auth;\ncreate public.profiles;\ncreate realtime;\ncreate storage;\n" should not contain "create auth;" GREEN (with fix) — only "create public.profiles;" is generated.
Coverage Report for CI Build 27204703528Coverage increased (+0.3%) to 64.618%Details
Uncovered ChangesNo uncovered changes found. Coverage Regressions152 previously-covered lines in 2 files lost coverage.
Coverage Stats
💛 - Coveralls |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9f63a3c80f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Supabase CLI previewnpx --yes https://pkg.pr.new/supabase@5521Preview package for commit |
The platform baseline catalog is produced by SetupDatabase (initSchema + ApplyApiPrivileges + vault secrets + supabase/roles.sql), so its contents are a function of the Postgres image AND the project inputs setup consumes — not the image alone. The cache key was still only the image version token, which meant: - A bare baseline written by a pre-fix CLI (keyed by the same token) was reused as the no-migration sync source, re-leaking platform objects until .temp/pgdelta was cleared. - Changing auto_expose_new_tables, vault secrets, or roles.sql after a generate left sync reusing a baseline built from the old config. Key the baseline catalog by a hash of the image token plus those setup inputs (baselineCatalogKey), resolved through a single baselineCatalogPath helper used by both the generate writer and the no-migration sync reader. Old bare-baseline filenames no longer match, so they are never reused, and config/roles changes self-invalidate the cache. Addresses Codex review feedback on #5521.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3dfa1ca491
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The previous commit keyed only the baseline catalog by setup inputs, which
left its sibling caches inconsistent and able to pair a freshly keyed source
with a stale snapshot from a different platform setup:
- baselineCatalogKey ignored the auth/storage/realtime service toggles that
gate initSchema, so toggling a service on the same image reused a stale
baseline.
- The zero-migration branch of getMigrationsCatalogRef fell through to the
migrations-hash cache (pgcache), which is not setup-aware, so an old
empty-migrations snapshot could be reused as the no-migration sync source.
- The warmed declarative target catalog was keyed only by the declarative
SQL hash, so a setup change with unchanged SQL paired a fresh source
baseline with a stale target.
Introduce a single setupInputsToken (image + service toggles + api +
vault + roles.sql) and thread it through all three caches: the baseline
key, a new declarativeCatalogCacheKey for the warmed target, and the
zero-migration path now reads/writes the setup-keyed baseline instead of
the migrations-hash cache. Every catalog in the flow is "platform baseline +
{nothing | migrations | declarative}", so each cache now self-invalidates on
setup changes.
Addresses follow-up Codex review feedback on #5521.
…supabase#5521) Refs CLI-1601 — https://linear.app/supabase/issue/CLI-1601/support-auth-dependencies-in-shadow-db-migrations Follow-up to supabase#5515. That PR taught the declarative apply path to provision the Supabase platform baseline (auth/storage/realtime) on the shadow before applying declarative schemas. This fixes a gap it left in the `generate` → `sync`-with-no-migrations handoff. ## The bug `getGenerateBaselineCatalogRef` exports `.temp/pgdelta/catalog-baseline-<version>.json` immediately after creating the shadow — **before** any platform setup runs — so the cached baseline represents a bare postgres image. That same file is reused by `getMigrationsCatalogRef` as the diff **source** when there are zero local migrations. After supabase#5515, the declarative **target** is built on top of the platform baseline. So a no-migration `sync` diffs: - source: bare postgres image - target: platform baseline + declarative schema instead of the intended: - source: platform baseline - target: platform baseline + declarative schema Platform-managed objects (`auth`, `storage`, `realtime`, grants, functions, …) no longer cancel and surface as spurious additions in the generated migration — e.g. a single declarative `public.profiles` table referencing `auth.users` produces a migration that also tries to create the `auth`/`storage`/`realtime` platform objects. ## The fix Provision the platform baseline in `getGenerateBaselineCatalogRef` **before** exporting, so the baseline catalog consistently means "platform baseline, no user migrations" — identical to `diff.MigrateShadowDatabase` with zero migrations, and in parity with the declarative target. The now-redundant second `setupShadowDatabase` call in `Generate`'s cache-warm path is removed since the reused shadow already has the baseline (it was previously provisioning the platform twice). This also fixes a latent `generate` issue: with a bare baseline, `generate` would have emitted platform schemas into the user's declarative files. ## Tests - `TestGetGenerateBaselineCatalogRefSetsUpPlatformBaseline` — pins the setup-before-export ordering. - `TestGenerateThenSyncWithNoMigrationsCancelsPlatformObjects` — full generate → no-migration sync flow through the public command functions, asserting only the user's table is generated and platform objects cancel. Docker/pg-delta seams are stubbed (the established cli-go pattern), so it runs in the standard `go test ./...` CI job. `diff.DiffPgDeltaRef` is now an injectable package var to allow diffing through the public path without the real pg-delta runtime. https://claude.ai/code/session_01ACrX8NXcsYLENnCRXAub3S --- _Generated by [Claude Code](https://claude.ai/code/session_01ACrX8NXcsYLENnCRXAub3S)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Refs CLI-1601 — https://linear.app/supabase/issue/CLI-1601/support-auth-dependencies-in-shadow-db-migrations
Follow-up to #5515. That PR taught the declarative apply path to provision the Supabase platform baseline (auth/storage/realtime) on the shadow before applying declarative schemas. This fixes a gap it left in the
generate→sync-with-no-migrations handoff.The bug
getGenerateBaselineCatalogRefexports.temp/pgdelta/catalog-baseline-<version>.jsonimmediately after creating the shadow — before any platform setup runs — so the cached baseline represents a bare postgres image.That same file is reused by
getMigrationsCatalogRefas the diff source when there are zero local migrations. After #5515, the declarative target is built on top of the platform baseline. So a no-migrationsyncdiffs:instead of the intended:
Platform-managed objects (
auth,storage,realtime, grants, functions, …) no longer cancel and surface as spurious additions in the generated migration — e.g. a single declarativepublic.profilestable referencingauth.usersproduces a migration that also tries to create theauth/storage/realtimeplatform objects.The fix
Provision the platform baseline in
getGenerateBaselineCatalogRefbefore exporting, so the baseline catalog consistently means "platform baseline, no user migrations" — identical todiff.MigrateShadowDatabasewith zero migrations, and in parity with the declarative target. The now-redundant secondsetupShadowDatabasecall inGenerate's cache-warm path is removed since the reused shadow already has the baseline (it was previously provisioning the platform twice).This also fixes a latent
generateissue: with a bare baseline,generatewould have emitted platform schemas into the user's declarative files.Tests
TestGetGenerateBaselineCatalogRefSetsUpPlatformBaseline— pins the setup-before-export ordering.TestGenerateThenSyncWithNoMigrationsCancelsPlatformObjects— full generate → no-migration sync flow through the public command functions, asserting only the user's table is generated and platform objects cancel. Docker/pg-delta seams are stubbed (the established cli-go pattern), so it runs in the standardgo test ./...CI job.diff.DiffPgDeltaRefis now an injectable package var to allow diffing through the public path without the real pg-delta runtime.https://claude.ai/code/session_01ACrX8NXcsYLENnCRXAub3S
Generated by Claude Code