Skip to content

chore(repo): sync develop into next - #7371

Merged
supabase-cli-releaser[bot] merged 44 commits into
nextfrom
sync/develop-into-next
Oct 29, 2026
Merged

supabase-cli-releaser[bot] merged 44 commits into
nextfrom
sync/develop-into-next

Conversation

@supabase-cli-releaser

Copy link
Copy Markdown
Contributor

Merging develop into next conflicts. This branch starts at the tip of develop (8d94420); next is at 9752843.

Conflicting files:

  • .github/workflows/cli-go-ci.yml
  • .oxlintrc.effect.json
  • apps/cli-go/api/v1-openapi.yaml
  • apps/cli-go/pkg/api/types.gen.go
  • apps/cli-go/pkg/config/templates/Dockerfile
  • apps/cli/AGENTS.md
  • apps/cli/scripts/build.ts
  • apps/cli/scripts/render-service-dockerfile.ts
  • apps/cli/scripts/render-service-dockerfile.unit.test.ts
  • apps/cli/scripts/update-homebrew.ts
  • apps/cli/src/command-internal/config-validate.parity.unit.test.ts
  • apps/cli/src/command-internal/db-bootstrap/bootstrap-config.ts
  • apps/cli/src/command-internal/db-bootstrap/local-container-inputs.ts
  • apps/cli/src/command-internal/db-bootstrap/start-local-database.ts
  • apps/cli/src/command-internal/db-config.toml-read.ts
  • apps/cli/src/command-internal/functions-local-config.ts
  • apps/cli/src/command-internal/go-proxy-target-env.integration.test.ts
  • apps/cli/src/command-internal/go-proxy.layer.ts
  • apps/cli/src/command-internal/go-proxy.layer.unit.test.ts
  • apps/cli/src/command-internal/local-config-values.ts
  • apps/cli/src/command-internal/local-config-values.unit.test.ts
  • apps/cli/src/command-internal/local-project-context.ts
  • apps/cli/src/command-internal/migration-apply.unit.test.ts
  • apps/cli/src/command-internal/stack-config.ts
  • apps/cli/src/command-internal/status-values.ts
  • apps/cli/src/command-internal/status-values.unit.test.ts
  • apps/cli/src/command-internal/storage-credentials.ts
  • apps/cli/src/command-internal/supabase-env.ts
  • apps/cli/src/commands/branches/create/create.integration.test.ts
  • apps/cli/src/commands/db/diff/diff.integration.test.ts
  • apps/cli/src/commands/db/dump/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/dump/dump.integration.test.ts
  • apps/cli/src/commands/db/pull/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/pull/pull.integration.test.ts
  • apps/cli/src/commands/db/push/push.integration.test.ts
  • apps/cli/src/commands/db/reset/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/reset/reset.integration.test.ts
  • apps/cli/src/commands/db/schema/declarative/generate/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/schema/declarative/sync/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/start/SIDE_EFFECTS.md
  • apps/cli/src/commands/experimental/stack/start/start.handler.ts
  • apps/cli/src/commands/functions/deploy/SIDE_EFFECTS.md
  • apps/cli/src/commands/functions/download/SIDE_EFFECTS.md
  • apps/cli/src/commands/functions/serve/SIDE_EFFECTS.md
  • apps/cli/src/commands/functions/serve/serve.stack.e2e.test.ts
  • apps/cli/src/commands/inspect/db/inspect-query.integration.test.ts
  • apps/cli/src/commands/inspect/report/report.integration.test.ts
  • apps/cli/src/commands/migration/fetch/fetch.integration.test.ts
  • apps/cli/src/commands/migration/list/list.integration.test.ts
  • apps/cli/src/commands/migration/repair/repair.integration.test.ts
  • apps/cli/src/commands/migration/squash/SIDE_EFFECTS.md
  • apps/cli/src/commands/migration/squash/squash.integration.test.ts
  • apps/cli/src/commands/secrets/set/SIDE_EFFECTS.md
  • apps/cli/src/commands/secrets/set/set.handler.ts
  • apps/cli/src/commands/secrets/set/set.integration.test.ts
  • apps/cli/src/commands/services/services-local-stack.ts
  • apps/cli/src/commands/start/SIDE_EFFECTS.md
  • apps/cli/src/commands/start/start.gates.ts
  • apps/cli/src/commands/start/start.handler.ts
  • apps/cli/src/commands/start/start.integration.test.ts
  • apps/cli/src/commands/start/start.services.unit.test.ts
  • apps/cli/src/commands/status/SIDE_EFFECTS.md
  • apps/cli/src/commands/status/status.handler.ts
  • apps/cli/src/commands/stop/stop.handler.ts
  • apps/cli/src/commands/storage/storage.target-default-warning.integration.test.ts
  • apps/cli/src/shared/config/project-link.ts
  • apps/cli/src/shared/init/project-init.templates.unit.test.ts
  • apps/cli/src/shared/telemetry/__fixtures__/error-tags.txt
  • apps/cli/tests/helpers/command-mocks.ts
  • apps/cli/tests/helpers/live.ts
  • apps/cli/tests/helpers/mocks.ts
  • apps/cli/tests/helpers/storage.ts
  • apps/cli/tests/helpers/target-default-warning.ts
  • apps/cli/tests/smoke-test-macos.ts
  • apps/docs/public/cli/config.schema.json
  • packages/cli-test-helpers/src/harness.ts
  • packages/config/src/json-schema-document.ts
  • tools/release/local-release.ts

To resolve:

git fetch origin
git switch sync/develop-into-next
git merge origin/next
# resolve the conflicts, then commit
git push origin sync/develop-into-next

Approve to fast-forward next; do not use the merge button.

supabase-cli-releaser Bot and others added 30 commits October 23, 2026 14:45
This bumps storage from v1.84.21-r0 to v1.84.22-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.84.22-r0

Planned after supabase/slim-services published v1.84.22-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps storage from v1.84.22-r0 to v1.84.23-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.84.23-r0

Planned after supabase/slim-services published v1.84.23-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.147.1-r0 to v2.147.2-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.147.2-r0

Planned after supabase/slim-services published v2.147.2-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This PR was automatically created to sync API types from the
infrastructure repository.

Changes were detected after refreshing `apps/cli-go/api/v1-openapi.yaml`
from the latest spec from infrastructure, and `apps/cli-go/pkg/api` is
regenerated from it. The snapshot diff is the upstream API change and is
worth reading: it is marked `linguist-generated`, so GitHub collapses it
behind a "Load diff" click rather than hiding it.

Co-authored-by: supabase-cli-releaser[bot] <246109035+supabase-cli-releaser[bot]@users.noreply.github.com>
This bumps realtime from v2.147.2-r0 to v2.147.3-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.147.3-r0

Planned after supabase/slim-services published v2.147.3-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps studio from 2026.10.19-sha-b375769-r0 to
2026.10.26-sha-478bd88-r0.


https://github.com/supabase/slim-services/releases/tag/studio-2026.10.26-sha-478bd88-r0

Planned after supabase/slim-services published
2026.10.26-sha-478bd88-r0. This branch is rewritten from develop
whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Plan-gated Management API denials already return `{ error: { code:
"entitlement_required", feature, upgrade_url } }`. In `--output-format
json` and `stream-json` that signal only survives as escaped text inside
`error.message`, so an agent has to parse prose to learn that an upgrade
is needed and where. I added a structured `entitlement` to the
machine-mode error object for every command whose status errors go
through `mapHttpError`.

```json
{"_tag":"Error","error":{"code":"DomainsUnexpectedStatusError","message":"...","entitlement":{"feature":"custom_domain","upgrade_url":"https://supabase.com/dashboard/org/<slug>/billing"}}}
```

**Changed:**
- **Machine-mode errors carry the plan gate**: on a 4xx, `mapHttpError`
decodes the untruncated body and, when it is the plan-gate envelope,
attaches `entitlement: { feature, upgrade_url }` to the status error.
`normalizeCliError` passes it into the json and stream-json error
object, so commands with no per-command upgrade wiring (`branches
unpause`) get it too.
- **Handlers that rebuild a mapped error keep it**: `branches
create`/`update`, `vanity-subdomains activate`/`check-availability` and
`sso list`/`add`/`update`/`remove` forward the field, and `Output.fail`
declares it in its type.
- **Envelope values are validated in one place**: I moved the parser
into `http-errors.ts` and `suggestUpgrade` reuses it. `feature` must be
a plain key and `upgrade_url` an http(s) URL without credentials,
emitted as the parsed URL so control and bidi characters arrive
percent-encoded; anything else counts as no envelope.

**Note:** text output and `cli_upgrade_suggested` are unchanged for
well-formed envelopes. The per-command text hint stays until I move the
hint and the event onto the same central path in a follow-up.

## Linear
- part of GROWTH-1050
<!--
Before opening this PR, confirm the linked issue is open and carries the
`open-for-contribution` label. PRs from external contributors that don't
follow
the workflow in CONTRIBUTING.md are closed automatically.
@supabase members working from Linear tickets are exempt.
-->

## Summary

Adds a SECURITY.md file so we can get better signal on our security
reports.

## Linked issue

[Linear
Issue](https://linear.app/supabase/issue/SEC-993/securitymd-to-guide-researchers)

- [x] The linked issue is **open** and carries the
`open-for-contribution` label (or I'm a Supabase maintainer).

## Checklist

- [x] The PR title follows [Conventional
Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`).
- [ ] Tests added or updated for the change.
- [ ] From the repository root, `pnpm check:all` passes; relevant
package tests pass for every touched workspace, and `pnpm types:check`
passes for each touched TypeScript workspace (or workspace declaring
it).

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
This bumps postgres from 17.11.0.006-r0 to 17.11.0.007-r0.


https://github.com/supabase/slim-services/releases/tag/postgres-17.11.0.007-r0

Planned after supabase/slim-services published 17.11.0.007-r0. This
branch is rewritten from develop whenever a newer relevant release
arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.147.3-r0 to v2.147.4-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.147.4-r0

Planned after supabase/slim-services published v2.147.4-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…#7320)

## TL;DR

fixes restoring a `supabase db dump --role-only` file as `postgres`
failing on a parameter grant to a reserved role

## whats improved/fixed?

`supabase db dump --role-only` already comments out create, alter and
membership grant lines for reserved roles, but parameter grants like
`GRANT SET ON PARAMETER "log_min_messages" TO
"supabase_realtime_admin";` passed through

linked and local projects whose realtime setup grants this get that line
in `roles.sql`, so restoring it as `postgres` aborted with `permission
denied for parameter log_min_messages`

## how?

a new rule anchored to the start of the line comments out parameter
grants to reserved roles, in both the dump script and the in-process
filter the local stack uses

grants to other roles and grant text inside role setting values stay as
they are

## ref:

- closes: #7315
…LI-2837) (#7300)

## TL;DR

the delegated binary lookup and the project link writes run through
effect, ready for the effect lint

## whats improved/fixed?

- the binary lookup checks its paths through `FileSystem` and reads its
override env var through `Config`
- `.link.json` is written through schema json instead of
`JSON.stringify`
- the lookup and the permissions help tests run as effects with typed
errors

## how?

- the lookup keeps the same search order and the same not found message
- the link file keeps the same pretty printed bytes

> [!NOTE]
> nothing changes for users, the same binary is found and `.link.json`
is exactly the same
> these files join the effect lint in the last page of this stack.

## ref:

- related: CLI-2837
…7301)

## TL;DR

local config values, config validation and path containment run through
effect, so the effect lint now covers `apps/cli/src`

## whats improved/fixed?

- they read env through `Config` and files through `FileSystem`, and
fail with typed errors instead of throwing
- the config value tests pin env through a config provider instead of
editing `process.env`, so a shell override can no longer skew them
- the effect lint allow list swaps its per-file `command-internal`
entries for one `!apps/cli/src/**` entry

## how?

- `start`, `status`, `stop`, `services`, `notebooks`, `config push` and
`stack start`
yield the converted helpers and map failures with the same messages they
used to catch
- the error classes keep their names, so error codes and telemetry
fingerprints match develop.
- `SIDE_EFFECTS.md` notes now say `fs.realPath` where they said
`realpathSync`
> [!NOTE]
> (same here) nothing changes for users, 
> every command prints the same output and exits with the same codes and
errors.
>
> `local-db-running` stays excluded, it talks to the docker socket or
named pipe over node http and needs a windows check first.


## ref:

- closes: CLI-2837
…7309)

## TL;DR

brings `packages/api/src` and its tests under the effect lint

## whats introduced?

- `packages/api/src/**` joins the allow list, and the generated
`contracts.ts` stays out
- `SupabaseApiConfigError` and `SupabaseApiInputError` move to
`Data.TaggedError` with the same message, name, cause, json and printed
output, pinned by a new test, so two `apps/cli` call sites whose
failures include them now yield them directly
- `createApiClient` in `bun.ts` and `node.ts` chains its promise instead
of being `async`, still disposing the runtime before it rejects
- the src tests move to effect: `FileSystem` and `Path`, schema json
codecs, and `Effect.runPromise` bodies instead of `async` callbacks

## ref

- closes: CLI-2841
#7310)

## TL;DR

brings the `packages/api` generator scripts and their tests under the
effect lint, which completes the package

## whats introduced?

- the allow list entry widens to `packages/api/**`
- `download-openapi.ts` and `generate.ts` run as effect programs on
`FileSystem`, `HttpClient`, `Config` and `Console`, with the same
requests, console output, generated files and exit codes
- a failed run still prints the original error and exits 1, with effect
frames in the stack, and an empty `SUPABASE_API_URL` now reports
effect's `UrlError`
- the scripts tests move to effect, spawning turbo and oxfmt through
`ChildProcess`, and the `openapi.json` sync test now checks the
generator's own serializer

## ref

- closes: CLI-2842
- closes: CLI-2840
## TL;DR

brings `apps/cli/tests` and `apps/cli/vitest.config.ts` under the effect
lint

## whats introduced?

- `apps/cli/tests/**` and `apps/cli/vitest.config.ts` join the allow
list, replacing the seven per-file `tests/helpers` entries
- the test helpers, smoke tests and vitest config run on `FileSystem`,
`Path`, `Config` and `ChildProcess`, and promise helpers like
`runSupabase` keep their call shape and reject with the same values
- `spawnSupabase` and `makeTempHome` become scoped effects, and
`seedLegacyStateDecoys` and `setLinkedRefFile` become effects, so their
e2e and integration call sites yield them
- a timed out `until` run now kills its child and removes its temp home
instead of leaving both behind

## ref

- closes: CLI-2852
## Summary

`secret()` and `env({ secret: true })` mark config fields with
`x-secret`, but the published `config.schema.json` never carried it,
because the JSON Schema generator only emits standard keywords. The only
hint a field held a secret was the "do not commit" note in its
description, which tools can't act on.

The published CLI config schema now has `"x-secret": true` on every
field the schema marks secret. That includes the `remotes.*` copies and
the values of `db.vault` and `edge_runtime.secrets`. Editors ignore
unknown keywords, so validation and completion behave the same, and
nothing changes in how config is loaded.

- `toPublishedJsonSchemaDocument` now generates both published schemas
itself and lets only `x-secret` through, so internal annotations like
`x-env-deferred` stay out
- `project-config.schema.json` doesn't change, since it already leaves
secret fields out altogether
- `apps/docs/public/cli/config.schema.json` is regenerated, and the only
change is the added markers

## Linked issue

Closes CLI-2858
This bumps realtime from v2.147.4-r0 to v2.148.0-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.148.0-r0

Planned after supabase/slim-services published v2.148.0-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps storage from v1.84.23-r0 to v1.84.25-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.84.25-r0

Planned after supabase/slim-services published v1.84.25-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.148.0-r0 to v2.148.1-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.148.1-r0

Planned after supabase/slim-services published v2.148.1-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.148.1-r0 to v2.148.2-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.148.2-r0

Planned after supabase/slim-services published v2.148.2-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## TL;DR

unblocks go ci `Test`, red since #7287, by listing the nested `pkg`
module with `go list -C pkg` so pkg coverage returns and the coveralls
total drops

## ref:

<details>
<summary>as seen in:</summary>

<img width="529" height="751" alt="image"
src="https://github.com/user-attachments/assets/753837cc-7656-449c-ba53-525dbed7f385"
/>

</details>
…7336)

## TL;DR

brings `apps/cli/scripts` under the effect lint, so the allow list
collapses into one `!apps/cli/**` entry

## whats introduced?

- `apps/cli/scripts/**` joins the allow list, and the `src`, `tests` and
`vitest.config.ts` entries collapse into `!apps/cli/**`
- the build, release, publish and docs scripts run as effect programs on
`FileSystem`, `HttpClient` and `Config`, with the same arguments,
output, error messages, generated files and exit codes
- a failed run still crashes with the original error, so malformed json
keeps its native `SyntaxError`, and a signal during
`refresh-e2e-timings` still waits for its cleanup
- the scripts tests move to `it.effect` and `it.live` with the same
names and assertions

## ref

- closes: CLI-2853
- closes: CLI-2851
This bumps storage from v1.84.25-r0 to v1.84.28-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.84.28-r0

Planned after supabase/slim-services published v1.84.27-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…7347)

## Summary

In stack mode, Edge Functions that boot at the same time can fail with
`503 BOOT_ERROR`. The logs show `Failed caching npm package … File
exists (os error 17)`, or `No such file or directory` when reading a
cached package file. This sets `noModuleCache: false` when the stack
bootstrap creates user workers, which is what classic `functions serve`
already does.

### What's going on

`noModuleCache: true` puts the worker's Deno cache into reload mode.
Each worker builds its own npm cache, so nothing is shared between
workers, and each one downloads every npm package it imports again. When
that package is already in the shared `DENO_DIR`, Deno extracts it again
in place, over the live copy, deleting and recreating each file. Two
workers doing that at the same time collide, and a worker that reads a
file in the middle of it finds it missing.

```mermaid
flowchart TD
  boot["Worker boots and imports npm:pkg"] --> flag{"noModuleCache"}
  flag -- "false" --> cached{"pkg in the cache?"}
  cached -- "yes" --> reuse["Reuse it"]
  cached -- "no" --> temp["Extract to a temp dir,<br/>then rename into place"]
  flag -- "true" --> cached2{"pkg in the cache?"}
  cached2 -- "no" --> temp
  cached2 -- "yes" --> inplace["Extract again in place,<br/>over the live copy"]
  inplace --> fail["Concurrent boots collide<br/>503 BOOT_ERROR"]
```

```mermaid
sequenceDiagram
  participant A as Worker A
  participant C as Shared Deno cache
  participant B as Worker B
  A->>C: create pkg/README.md (exists, so delete it)
  B->>C: create pkg/README.md (succeeds)
  A->>C: create pkg/README.md
  C-->>A: File exists (os error 17)
  Note over A: 503 BOOT_ERROR
```

This explains the odd parts of the report:

- A package that isn't cached yet goes through the temp dir and rename,
which is safe. That's why a cold first round often passes, and why a
warm-up request doesn't help.
- Native keeps its cache across `stop` and `start`, so it fails much
more often than Docker, whose new container starts with an empty cache.
- `forceCreate: true` boots a new worker for every request, so every
request goes down this path. I've left it as it is, because it's what
makes edits show up without a restart.

Against Edge Runtime directly, with only this flag changed, 40 of 64
concurrent boots failed with it on and none of 112 failed with it off.

### What changes

- npm packages and remote modules are reused from the cache instead of
being downloaded and extracted on every boot, so boots are quicker too.
- An exact version that isn't cached yet still resolves, because Deno
fetches package info again when resolution fails. Floating versions like
`npm:x@latest` stay on the cached version until the cache resets (a new
container on Docker, `stack destroy` on native). That matches classic
`functions serve` and `deno run`.
- Local function code is still read from disk on every boot, so edits
show up straight away.
- A new integration test serves a package from a local npm registry,
warms the cache, then boots several workers at once. It checks that they
all succeed and that the package is downloaded only once.

Earlier bootstraps and classic `functions serve` use `false`. If `true`
was there for something I've missed, I'm happy to talk it through.

## Linked issue

Closes #7321 (CLI-2850)
…n the config schema (#7333)

## Summary

The config loader resolves `env(VAR)` on any field and then coerces it
to the field's type, but the published `config.schema.json` typed
number, integer, boolean, enum and string-list fields strictly. So
`max_rows = "env(MAX_ROWS)"` loads fine but shows as an error in the
editor.

Those fields now accept either their usual value or a string matching
the loader's `env()` syntax. A mistyped literal like `max_rows = "1000"`
or `pool_mode = "statement"` still fails.

- `toPublishedJsonSchemaDocument` takes an `acceptEnvReferences` option,
and the CLI config schema turns it on. Each affected field becomes an
`anyOf` of its original type and an `env()` string, with `description`,
`default` and `examples` kept on the outer node so hover docs look the
same
- String lists such as `auth.additional_redirect_urls` accept an `env()`
string in place of the whole list, since the CLI splits the resolved
value on commas. Lists of enums don't, as the loader doesn't split those
- Fields that are already a union (e.g. `storage.file_size_limit`) get
one extra `env()` branch rather than a nested one
- `project-config.schema.json` doesn't change, since it describes values
after `env()` has been resolved
- `apps/docs/public/cli/config.schema.json` is regenerated
- `ajv` is added as a dev dependency of `@supabase/config` so tests can
check the published schema against what the loader accepts

## Schema shape change

If you generate types or other tooling from `config.schema.json`, the
affected fields now read as a union: their `type` moves from the field
itself into the first `anyOf` branch, next to the `env()` branch.
Configs that validated before still validate.

## Linked issue

Closes CLI-2857
## TL;DR

adds an ECR Public fallback for slim images, so a GHCR rate limit no
longer fails `supabase start`

## whats introduced?

with `SUPABASE_USE_SLIM_IMAGES` on, slim images only came from GHCR, so
a `toomanyrequests` burst failed the command

a failed GHCR pull now falls back to the same tag and digest on
`public.ecr.aws/supabase/cli`,
the mirror the stack already uses
ps: containers started from the mirror keep their slim healthchecks and
pass the `db` stale image guard

<details><summary>visual rep:</summary>

```mermaid
flowchart LR
    pull["slim image pull"] --> ghcr["ghcr.io/supabase/cli"]
    ghcr -->|ok| run["container starts"]
    ghcr -->|"fails 3 times"| ecr["public.ecr.aws/supabase/cli<br/>same tag and digest"]
    ecr --> run
```

</details>

## ref

- closes: #7338
…7345)

## TL;DR

adds `X-Forwarded-For` and `X-Real-IP` to what the stack gateway sends
upstream, so edge functions can see who is calling them

## whats introduced?

the gateway now appends the client address to any incoming
`X-Forwarded-For` chain and sets
 `X-Real-IP` to the client address, the same way the legacy backend does

both the http path and the websocket upgrade path send them

a client sent `X-Real-IP` is always replaced or dropped, so callers cant
spoof it through the gateway

<details>
<summary>visual rep</summary>

```mermaid
flowchart LR
  subgraph before
    A1[client] --> B1[stack gateway]
    B1 --> C1[edge function sees no client address]
  end
  subgraph now
    A2[client] --> B2[stack gateway]
    B2 --> D2{peer address known}
    D2 -->|yes| E2["append client to X-Forwarded-For<br/>set X-Real-IP to client"]
    D2 -->|no| F2[drop client sent X-Real-IP]
    E2 --> G2[http and websocket upstreams]
    F2 --> G2
    G2 --> H2[edge function sees the caller]
  end
```

</details>

## ref

- closes: #7275
…h effect lint (CLI-2881) (#7348)

## TL;DR

brings `tools`, `apps/docs` and `packages/cli-test-helpers` under the
effect lint

## whats introduced?

- `apps/docs/**`, `packages/cli-test-helpers/**` and `tools/**` join the
allow list
- the release and config tools run as effect programs on `FileSystem`
and `HttpClient`, with the same requests, console output, files written
and exit codes, so the root gains `effect` and `@effect/platform-bun`
dev dependencies
- the test harness runs on effect too, so `cli-test-helpers` gains the
same two as dependencies, and `makeTempDir` returns a promise of an
async disposable dir, so its two `apps/cli-e2e` call sites await it
- the docs page swaps its `async` functions for promise chains and
renders the same pages
- `local-registry.ts` adds one `oxlint-disable` for the `openSync` log
descriptor Verdaccio shares across stdout and stderr, which effect's
`ChildProcess` cannot hand over
- a failed run prints the same error, with effect frames in the stack

## ref

- closes: CLI-2881
This bumps postgres from 15.19.0.007-r0 to 15.19.0.008-r0.


https://github.com/supabase/slim-services/releases/tag/postgres-15.19.0.008-r0

Planned after supabase/slim-services published 15.19.0.008-r0. This
branch is rewritten from develop whenever a newer relevant release
arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
supabase-cli-releaser Bot and others added 13 commits October 27, 2026 19:35
This bumps storage from v1.84.28-r0 to v1.84.30-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.84.30-r0

Planned after supabase/slim-services published v1.84.30-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.148.2-r0 to v2.148.5-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.148.5-r0

Planned after supabase/slim-services published v2.148.5-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.148.5-r0 to v2.148.6-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.148.6-r0

Planned after supabase/slim-services published v2.148.6-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This PR was automatically created to sync API types from the
infrastructure repository.

Changes were detected after refreshing `apps/cli-go/api/v1-openapi.yaml`
from the latest spec from infrastructure, and `apps/cli-go/pkg/api` is
regenerated from it. The snapshot diff is the upstream API change and is
worth reading: it is marked `linguist-generated`, so GitHub collapses it
behind a "Load diff" click rather than hiding it.

Co-authored-by: supabase-cli-releaser[bot] <246109035+supabase-cli-releaser[bot]@users.noreply.github.com>
This bumps storage from v1.84.30-r0 to v1.84.32-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.84.32-r0

Planned after supabase/slim-services published v1.84.31-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps edge-runtime from v1.77.8-r0 to v1.77.9-r0.


https://github.com/supabase/slim-services/releases/tag/edge-runtime-v1.77.9-r0

Planned after supabase/slim-services published v1.77.9-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## TL;DR

fixes the migration error caret when accented letters or emoji come
before the failing token

## whats improved/fixed?

postgres reports the error position in characters but `markError`
counted bytes,
 so `db push` and `db reset` dropped or misplaced the caret

## how?

count each line in code points instead of utf8 bytes

## ref:

- closes: #6886
## TL;DR

adds a commented `[auth.web3.ethereum]` example to the `config.toml`
from `supabase init`, matching the web3 docs, drops the wrong EIP-4361
citation from the solana comment and fixes the `max_rows` comment typo

## ref:

- closes: #7324
…#7362)

## Summary

On some nested or sandboxed Docker hosts, `docker start` works but
`docker exec` doesn't. runc can't join the container's namespaces, so
every exec fails with `OCI runtime exec failed: … error executing setns
process: exit status 1`. Docker runs every `HEALTHCHECK` through exec,
so on these hosts no container ever turns healthy.

`supabase start` waited on Docker health for Postgres, so it sat out the
whole `db.health_timeout` (2 minutes by default), failed with
`HealthCheckTimeoutError … container is not ready: unhealthy` and rolled
the stack back. The real reason, the setns error in `State.Health.Log`,
was never shown.

This makes the readiness checks work without Docker being able to exec
into containers, and puts the health-check output in the error when
something genuinely isn't ready.

### What changes

- Postgres readiness is a connection from the host. `start`, `db start`,
`db reset`, and the shadow databases for `db diff` and `migration
squash` now wait until Postgres accepts a connection on its published
port. It's the same probe the pg-delta shadow already used. The db gate
doesn't read Docker health any more.
- Other services fall back when their health check can't run. That means
the last health check failed to exec (exit code -1, `OCI runtime exec
failed`), and the failure isn't a missing or broken health-check command
in the image. In that case the gate checks:
- the Kong-routed services (Auth, Storage, postgres-meta, Analytics)
through their health route in Kong, which has to return 200
  - Kong itself by any HTTP response from its proxy
  - everything else by it running

`start` then prints one warning that names the containers it could only
confirm as running.
- `status` and the already-running check on `start` accept a db whose
health check can't exec, with the same warning, instead of failing.
- Not-ready errors say why. They now include the last health-check exit
code and output, e.g. `container is not ready: unhealthy (last health
check exit code -1: OCI runtime exec failed: …)`. When exec is the
cause, the error adds a hint with a `docker exec <container> true`
command to confirm it.
- Probes are bounded. One timeout covers each HTTP probe's request and
body, and the service wait has a wall-clock cap. A proxy that accepts
connections and then hangs can't stretch the wait out indefinitely.

On a host where exec works, nothing falls back and no warning is
printed.

### Trade-offs of always probing Postgres from the host

I went with always using the connection probe for Postgres, rather than
only falling back to it when exec fails. It's simpler, and a working
connection is what we actually care about. It does change a few things
on normal hosts too:

- `start` is faster. Postgres accepts connections several seconds before
Docker's first health check runs (its interval is 10s). In my runs
`start` returned about 9s sooner, roughly a third faster.
- `db start` gives most of that back. `status` and the already-running
check still read Docker health, so `db start` and `db reset` wait up to
15s afterwards for Docker's first health verdict. Without that wait,
`supabase db start && supabase status` would fail with `container is not
ready: starting`. So `db start` ends up only slightly faster than
before. `start` does the same wait, but by the time the other services
are ready the db has almost always settled, so it costs nothing on a
full stack.
- A changed postgres password no longer fails fast. Say a reused volume
has a different password from the one the CLI connects with. The
connection probe keeps getting rejected until `db.health_timeout` runs
out (2 minutes by default). Before, the `pg_isready` health check didn't
authenticate, so the gate passed and the next step failed straight away.
I don't think that case is common enough to special-case, but I'm happy
to make an auth failure end the wait early if we'd rather.
- `db start --from-backup` still ignores a readiness timeout, but the
wait is now a connection from the host to the published port rather than
Docker health.
- The db that `db diff` starts for pg-delta (through
`startLocalDatabase`) gets the same 15s settle, so its timing stays
about the same as before.

### Not covered

- `db reset` on these hosts still fails at the Kong reload step, because
`kong reload` runs through `docker exec`. It now fails in a few seconds
with `KongReloadError` instead of after the 2-minute timeout.
- `docker ps` still shows these containers as `unhealthy`. That's
Docker's own state and the CLI can't change it.

## Linked issue

Closes #7325 (CLI-2855)
This bumps realtime from v2.148.6-r0 to v2.149.0-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.149.0-r0

Planned after supabase/slim-services published v2.149.0-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## TL;DR

stops `supabase secrets set` uploading secrets from the current
directory when `--workdir` points at another project

## whats improved/fixed?

`supabase secrets set --workdir ../clean` read `supabase/config.toml`
and `supabase/.env` from the directory it ran in, ignoring `--workdir`
and `SUPABASE_WORKDIR`

so local only secrets from that directory got uploaded to the linked
project, and the workdir project's own secrets were skipped

## how?

`secrets set` now loads the config and its `.env` files from an explicit
`--workdir` or `SUPABASE_WORKDIR` as given, never climbing to a parent
project

without one it still finds the nearest project from the current
directory, exactly as before

> [!NOTE]
> with an explicit `--workdir` that has no `supabase/config.toml`,
config secrets are no longer picked up from a parent or the current
directory, matching the config commands and the old CLI
>
> a `--workdir` that does not exist now fails with `failed to change
workdir` before any request, like the config commands
>
> `--env-file` relative paths still resolve against the current
directory

## ref:

- closes: #7354
- broken in: #5357
This bumps realtime from v2.149.0-r0 to v2.149.1-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.149.1-r0

Planned after supabase/slim-services published v2.149.1-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps storage from v1.84.32-r0 to v1.84.33-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.84.33-r0

Planned after supabase/slim-services published v1.84.33-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@supabase-cli-releaser supabase-cli-releaser Bot added the do not merge Approve to apply; do not merge. label Oct 28, 2026
@supabase-cli-releaser
supabase-cli-releaser Bot requested review from a team and supabase-oss as code owners October 28, 2026 12:47
return dropComments(`-- ${line}`);
if (
!inQuotedSql &&
new RegExp(`^GRANT [A-Z ,]+ ON PARAMETER ".*" TO "(${reservedRoles})"([ ;]|$)`, "u").test(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚪ Severity: LOW

Remote pg_dumpall output can put a reserved role in a multi-grantee statement, such as GRANT SET ON PARAMETER ... TO "app_user", "supabase_admin";. This regex only recognizes a reserved first grantee and rejects a trailing comma, so the grant can survive db pull into roles.sql and alter platform-managed role ACLs when later applied.
Helpful? Add 👍 / 👎

💡 Fix Suggestion

Suggestion: Extend the regex so the reserved role can appear anywhere in the comma-separated grantee list, not only as the first grantee. Allow any number of preceding quoted grantees ((?:"[^"]+", *)*) and accept a trailing comma after the reserved role ([ ,;]). Any GRANT ... ON PARAMETER statement that includes a reserved role is then commented out. Be aware that this also comments out the non-reserved grantees on that line. If you need to keep those grants, rewrite the statement to drop only the reserved grantees. That is a larger change.

⚠️ Experimental Feature: This code suggestion is automatically generated. Please review carefully.

Suggested change
new RegExp(`^GRANT [A-Z ,]+ ON PARAMETER ".*" TO "(${reservedRoles})"([ ;]|$)`, "u").test(
new RegExp(`^GRANT [A-Z ,]+ ON PARAMETER ".*" TO (?:"[^"]+", *)*"(${reservedRoles})"([ ,;]|$)`, "u").test(

Comment on lines +323 to +324
if (quote !== "") {
if (char === quote) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚪ Severity: LOW

An attacker-controlled pg_dumpall role setting can contain an E-string with a backslash-escaped quote. The scanner treats it as closing the literal, then the real terminator as opening one; a following parameter GRANT to supabase_admin is misclassified as quoted and survives db pull into roles.sql, allowing reserved-role ACL changes on restore.
Helpful? Add 👍 / 👎

💡 Fix Suggestion

Suggestion: Make the quote scanner aware of PostgreSQL E-strings (E'...'). Inside an E-string a backslash escapes the next character, so \' must not close the literal. Track E-string mode in the persisted quote state, for example with the sentinel value E', so it carries across lines. On a backslash in that mode, skip the next character. Keep doubled-quote ('') handling for both string kinds.

⚠️ Experimental Feature: This code suggestion is automatically generated. Please review carefully.

Suggested change
if (quote !== "") {
if (char === quote) {
if (quote !== "") {
const isEString = quote === "E'";
const closer = isEString ? "'" : quote;
if (isEString && char === "\\") i++;
else if (char === closer) {
if (next === closer) i++;
else quote = "";
}
} else if (char === "'") {
const prev = line[i - 1];
const beforePrev = line[i - 2];
quote =
prev !== undefined &&
/[Ee]/u.test(prev) &&
!(beforePrev !== undefined && /[A-Za-z0-9_$]/u.test(beforePrev))
? "E'"
: "'";
} else if (char === '"') quote = char;
else if (char === "-" && next === "-") break;

@supabase-cli-releaser
supabase-cli-releaser Bot merged commit 7c6505f into next Oct 29, 2026
85 of 88 checks passed
@supabase-cli-releaser
supabase-cli-releaser Bot deleted the sync/develop-into-next branch October 29, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do not merge Approve to apply; do not merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants