feat(cli): apply local stack configuration parity - #6092
Conversation
# Conflicts: # packages/stack/src/StackBuilder.ts # packages/stack/src/StackBuilder.unit.test.ts # packages/stack/src/services/analytics.ts # packages/stack/src/services/auth.ts # packages/stack/src/services/mailpit.ts # packages/stack/src/services/postgres.ts # packages/stack/src/services/postgrest.ts # packages/stack/src/services/realtime.ts # packages/stack/src/services/services.unit.test.ts # packages/stack/src/services/storage.ts # packages/stack/src/services/studio.ts
…k-launch-adapter # Conflicts: # packages/stack/docs/architecture.md # packages/stack/src/LocalStack.ts
…l-stack-launch-adapter # Conflicts: # apps/cli/src/next/config/local-stack-config-parity.ts # apps/cli/src/next/config/local-stack-config-parity.unit.test.ts
…l-stack-launch-adapter # Conflicts: # apps/cli/src/next/config/local-stack-config-parity.ts # apps/cli/src/next/config/local-stack-config-parity.unit.test.ts
…l-stack-launch-adapter # Conflicts: # apps/cli/src/next/config/local-stack-config-parity.ts # apps/cli/src/next/config/local-stack-config-parity.unit.test.ts
…e/cli into agent/local-stack-launch-adapter
…e/cli into agent/local-stack-launch-adapter
…upabase/cli into agent/local-stack-launch-adapter # Conflicts: # apps/cli/src/next/config/local-stack-config-parity.ts # apps/cli/src/next/config/local-stack-config-parity.unit.test.ts
…e/cli into agent/local-stack-launch-adapter
…upabase/cli into agent/local-stack-launch-adapter # Conflicts: # apps/cli/src/next/config/local-stack-config-parity.ts # apps/cli/src/next/config/local-stack-config-parity.unit.test.ts
…' into agent/local-stack-launch-adapter # Conflicts: # packages/stack/src/services/health-budgets.ts # packages/stack/src/services/health-budgets.unit.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 48c1da6e1c
ℹ️ 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".
| elif [ "$applied_hash" != "$checksum" ]; then | ||
| echo "Updating seed hash to $history_path..." | ||
| update_seed_hash "$history_path" "$checksum" |
There was a problem hiding this comment.
Re-run dirty seed SQL before updating its hash
When a seed already exists in supabase_migrations.seed_files with a different checksum, this branch only updates the stored hash and never calls apply_seed. In a reused local stack after editing supabase/seed.sql, the database does not receive the new SQL, but the hash is advanced so future starts consider it applied; dirty seeds need to execute the seed batch before recording the new checksum.
Useful? React with 👍 / 👎.
| if (loaded.appliedRemote === undefined || loaded.document === undefined) return false; | ||
| const remotes = nestedValue(loaded.document, ["remotes"]); | ||
| if (!isRecord(remotes)) return false; | ||
| const remote = remotes[loaded.appliedRemote]; | ||
| return isRecord(remote) && nestedValue(remote, path) !== undefined; |
There was a problem hiding this comment.
Preserve remote DB bootstrap precedence
Real loadProjectConfigFile removes the remotes subtree after merging the selected remote, so loaded.document.remotes is absent for an applied remote and remoteDefines() returns false. With a remote that sets db.seed.enabled or db.migrations.enabled and a conflicting SUPABASE_DB_* env var, the env var wins and can enable seeds or migration discovery that the selected remote disabled; consult loaded.remoteOverridePaths instead of the stripped document.
Useful? React with 👍 / 👎.
| if (secret.length < 32) { | ||
| throw new LocalCredentialsError({ | ||
| path, | ||
| detail: "The local JWT shared secret must contain at least 32 characters.", |
There was a problem hiding this comment.
Accept Go-compatible JWT secrets
Configs with auth.jwt_secret between 16 and 31 characters are accepted by the Go CLI, but this new credentials resolver rejects them before the stack starts. Since translateAuthStackConfig now passes the project auth.jwt_secret into credentials.signing, existing local configs in that range regress; lower this threshold to the Go-compatible 16-character minimum or reject it earlier as an intentional parity break.
Useful? React with 👍 / 👎.
| return Object.fromEntries( | ||
| Object.entries(input.external).map(([name, provider]) => { |
There was a problem hiding this comment.
Preserve custom Auth providers
For [auth.external.<custom>] entries, Go keeps the provider in its external-provider map, but the project schema does not expose unknown provider ids on ProjectConfig["auth"]["external"]. Iterating only input.external therefore drops a configured custom provider, so local Auth starts without a provider the user configured; include or explicitly block raw authDocument.external keys that are not in the schema-known set.
Useful? React with 👍 / 👎.
| const gcp = | ||
| enabled && backend === "bigquery" | ||
| ? { | ||
| projectId: required( |
There was a problem hiding this comment.
Skip BigQuery checks when analytics is excluded
When a project has analytics.enabled = true and backend = "bigquery" but the user launches with --exclude analytics, resolveCoreStackConfig passes base.analytics = false, yet this branch still requires the BigQuery GCP fields before honoring input.base === false. That makes an intentionally excluded analytics service abort startup because of missing credentials for a service that will not run; return false before validating analytics-only settings.
Useful? React with 👍 / 👎.
| envBoolean({ | ||
| loaded: input.loadedProjectConfig, | ||
| environment: input.projectEnvironment, | ||
| configured: smtpDocument.enabled === undefined ? true : auth.email.smtp?.enabled === true, |
There was a problem hiding this comment.
Respect an omitted SMTP enabled flag
When the raw [auth.email.smtp] table is present but enabled is omitted, this forces SMTP on even though the decoded config default is enabled = false and Go only validates/uses SMTP when that flag is true. A config that merely declares the table or leaves commented examples partially uncommented now requires host/port/user/pass and changes Auth behavior; use the decoded auth.email.smtp?.enabled value unless an environment override explicitly enables SMTP.
Useful? React with 👍 / 👎.
| uri: envString({ | ||
| loaded: input.loaded, | ||
| environment: input.environment, | ||
| path: `auth.hook.${name}.uri`, | ||
| configured: hook.uri, | ||
| enabled: sectionPresent, | ||
| }), | ||
| secrets: envString({ |
There was a problem hiding this comment.
Validate enabled Auth hooks before exporting them
When an auth.hook.* entry is enabled, Go rejects configs with no uri, and HTTP/HTTPS hooks also require secrets. This mapper just forwards undefined values as empty Auth env vars, so an enabled-but-incomplete hook can start Auth with invalid hook settings instead of failing during config translation; apply the same validation before returning the hook.
Useful? React with 👍 / 👎.
| enableSignup: envBoolean({ | ||
| loaded: input.loadedProjectConfig, | ||
| environment: input.projectEnvironment, | ||
| configured: auth.sms.enable_signup, | ||
| path: "auth.sms.enable_signup", | ||
| }), |
There was a problem hiding this comment.
Disable phone signup without an SMS provider
When auth.sms.enable_signup is true but none of the SMS providers is enabled, Go's validation warns and flips phone signup back to false. This translation preserves the true value while resolveSmsProvider() returns undefined, causing Auth to receive phone signup enabled with no provider configured; mirror the Go fallback before building the Auth config.
Useful? React with 👍 / 👎.
| mode, | ||
| startupMode: "lazy", | ||
| startupMode, | ||
| edgeRuntime: excluded.has("edge-runtime") ? false : {}, |
There was a problem hiding this comment.
Keep Edge Runtime off for native launches
For --mode native with the other docker-only services disabled, setting edgeRuntime to {} prevents StackConfigResolver's native-mode default from disabling Edge Runtime when it is unspecified. The resolved config then includes the docker-only Edge Runtime and StackBuilder rejects the launch unless users also add --exclude edge-runtime; leave this field undefined in native mode unless explicitly requested.
Useful? React with 👍 / 👎.
Builds one deep launch adapter that resolves project config, environment bindings, remote overrides, exclusions, database bootstrap inputs, and functions into explicit stack runtime inputs.
Adds an executable parity ledger so unsupported local-start settings fail or warn deliberately instead of being silently ignored. Implements core topology, Auth and credential translation, data-plane services, ordered seed bootstrap, and functions configuration while preserving lazy Edge Runtime activation and secure JWKS-based verification.
Conventional migrations remain blocked when enabled migration files are present, and declarative schema paths remain blocked. Replaying either through a partial executor would lose legacy statement-history, pipeline, or schema-diff semantics; those settings should only be enabled after a parity-correct executor exists.
Depends on #6090 and #6079.