Skip to content

fix(config): retire push-capability pruning from ProjectConfig (CLI-2314) - #6469

Merged
Coly010 merged 14 commits into
developfrom
columferry/cli-2314-supabaseconfig-retire-push-capability-pruning-make-silence
Sep 4, 2026
Merged

fix(config): retire push-capability pruning from ProjectConfig (CLI-2314)#6469
Coly010 merged 14 commits into
developfrom
columferry/cli-2314-supabaseconfig-retire-push-capability-pruning-make-silence

Conversation

@Coly010

@Coly010 Coly010 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

fromConfigDocument baked the legacy config push pipeline's write-capability envelope into the
shared ProjectConfig representation (ADR 0021's original "push convergence" ruling). That was
right when the CLI's own push command was the only reader; it's wrong now that Studio reads the
same package for drift detection via the Management API, an actor with none of push's write-path
limitations. Concretely, this hid real hosted customization from every consumer — not just push —
behind three families of unconditional/blanket omissions.

Builds on #6454 (CLI-2313, merged into develop) — this branch has already been rebased onto
develop post-merge. Nothing here depends on the v2 PATCH endpoint (BRA-245/CLI-2317); everything
works over the v1 write endpoints #6454 already wired up.

Linear: CLI-2314.

What changed

  • applyPushUnmanagedOmissions deleted — this unconditionally dropped the whole
    auth.oauth_server subtree and dropped storage.analytics/storage.vector entirely whenever
    enabled: false, because legacy push never sent those shapes. That pipeline no longer exists
    (CLI-2313 deleted config-sync/*.sync.ts); push now consumes ProjectConfig directly.
  • DISABLED_SENTINEL_PRUNES re-derived from the platform's actual data model, not from what
    legacy push happened to send. Every surviving entry's docstring now states a real, verified
    reason a sibling field goes inert server-side when its container is off (e.g. api.enabled is
    the same wire fact as db_schema.length > 0, not an independent field the API arm doesn't
    already gate on its own). A new cross-arm symmetry test makes this machine-checked: a disabled
    document projection and the equivalent disabled API-response projection must be byte-identical.
  • Deleted the auth.enabled/storage.enabled blanket section-prunes. These had nothing to do
    with the platform — auth.enabled is literally "Enable the local GoTrue service" with no
    hosted/registry equivalent, yet disabling it wiped the entire rest of the auth section (SMTP,
    external providers, captcha, everything) from the shared representation for anyone reading it.
    Fixed a real bug this exposed: push.plan.ts's legacyPushResourceEnabled was gating the
    entire auth/storage resource dispatch on that same local toggle, so a declared change could
    be silently dropped. auth/storage now follow the same no-gate pattern api/db.settings
    already used. No new "default comparison" machinery was needed — diffProjectConfig's existing
    declared flag (computed generically from raw TOML presence for every comparable path) already
    keeps an undeclared default value from ever being pushed over a real hosted customization.
  • auth.oauth_server.* wired up as genuinely pushable. It's writable via UpdateAuthConfigBody
    (confirmed against the OpenAPI spec) — push's own SIDE_EFFECTS.md had been carrying it in the
    unsupported-prefix list as an explicitly-labeled placeholder for this exact issue.
  • Named ConfigAbsencePolicy ("absent-is-default" / "absent-is-hands-off") for the two
    operand policies fromConfigDocument always implicitly implemented depending on which overload
    you called. Documents the one genuinely hazardous cell (an absent field masquerading as a real
    declaration when diffing in dense mode) and the declaredRoot = {} cliff a caller hits by
    omitting document — exactly the calling shape Studio would use.
  • Unmanaged caveat reworded to actor-neutral language ("not managed while its section is
    disabled" instead of "cannot be pushed").
  • ADR 0021 addendum reframing ProjectConfig as a shared multi-actor representation, plus
    matching touch-ups to ADR 0022/0023 and cleanup of stale references to the deleted function.

Verification (post-rebase onto develop)

  • packages/config: bun --bun vitest run --project unit — 1264 passed.
  • apps/cli: pnpm types:check clean; pnpm test:unit — 5984 passed, 1 skipped;
    pnpm test:integration — 3438 passed.

Follow-ups (out of scope here)

  • Consider a local.auth.enabled/local.storage.enabled namespace so supabase start's "run this
    Docker service" concept is structurally separate from hosted management, instead of overloading
    auth.enabled/storage.enabled.
  • Audit LEGACY_PUSH_UNSUPPORTED_PREFIXES's remaining db.pooler entry against the OpenAPI spec —
    pool_mode/default_pool_size are writable via UpdateSupavisorConfigBody, only
    max_client_conn genuinely isn't.

@Coly010
Coly010 requested a review from a team as a code owner September 4, 2026 17:29
@Coly010 Coly010 self-assigned this Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Supabase CLI preview

npx --yes https://pkg.pr.new/supabase/cli/supabase@0676789936a20d45f59a17dd2184153a4b290a35

Preview package for commit 0676789.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 AI Review

All 13 deduplicated findings were verified and confirmed. The most consequential issues are silently skipped email-template bodies when local Auth is disabled and newly pushable stock-template values that can disable or overwrite hosted configuration. The remaining findings concern inaccurate documentation, stale test fixtures, and missing positive coverage.

Findings

Severity Location Category Sources Claim
🟠 MAJOR packages/config/src/project-config/project-config.ts:753 compatibility claude A stock [storage.analytics] enabled = false declaration now becomes an update that disables a remotely enabled Analytics/Iceberg catalog.
🟠 MAJOR apps/cli/src/legacy/commands/config/push/push.encoders.ts:1387 compatibility claude The stock [auth.oauth_server] enabled = false declaration can now disable a hosted OAuth server that was enabled outside the CLI.
🟠 MAJOR apps/cli/src/legacy/commands/config/push/push.plan.ts:188 compatibility claude Users who set the local-only auth.enabled toggle false can now push all other stock Auth declarations, including local-development URLs, over hosted values.
🟠 MAJOR apps/cli/src/legacy/commands/config/push/push.handler.ts:316 correctness claude+codex Auth email template and notification bodies are silently skipped when auth.enabled is false even though the Auth resource and its other declared fields are now pushed.
🟡 MINOR apps/cli/src/legacy/commands/config/push/SIDE_EFFECTS.md:102 documentation claude The push side-effects documentation still says auth.enabled and storage.enabled gate their resources, contradicting the new implementation.
🟡 MINOR apps/cli/src/legacy/commands/config/push/push.handler.ts:568 documentation claude The handler comment incorrectly says only db.network_restrictions can receive disabled status; undeclared db.ssl_enforcement does too.
🟡 MINOR apps/cli/src/legacy/commands/config/pull/pull.handler.ts:242 documentation claude The claim that every prune depends on the written path's own state and that the unpushable branch has no live trigger is false for the SMTP-to-email-rate-limit presence cascade.
🟡 MINOR apps/cli/src/legacy/commands/config/pull/pull.integration.test.ts:599 test-coverage claude The pull unpushable-warning path no longer has positive integration or rendering coverage after the OAuth-server test was changed to negative assertions.
🟡 MINOR apps/cli/src/legacy/commands/config/config.format.ts:193 user-output claude+codex The unmanaged-path message falsely says every omitted path belongs to a disabled section.
🟡 MINOR packages/config/src/project-config/project-config.ts:799 documentation claude The DISABLED_SENTINEL_PRUNES header still describes obsolete legacy-push behavior and attributes rules to the wrong constant.
⚪ NIT packages/config/src/config-diff.ts:89 documentation claude The ConfigChangeSet.unmanaged docstring still defines the concept specifically as state config push cannot communicate, despite the PR's actor-neutral semantics.
⚪ NIT packages/config/src/project-config/project-config.ts:857 documentation codex The SMTP sentinel comment says host is excluded from dropKeys, but the rule includes it.
⚪ NIT apps/cli/src/legacy/commands/config/push/push.format.unit.test.ts:656 test-quality claude Formatter tests still use auth.oauth_server.enabled as an unmanaged path and a gated-off Auth resource, states the production pipeline can no longer produce.

Findings outside the diff

  • 🟠 MAJOR apps/cli/src/legacy/commands/config/push/push.handler.ts:316 — Auth email template and notification bodies are silently skipped when auth.enabled is false even though the Auth resource and its other declared fields are now pushed.
  • ⚪ NIT apps/cli/src/legacy/commands/config/push/push.format.unit.test.ts:656 — Formatter tests still use auth.oauth_server.enabled as an unmanaged path and a gated-off Auth resource, states the production pipeline can no longer produce.

Stats

Claude findings: 12 · Codex findings: 3 · Confirmed: 13 · Refuted: 0 · Uncertain: 0


Models: claude-opus-5 + gpt-5.6-sol · Trigger: auto · Workflow run

This review runs once per PR. A maintainer can request another with a /ai-review comment.

Comment thread packages/config/src/project-config/project-config.ts
Comment thread apps/cli/src/legacy/commands/config/push/push.encoders.ts
Comment thread apps/cli/src/legacy/commands/config/push/push.plan.ts
Comment thread apps/cli/src/legacy/commands/config/push/SIDE_EFFECTS.md Outdated
Comment thread apps/cli/src/legacy/commands/config/push/push.handler.ts Outdated
Comment thread apps/cli/src/legacy/commands/config/pull/pull.integration.test.ts
Comment thread apps/cli/src/legacy/commands/config/config.format.ts Outdated
Comment thread packages/config/src/project-config/project-config.ts Outdated
Comment thread packages/config/src/config-diff.ts Outdated
Comment thread packages/config/src/project-config/project-config.ts Outdated
- push.handler.ts: stop gating auth email template/notification content
  loading on auth.enabled, which silently pushed empty content over real
  hosted customization now that the auth resource is always considered
- fix stale docs that still described the pre-CLI-2314 auth/storage
  gate, the wrong resource-disabled example, and the wrong constant for
  hook/SMS sentinel rules
- fix a comment that claimed host was excluded from the SMTP dropKeys
  list when it is included
- reword the unmanaged-path message to not assume every omission is
  caused by a disabled section (SMTP-linked rate-limit and unselected
  SMS provider credentials are omitted for other reasons)
- add positive integration coverage for the pull "unpushable" warning,
  which had none since the oauth_server case was rewritten to negative
  assertions; corrects the accompanying docstrings, which understated
  the real (narrower) trigger condition once actually verified
- repoint stale oauth_server.enabled/disabled-resource fixtures in
  formatter unit tests to states the pipeline can still produce
Review round follow-up: still framed unmanaged paths as specifically
what config push cannot communicate, and didn't mention the
cross-path smtp/rate_limit_email_sent case.
@Coly010

Coly010 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the AI review round (13 findings). Two of them were reported "outside the diff" with no inline thread to reply to directly:

  • MAJOR, correctness (push.handler.ts:316): confirmed real. Auth email template/notification content loading was still gated on config.auth.enabled, silently substituting {template: {}, notification: {}} when it's false — even though the auth resource is now always considered for push regardless of that flag. That meant a user with auth.enabled = false and genuinely customized email templates would have had them silently dropped from the push instead of sent. Fixed in e46fdbd16 by removing the gate; legacyLoadAuthEmailContent is a pure file read independent of that flag.
  • NIT, test-quality (push.format.unit.test.ts:656): fixed in e46fdbd16 — repointed the stale auth.oauth_server.enabled-as-unmanaged and storage-as-disabled formatter fixtures to states the pipeline can still actually produce.

The other 11 findings each got a reply on their own thread. 8 are fixed and those threads are resolved. 3 (the storage.analytics/oauth_server/auth-stock-declarations "compatibility" findings) are confirmed accurate but are the direct, intended consequence of what this PR set out to do — I've left those open with the existing mitigation (push's per-resource interactive confirmation) explained, flagged for your call rather than deciding unilaterally on a design we worked out together.

Commits: e46fdbd16 (main batch), 479a2cd67 (one docstring follow-up). Full suite re-verified green after both: packages/config 1264 passed, apps/cli unit 5984+1 skipped, integration 3439 passed.

…note

CI's fmt:check caught oxfmt table-alignment drift from an earlier
manual edit. Also corrected the Files Read table's auth email template
row, which still said content is only read "when auth.enabled" -
that gate was removed in the CLI-2314 review-round fix (e46fdbd).
…eed risk

Review round decision (not a code change): the interactive per-resource
confirmation is accepted as sufficient mitigation for previously-invisible
fields (storage.analytics, auth.oauth_server, auth's stock dev values)
becoming genuinely pushable. Spelling out in --help that a non-interactive
run defaults to proceeding without an explicit answer, so a script or
agent driving this command should check `config diff` first rather than
relying on a prompt it may not observe.
Nothing in this repo consumes it via the root entrypoint — the only
real usage is packages/config's own internal import from
./project-config/hosted-sections.ts, which predates this PR and is
untouched. It was added purely on the assumption that Studio (a
separate repo) would want it; add it back if and when that repo
actually asks for it.
@Coly010
Coly010 added this pull request to the merge queue Sep 4, 2026
Merged via the queue into develop with commit 2677ccc Sep 4, 2026
36 of 37 checks passed
@Coly010
Coly010 deleted the columferry/cli-2314-supabaseconfig-retire-push-capability-pruning-make-silence branch September 4, 2026 19:56
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.

2 participants