Repository navigation
chore(repo): sync develop into next - #7097
Closed
supabase-cli-releaser[bot] wants to merge 33 commits into
Closed
supabase-cli-releaser[bot] wants to merge 33 commits into
supabase-cli-releaser[bot] wants to merge 33 commits into
Conversation
This bumps storage from v1.80.0-r0 to v1.80.2-r0. https://github.com/supabase/slim-services/releases/tag/storage-v1.80.2-r0 Planned after supabase/slim-services published v1.80.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>
…nt (CLI-2653) (#7045) ## TL;DR brings the `db` connection string parser, `pgpass` and `pgservicefile` under the effect lint ## whats introduced? - `db-config.parse`, `pgpass` and `pgservicefile` join the allow list file by file, so the rest of the `db` module waits for the later PRs in this stack - the parser reads `pgpass` and the service file through the `FileSystem` and `Path` services, and its libpq env reads go through `Config` once up front - `parseConnectionString` and `poolerConfigFromConnectionString` become effects, and every caller across `db`, `stack`, `test-db`, `migration squash`, `gen types` and the pg-delta engine yields them - an empty shell var still wins over the project `.env`, a missing `pgpass` or service file still reads as absent, and every parse error keeps its text - unit tests run on temp dirs and a pinned `Config` env instead of `process.env` writes, with a new case for the empty shell var ## ref - related: CLI-2653
) (#7046) ## TL;DR brings the `db` pg connection layer and few resolvers under the effect lint ## whats introduced? - `db-connection` and `db-dns` join the allow list - the `sslrootcert`, `sslcert` and `sslkey` reads go through `FileSystem`, keeping the BOM and the errno messages, and `dbConnectionLayer` captures it at build so `DbConnection.connect` keeps its type - a cert path with a NUL byte, only reachable as `%00` in a DSN, now reads `FileSystem.readFile: ...` instead of `TypeError [ERR_INVALID_ARG_VALUE]: ...`, since the platform keeps only the message for that throw - `--dns-resolver https` sends the same request through `HttpClient` with automatic HTTP tracing disabled, so no trace headers reach Cloudflare, and keeps every failure text and the 10s timeout; a `Db.resolveHostsOverHttps` span records the response status and answer count - tests pin the full cert read errors and cover the DoH resolver: non-200, rejected request, no valid IP, invalid and empty JSON and the timeout ## ref - related: CLI-2653
…I-2653) (#7048) ## TL;DR brings the `db` config toml reader under the effect lint ## whats introduced? - `db-config.toml-read` joins the allow list - shell env reads go through `Config` once, for the override names and every `env(...)` ref in the toml, and the sync `envLookup` reads from that snapshot - `config push` drops its copy of the env ref helpers and uses the reader's - the toml parse runs before the env snapshot with the same failure order and messages - invalid signing keys files retain native JSON parser details in both `config.toml` loading and `local-config-values`, with the same narrow lint exception used by the SSO readers - unit tests pin env through `Config` and temp dirs instead of `process.env` writes, and the push, reset and start integration tests pin the three values the reader now takes from `Config` ## ref - related: CLI-2653
…I-2653) (#7049) ## TL;DR brings the rest of the `db` module under the effect lint ## whats introduced? - the per file `db-config.parse`, `db-config.toml-read`, `db-connection` and `db-dns` entries collapse into `db-*.ts`, and `branch-target`, `connect-errors`, `pooler-fallback` and `schema-flags` join, which covers the whole `db` module - `db-config.layer`, `db-pull-run` and `db-push-core` yield their errors directly with the same classes and messages, and `branch-target` recovers through `Effect.option` and `orElseSucceed` - `db-config` integration tests feed env through `Config` instead of `process.env` hooks, and `db-image` and `db-target-flags` move to `it.effect` ## ref - closes: CLI-2653
This bumps realtime from v2.142.0-r0 to v2.143.0-r0. https://github.com/supabase/slim-services/releases/tag/realtime-v2.143.0-r0 Planned after supabase/slim-services published v2.143.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> Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com> Co-authored-by: Julien Goux <hi@jgoux.dev>
Linear: [CLI-2442](https://linear.app/supabase/issue/CLI-2442) Hotfix PR gating, the first of three PRs that complete the hotfix flow on top of the branch and release work from #7038. A hotfix is a `hotfix/*` PR into `main` with a `fix`, `perf`, or `revert` title; squash-merging publishes the next stable patch and the existing sync carries it back to `develop`. - **Check Deploy** always runs and reports. On the scheduled `develop` promotion it succeeds. On `hotfix/*` heads it requires the title to start with `fix`, `perf`, or `revert`, with an optional scope and no `!`, and the failure message says what to change. Any other head fails, and so does a fork head on either path: hotfixes come from this repository. The job is named so it can become a required status check on `main` later; because `main` has no App bypass, the promotion's head SHA must carry a real success for the deploy fast-forward push to pass. - **Release Smoke Test** triggers on hotfix PRs into `main` and runs the shared release pipeline with `dry_run: true`, restoring the build-and-smoke rehearsal that beta normally provides. Dispatch inputs keep their defaults. Runs are per-PR concurrent with cancel-in-progress, and fork pull requests are skipped since their token cannot hold the permissions the shared workflow declares. - **Release dispatch guard**: a non-dry-run stable release can only be dispatched from `main`. The `hotfix/*` exemption existed for the manual rehearsal, which this PR makes automatic. @Coly010, was a real stable publish from an unmerged hotfix branch intended? If so, say so and I will restore it. Verified on a scratch repository: with a ruleset requiring only this check on `main`, a direct push of a deploy PR head and of a hotfix PR head both passed once the job had reported on the head SHA, and a push with no check run was rejected (rule suites 4418391424 and 4418634505). The runbook's hotfix section and the rollback policy change in a separate PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <noreply@anthropic.com>
…#7052) Linear: [CLI-2442](https://linear.app/supabase/issue/CLI-2442) Third of three PRs for the hotfix flow on top of #7038. Documentation only. - **Runbook, hotfix section** (`apps/cli/docs/release-process.md`): when a hotfix is warranted, the patch-type title rule and why not to edit the squash subject, the checks that run automatically including the dry-run release rehearsal, the sync back into `develop` and what to do when it conflicts, the interaction with an open deploy PR, and how a hotfix reaches `@supabase/config` consumers. The manual dry-run dispatch step is gone. - **Runbook, rollback section**: replaced by the forward-only policy. A `revert:` hotfix is the response to a bad release. - **ADR 0030**: hotfix criteria, forward-only, the required `Check deploy`, the automatic rehearsal, and the notifications, referencing ADR 0028 for the sync and fast-forward mechanics. - **Maintainers guide and root instructions**: a short hotfix paragraph and one sentence respectively, pointing at the runbook. Stacked on #7050, so the workflows this runbook describes are in the checkout: review this diff against that branch. It merges after #7050 and #7051 (Slack and the fast-forward comment); once #7050 lands, GitHub retargets this PR to `develop` and I bring `develop` in before it goes through the queue. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
Linear: [CLI-2442](https://linear.app/supabase/issue/CLI-2442) Second of three PRs for the hotfix flow on top of #7038. After a hotfix publishes from `main`, the sync merges `main` back into `develop`. When that conflicts, the bot opens a sync PR that nobody is told about, and a Tuesday deploy approved in the meantime is refused with a comment that only says `main` moved. This PR closes both gaps without changing how the sync or the fast-forward work. - **Sync branches** exposes the conflict PR number as a job output. For the `main-into-develop` pair a new job posts a `sync-conflict` message to the release Slack channel with the PR link and the resolution steps, through the shared Slack workflow. The `develop-into-next` pair is unchanged. CODEOWNERS already requests the CLI team on these PRs, so no review request is added. - **Fast-forward on approval**: when a deploy PR is refused because `main` has commits `develop` lacks, the comment names the open `sync/main-into-develop` PR, or tells the approver to dispatch the sync if none is open. A failed lookup falls back to the generic comment rather than skipping it. - **Slack notify** gains the `sync-conflict` status and a `pull_request` input; `version` becomes optional for messages that are not about a release. Draft alongside #7050; both are independent of each other. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <noreply@anthropic.com>
## Summary **TL;DR** Failures from the new local stack (`supabase stack *`, and stack-backed `db reset`, `db dump`, `db diff`, `test db` and `functions serve`) now reach telemetry with a cause. Before, most of them were reported as one fingerprint per error tag with category `unknown`, so start and destroy failures couldn't be told apart. A port conflict now counts as user-actionable only when the user pinned the port. ### Before ```mermaid flowchart LR A["typed failure<br/>port, pull, timeout"] --> B["StackError<br/>message only"] B --> C["…StartError<br/>reason unknown"] C --> D["tag:ExperimentalStackStartError<br/>category unknown"] ``` ### After ```mermaid flowchart LR A["typed failure<br/>port, pull, timeout"] -->|failureKind| B["StackError<br/>kind + reason"] B --> C["…StartError<br/>reason stack"] C -->|StackError adapter| D["tag:ExperimentalStackStartError:port_conflict<br/>invalid_config"] ``` ### Why Every `@supabase/stack` failure crossed the owner RPC boundary as message text. The CLI wrapped each one as `reason: "unknown"`, and none of the `ExperimentalStack*Error` reasons set a fingerprint suffix. As a result: - the top new-stack start and destroy errors showed as `unknown`; - `stack status` "no stack" and real flag errors shared one fingerprint; - a raw `StackError` that escaped a command was reported as `tag:unknown`, losing even its tag. ### What changed - **`@supabase/stack` carries a failure kind.** `failureKind()` derives a closed `StackFailureKind` from the typed cause chain. It is carried on `StackError`, each failed composition outcome, the `POST /shutdown` failure body and the owner readiness line. - Failure sites that know the cause set the kind explicitly: port claims, engine command failures, health and startup timeouts, process exit and stop, artifact preparation, state, owner startup, connection and exit, and lease conflicts. - Docker stderr is classified only where the container error is built, as with the existing retry classifiers. - **The wire field is an open string.** An older client that decodes a newer owner's error ignores kinds it doesn't know instead of rejecting the response. - **Port provenance.** `port-conflict` (user-actionable) is reserved for a port requested by number, i.e. set in `config.toml` or a `SUPABASE_*_PORT` override. The stack's own allocation reports `port-allocation` (internal bug): - auto-assigned ports, including a saved auto assignment that is now taken; - native backend port collisions; - Docker publish refusals, since Docker chooses the host port. - **A typed `StackError` adapter in the CLI.** It lives in `error-actionability.ts` and checks, in order: 1. the client `reason`; 2. the `kind`; 3. the first failed outcome's kind; 4. otherwise `:unclassified`. - **Per-reason fingerprints.** Every new-stack command error reason, plus `FunctionsServeStackError`, has its own fingerprint suffix (for example `:not_found`, `:flags`, `:confirmation`). A `stack` reason classifies through its wrapped cause, so wrapped CLI errors such as `DbSetupError` keep their own classification. - **Stack-backed db and functions wrappers** keep the stack cause, so the real failure shows through: `LocalDbRunningError`, `db reset`, `db dump`, `db diff`, declarative sync, `test db` and `functions serve`. - **Engine command failures** are classified as `runtime_crash` / `engine_command` rather than `invalid_config`. - **Unused internal CLI reasons are removed:** `registry`, `port`, `artifact` and `impossible-state`. ### Reviewer notes - **Dashboards:** fingerprint values change for these errors. A query matching `tag:ExperimentalStackStartError` exactly needs a prefix match now. - **`functions serve` edge case:** on a stack with no API service it still binds the CLI's default API port, so a conflict there reports as user-actionable. That number also forms the served `SUPABASE_URL` before the instance exists, so it is left as is. - **Not covered here** (both pre-existing, for every command): parse errors (an unknown flag or unexpected argument) and Ctrl+C send no `cli_command_executed` event. ## Linked issue None. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This bumps analytics from v1.52.0-r0 to v1.53.0-r0. https://github.com/supabase/slim-services/releases/tag/analytics-v1.53.0-r0 Planned after supabase/slim-services published v1.53.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 realtime from v2.143.0-r0 to v2.143.1-r0. https://github.com/supabase/slim-services/releases/tag/realtime-v2.143.1-r0 Planned after supabase/slim-services published v2.143.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.143.1-r0 to v2.143.2-r0. https://github.com/supabase/slim-services/releases/tag/realtime-v2.143.2-r0 Planned after supabase/slim-services published v2.143.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 bumps realtime from v2.143.2-r0 to v2.143.3-r0. https://github.com/supabase/slim-services/releases/tag/realtime-v2.143.3-r0 Planned after supabase/slim-services published v2.143.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>
Adds [jactionlint](https://github.com/jdx/jactionlint) as a core lint for our GitHub Actions workflows and runs it as part of `check:all`. - Replaces `.github/actionlint.yaml` with `.github/jactionlint.yaml` and enables `require-commit-hash`, so actions, reusable workflows, and `docker://` images must be pinned to a full SHA or digest. - Pins `jactionlint` and `shellcheck` through mise. jactionlint only checks `run:` scripts when shellcheck is on `PATH`, so pinning it keeps local and CI results the same. - Adds a root `lint:actions:check` script, registers it as an uncached Turbo task, and includes it in `check:all`. Fixes for existing findings: - The `publish` jobs in `cli-go-pg-prove.yml` and `cli-go-publish-migra.yml` now grant `packages: write` and `id-token: write`. The reusable `cli-go-mirror-image.yml` workflow needs both, and these callers only had the workflow-level `contents: read`. - `$GITHUB_OUTPUT` redirects in workflow scripts are now quoted. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Julien Goux <hi@jgoux.dev>
This bumps storage from v1.80.2-r0 to v1.81.0-r0. https://github.com/supabase/slim-services/releases/tag/storage-v1.81.0-r0 Planned after supabase/slim-services published v1.81.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>
…7068) ## TL;DR stops a database helper from being left behind as a `Created` container when readiness times out mid create ## whats introduced? the helper is now created by name with `docker create --rm -i` and then attached with `docker start --attach --interactive`, so the name exists before any readiness timeout and `rm -f` always finds it. `create --rm -i` keeps the `AutoRemove` and `StdinOnce` of `run`, so a dead owner still ends the helper... the create is bounded to 30 seconds and its stderr stays in readiness errors. a create the daemon finishes after that timeout is removed again by name on owner shutdown, and an owner killed between `create` and `start` leaves a helper the stack sweep on stop and destroy removes. ## ref: - closes: #7063 - left/spotted in: #7014 --------- Co-authored-by: 7ttp <117663341+7ttp@users.noreply.github.com>
…7075) ## TL;DR stops the local stack gateway from opening a new upstream connection for every write. ## whats broken? every `.rpc()`, `auth.admin.createUser`, delete or upload went upstream on its own connection and left it in `TIME_WAIT`, so a busy test run used up the macOS port range. ## now fixed by: writes reuse the gateway's keep alive pool like reads do. a write is still never resent. Studio and its `/mcp` route keep a fresh connection per write, as before chunked GET and DELETE bodies are forwarded as chunked, so they reach the upstream and stay off the next request PS: Auth's own Postgres churn is tracked in #6981 ## ref: - closes: #6987 - extends: #6925
Bumps `effect`, `@effect/platform-bun`, `@effect/platform-node`, `@effect/platform-node-shared`, `@effect/sql-pg`, and `@effect/vitest` from `4.0.0-rc.112` to the stable `4.0.2` release. `@effect/tsgo` is unchanged. The goal is zero change to CLI behaviour. Every edit is either required by a removed or renamed API, or restores a behaviour whose upstream default moved. ## Commit layout The first three commits are the bump plus two scripted rewrites and can be skipped by reviewers: - `effect/unstable/*` import paths moved to `effect/*` (removed upstream in rc.118, [effect#8354](Effect-TS/effect#8354)). - CLI and Config constructors renamed to PascalCase ([effect#7453](Effect-TS/effect#7453), [effect#8121](Effect-TS/effect#8121)). The remaining commits are hand migrations, one topic each. ## Hand migrations - **node-postgres pool bridge** — `@effect/sql-pg` 4.0 is a native client and dropped `PgClient.fromPool` ([effect#7426](Effect-TS/effect#7426)). The remote database session keeps its own node-postgres pool for the zero idle timeout, the per-connection role step-down hook, and raw `COPY` connections, so `db-connection.pool-client.ts` is a small `SqlClient.make` adapter over that pool with the same statement execution, cancellation, and error classification the old bridge had. - **Stack RPC strictness** — parse-option annotations no longer affect decoding ([effect#8131](Effect-TS/effect#8131)) and the RPC transport passes no parse options, so the initialization command and `runCommand` payload schemas now reject unknown keys through a `Record` filter ahead of the struct decode, with the same "Expected no excess property" wording. Encoding drops `undefined` entries first, so optional fields passed as explicit `undefined` (for example `pgProve.workingDir`) still cross the RPC JSON codec as they did with the plain struct. - **One statement per query** — the native `@effect/sql-pg` client sends everything through the extended protocol, which rejects multi-command strings. The realtime schema bootstrap runs as two statements, and the generated `ALTER ROLE` / `ALTER DATABASE` batches come back from Postgres as an array and run one at a time inside the same transaction. - **Socket addresses, file sizes, encoding, sockets** — server addresses are `NetAddress.SocketAddress` values, `File.seek` and `File.Info.size` use `bigint` and `ByteSize`, `Encoding` moved to `effect/encoding/Base64Url`, and the whole-stack WebSocket test helper uses the reader and writer pair. - **`Effect.partition`** returns `[passes, fails]`; the `stack destroy` handler destructures in that order. - **Management API contracts** — `packages/api` contracts are regenerated; the 4.0.2 schema codegen emits code-point length checks and Unicode-flagged patterns. - **Config package** — `SchemaAST.Union.mode` moved under `options`, `ToJsonSchemaOptions.additionalProperties` became `onExcessProperty`, and regex patterns need the Unicode flag to be exported into JSON Schema ([effect#8482](Effect-TS/effect#8482)). Peer dependency ranges are untouched and already satisfy 4.0.2. ## Preserved defaults - The stack's `PgClient.layer` calls pin `idleTimeout: "10 seconds"`; the default since 4.0.1 is 60 seconds ([effect#8679](Effect-TS/effect#8679)). - The published JSON Schema files (`@supabase/config` `schema.json` and `project-schema.json`, mirrored at `apps/docs/public/cli/*.schema.json`) are byte-identical to the develop build. `toCliConfigJsonSchema` passes `onExcessProperty: "error"` so structs keep `additionalProperties: false` ([effect#8147](Effect-TS/effect#8147)); the shared document assembler leaves pattern-keyed records open, as the generator has no per-schema setting for that; and bucket tables are modelled so they render as the published object-or-array union. ## Behaviour changes reviewed and accepted These upstream changes have no configuration knob. Each was checked against the repo's call sites and judged not user-visible: - Child-process `kill` and scoped release now wait for the process group, bounded to one second without `forceKillAfter` ([effect#8018](Effect-TS/effect#8018)). The stack host, bundled Postgres clients, and containers already set `forceKillAfter`; other spawn sites can only see up to one extra second of teardown when a descendant lingers. - `Effect.cached` treats interruption as abandonment ([effect#8719](Effect-TS/effect#8719)). Every cached effect in the repo is awaited by a single fiber or forked into an owning scope, so the shared-interruption semantics do not apply. - Empty bucket tables under `storage.analytics.buckets` and `storage.vector.buckets` are modelled as an object-or-array union instead of `Schema.Struct({})`. Runtime decoding now rejects a primitive bucket value (`foo = "x"`), which the old schema accepted and ignored; objects and arrays decode as before. - HTTP client spans are named after the bare method (`GET` instead of `http.client GET`), following the OpenTelemetry convention. Nothing in the repo keys on the old name. - Generated Management API string length checks count code points instead of UTF-16 code units, which only differs for characters outside the Basic Multilingual Plane. ## Patches - Rebased: the `@effect/platform-node-shared` stdin EPIPE listener, now against 4.0.2. 4.0.2 still removes the stdin sink's error listener before the final `end()` flush, so a child that exits before reading its input raises an uncaught EPIPE on Linux; [effect#7712](Effect-TS/effect#7712) and [effect#7714](Effect-TS/effect#7714) do not cover that path. - Rewritten: the `@effect/vitest` `runTest` patch. Upstream's finalizer ordering fix ([effect#8154](Effect-TS/effect#8154)) covers the abort hook, so the patch now only layers the two behaviours the stack's `effect-timeout` tests assert on top of it: rejecting with the pretty errors and reporting a finalizer failure after a timeout. ## Test-only changes - Stack integration and CLI `db reset` e2e fixtures that seeded data through `PgClient.layer` with semicolon-joined statements now issue one statement per call; fixtures that go through `psql` are unchanged. - The `db reset` e2e fixture reads `count(*)::int`, since the native client decodes `int8` as `bigint`. ## Follow-ups - Migrate the remote database session to the native `@effect/sql-pg` client and delete the pool adapter. That changes result decoding (int8, timestamps, bytea) across the SQL consumers and needs its own review. --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Julien Goux <hi@jgoux.dev>
## Summary
**TL;DR:** The experimental local stack can now run OrioleDB through
`db.orioledb_version`, on both the Docker and native runtimes. It uses
the new slim-services OrioleDB release line (`<upstream>-orioledb`). A
version without a published artifact fails closed, listing the supported
ones.
### Before
```mermaid
flowchart LR
A["db.orioledb_version set"] --> B{"experimental stack?"}
B -- yes --> C["error: unsupported by the experimental stack"]
B -- no --> D["Compose: docker.io supabase/postgres:<v>-orioledb"]
```
### After
```mermaid
flowchart LR
A["db.orioledb_version set"] --> B{"OrioleDB pin in catalog?"}
B -- no --> C["fail closed: lists published versions"]
B -- yes --> D["stack: slim <v>-orioledb-rN<br/>docker or native"]
D --> E["db diff / declarative shadow<br/>use the same pin"]
D --> F["data reuse only within<br/>the OrioleDB line"]
G["slim-services publishes<br/><v>-orioledb-r0"] --> H["catalog sync opens<br/>add postgres PR"]
H --> B
```
### Why
OrioleDB is leaving experimental. The new stack rejected
`db.orioledb_version` with `db.orioledb_version is unsupported by the
experimental stack`. supabase/slim-services#315 now builds and publishes
OrioleDB as its own Postgres release line, next to stock 15 and 17, so
the stack can pin it like any other artifact.
### What changed
- **Catalog sync.** `-orioledb` releases form their own catalog line
(`17-orioledb`).
- The first publish opens an `add` PR.
- Later releases upgrade or hotfix that line on their own.
- An OrioleDB release never touches the stock 17 pin, and the reverse.
- Legacy tags without `-rN` are ignored.
- **One version resolver.** `db.orioledb_version` (and
`SUPABASE_DB_ORIOLEDB_VERSION`) resolves to `<v>-orioledb` through one
shared resolver. `stack start`, the `db diff` shadow and its cache key,
and the versions output all use it.
- The setting requires `db.major_version = 17`.
- An unpinned version fails with the list of published versions.
- `postgresVersion("17")` still resolves to stock.
- **Data safety.** The ready-marker, `PG_VERSION` and snapshot checks
compare the engine line, not only the major. Stock and OrioleDB data,
snapshots and shadow caches never mix.
- Unmarked data, including data left behind by an interrupted first
start, is refused for an OrioleDB request.
- The error suggests `supabase stack destroy`.
- Switching `orioledb_version` on a saved stack requires `stack
destroy`, because the stack keeps its database version.
- **`test db`.** Maps OrioleDB to its major for pg_prove.
- **Declarative shadow.** No CLI-side handling: pg-delta's Supabase
profile treats `orioledb` as a platform extension
([supabase/pg-toolbelt#513](supabase/pg-toolbelt#513)),
so declarative export never emits it and the diff never creates or drops
it. Shipped in pg-delta `1.0.0-alpha.58`, which this PR pins.
- **Compose.** With `SUPABASE_USE_SLIM_IMAGES`, Compose maps
`supabase/postgres:<v>-orioledb` to the pinned slim OrioleDB image.
Unpinned versions stay on docker.io.
- **Docs.** `stack-commands.md`, `SIDE_EFFECTS.md`,
`packages/stack/ARCHITECTURE.md` and ADR 0026.
It also pins the first published OrioleDB release,
`17.11.0.002-orioledb-r0`, added with the catalog sync's `--release`
mode. Later OrioleDB releases arrive through the existing
`slim-release-published` sync.
## Linked issue
Part of CLI-2387. Depends on supabase/slim-services#315.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ts (#6950) With `[experimental] stack` enabled, changing a port in `config.toml` (including removing the fixed ports a legacy `supabase init` writes) used to make the next `supabase start` fail with "The saved stack cannot adopt these changes". The only way out was to destroy the stack and lose its data. Now, when a stopped stack starts, it applies endpoint port changes and prints each one, for example `api: 54321 → 26199`. JSON and stream-json output add an `endpoint_changes` array to the success payload; each entry names the endpoint, the `endpoints` keys it moved (`keys`), and its `from`/`to` port. - `config.toml` is the source of truth. The re-plan runs inside the stack owner's startup, while the owner holds the stack lease and before it binds any endpoints. It saves the requested endpoint intents, releases the changed endpoints' rows in the port registry (for example an old sticky automatic port), and claims the new ports through the owner's normal port acquisition, with the usual conflict and occupancy checks. Concurrent starts attach to the winning owner instead of racing it. - Nothing is rolled back. A requested fixed port that is already taken fails the start with the usual port conflict, naming the config key and noting that the new port is saved and the previous automatic port released, so starting again succeeds once the port is free. - Changing which services share the API port is handled too: when a different sharing service requests a fixed API port, the shared listener's old automatic claim is released. - A start request is the complete composition, so excluded or absent services no longer pin the shared API port, and removing `[api] port` moves the stack to an automatic port instead of being silently ignored. A stopped service excluded during a re-plan has its endpoints rewritten when it is requested again, so the start reuses it and its data instead of creating a second instance. - Endpoints whose configuration didn't change keep their saved ports. A running stack still has to be stopped first, and so does an idle owner kept alive by `stack prepare`: its error now suggests `stack stop` then `stack start` instead of `stack destroy`. Artifact-version and PostgreSQL major-version changes are still rejected. - The stack definition sent on first registration and the requested configuration for a re-plan reach the spawned owner through a private (`0600`), short-lived file the owner deletes after reading, instead of its command line, so secrets don't appear in process listings. ADR 0017 is amended: saved ports stay stable unless the configuration deliberately changes them on a stopped stack.
…efore start (#7081) ## TL;DR stops a container service from failing to start when its published host port is taken between create and start. ## whats broken? containers publish with an engine-chosen host port (`127.0.0.1::<port>`). Podman picks that port at create by opening and closing a socket, and pasta only binds it at start. Anything that grabs the port in between, such as an outbound connection from another stack, fails the start with `Listen failed for HOST TCP port …: Address in use`. ## now fixed by: - pasta's "Address in use" is classified as a port-allocation failure, like Docker's "port is already allocated". - a launch that fails with a port-allocation failure removes its container and creates a new one, which gets a new port, up to 3 attempts. The last failure is returned as before. ## ref: - seen on: #7080
…7089) ## TL;DR fixes `supabase start` failing on podman when the project has no `supabase/snippets` folder ## whats broken? since the ts port, start creates containers through `podman create -v` which rejects a missing bind source while docker just creates it. studio binds `supabase/snippets` so a fresh project failed with `statfs <project>/supabase/snippets: no such file or directory` ## now fixed by: start creates `supabase/snippets` when studio is enabled, before any container is created matching what the stack already does... ## ref: - closes: #7086 - broken/missed in: #5847
… lint (CLI-2649) (#7084) ## TL;DR brings the `api`, `http` and `auth` modules under the effect lint, along with `profile`, `debug` and the rest of `project` ## whats introduced? - the files of these modules join the allow list - `dohFetch` runs as one effect, and the request signal still only cancels the DoH lookup, so responses and fetch errors come back as before - `identity-stitch` writes `telemetry.json` through a schema codec and `DateTime` with the same bytes, a raw int64 `schema_version` included - the `--debug` HTTP timestamp and the default login token name read the clock through Effect, and the branch resolvers move to `Effect.fn` with the same span names - tests move to scoped temp dirs, `TestClock` and `it.effect`, with new cases for the abort handling, the int64 token, the debug timestamp and the token name ## ref - closes: CLI-2649
## TL;DR patches a couple of flakes: - **slim images** timed out without naming the stalled image. i've added a timeout per probe and bounded cleanup; the original hang's cause is still unknown. - **streamed HTTP** reset the body because the fixture could end its response before the upload finished. i've fixed it by waiting for completion. - **Functions cleanup** gets a minor change: reuse the artifact cache to avoid a cold download. - **pinned ports** in the Network tests came from Linux's ephemeral range, so an outbound socket could already hold one. i've moved them below every range the stack and the OS hand out. - **log halving** could split its 256 lines when the forwarder read mid-append. i've seeded them before Analytics wakes. ## ref: - spotted in: [slim images](https://github.com/supabase/cli/actions/runs/37597900104/job/112714886007) · [streamed HTTP](https://github.com/supabase/cli/actions/runs/37640970591/job/112859517856) · [pinned ports](https://github.com/supabase/cli/actions/runs/37935786356/job/113837363870) · [log halving](https://github.com/supabase/cli/actions/runs/37754787871/job/113236924626)
This bumps studio from 2026.10.05-sha-94b8b06-r0 to 2026.10.12-sha-3699278-r0. https://github.com/supabase/slim-services/releases/tag/studio-2026.10.12-sha-3699278-r0 Planned after supabase/slim-services published 2026.10.12-sha-3699278-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> Co-authored-by: Julien Goux <hi@jgoux.dev>
…` with effect lint (CLI-2650) (#7077) ## TL;DR brings the project `.env` loader and the local project context under the effect lint ## whats introduced? - `project-environment`, `local-project-context`, `dotenv`, `vault` and `vault-decrypt` join the allow list, and `viper-env` follows in the next PR of this stack - the project `.env` files are read through the `FileSystem` and `Path` services and fail in the error channel, so both callers keep the same `failed to read config: Error: ...` text - the read order, shell-wins precedence, a kept leading BOM and the missing, unreadable or directory `.env` cases behave as before, and a `.env` FIFO no longer blocks Ctrl+C - `SUPABASE_ENV` and `SUPABASE_PROJECT_ID` are read through `Config` with the same empty and unset handling - tests pin env through `Config`, stay hermetic against an exported `SUPABASE_ENV` or `SUPABASE_PROJECT_ID`, and cover the BOM, directory, symlink loop and `.env.local` skip cases ## ref - related: CLI-2650
## TL;DR brings `viper-env` and the experimental gate tests under the effect lint ## whats introduced? - `viper-env` and `experimental-gate` join the allow list - the `SUPABASE_*` readers read through `Config` and become effects, so every caller keeps its `flag || env` short-circuit and the same true, false, empty and unset handling - `dumpNetworkMode` in `pg-dump.run` becomes an effect for the same reason - tests that set these vars through `process.env` would pass without testing anything once `Config` snapshots the env, so they pin them through `withConfigEnv`, and the unset guards also hide them from `Config` through a new `withEmptyConfigEnv` helper - the shadow cache guard becomes a `shadowCacheDisabledLayer` merged into each file's setup ## ref - closes: CLI-2650
… event log (#7091) ## TL;DR stops the Podman sweep integration test from timing out with `The next owner did not sweep orphans`. ## whats broken? the test waits for each swept container's `remove` event from `podman events --since …`. On CI, Podman logs events to a shared file that it rotates when it reaches its size limit. A reader that hasn't polled an event yet when the log rotates skips it, so the wait never completes and the test hits its 1 minute timeout. Parallel Podman test files fill that log quickly, so this happens occasionally in the Podman integration job. ## now fixed by: - on Podman, the helper waits on the container itself with `podman wait --condition removing --ignore`, which also returns for a container that is already gone. Docker keeps its event stream, which is not affected. - the database stop test's helper reads Podman's exit code with `podman wait <container>` instead of its `died` event, which the same rotation can drop. - the timeout message names the waits that are still pending, so any remaining failure points at its cause. ## ref: - seen on: #7081 (merge queue) and https://github.com/supabase/cli/actions/runs/37703640927
## Summary Scoped personal access tokens let a user pick exactly which permissions a token gets. For that to be useful, a user needs to know what a given CLI command actually needs before creating a token — today the CLI can't answer that at all. This work builds the mapping from every command (and its flags) to the Management API permissions it needs, plus tests that keep that mapping from drifting as the code changes. See [CLI-2474](https://linear.app/supabase/issue/CLI-2474). This is the first of several PRs. This one is pure foundation — no command is mapped yet. ## What's in this PR - The data model for a command's permission mapping (plain, serializable data), and a `withPermissions` combinator that attaches a command's declaration to the `Command` itself. The command tree is the single registry, so a declaration sits next to the command it describes and any future docs or help feature reads it straight off the command. - A spec-backed operation matcher (FGA permissions and OAuth scope) and a drift-assertion test helper that later PRs will use to check a command's declared mapping against its real API calls. - A completeness test that walks the real CLI command tree for both stack backends and fails if any command or flag isn't accounted for. - A central list of commands still pending a declaration, so the completeness test passes until each batch lands. Follow-up PRs shrink it, and the last one deletes it. Nothing in the shipped CLI imports these modules yet, so this PR doesn't change the bundle. Follow-up PRs will map the shared logic several commands reuse, then the remaining commands in batches. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
## Summary **TL;DR** An unhandled crash (an Effect defect that matches no classification) is now fingerprinted as `error:Defect:<identity>` instead of a bare `error:Defect`. Unrelated crashes no longer share one fingerprint, so the most frequent one can be identified from telemetry. ### Before ```mermaid flowchart LR A["Namespace.NamespaceError"] --> C["error:Defect"] B["Error with code ENOENT"] --> C ``` ### After ```mermaid flowchart LR A["Namespace.NamespaceError"] --> C["error:Defect:Namespace.NamespaceError"] B["Error with code ENOENT"] --> D["error:Defect:Error:ENOENT"] ``` ### Why `stack status`, `status` and `stack list` crash on Linux with `error:Defect`. That fingerprint collapses every defect the classifier doesn't recognize, so the crash can't be told apart from any other unhandled failure. Native JS exceptions already name themselves (`error:TypeError`); everything else did not. ### What changed - `classifyCliCauseActionability` appends the first unclassified defect's identity: - for an `Error`, the tag its class defines on the prototype (dotted tags such as `Namespace.NamespaceError` included), else `Error`, followed by its `code` when it is one of a fixed list of system and DNS error codes (for example `error:Defect:Error:ENOENT`); - for anything else, the value's type (`object`, `string`, …). - The category is unchanged: these crashes still count as `internal_bug` / `panic`. - Only source-owned values are used: instance `_tag`, `name`, and message are never read, the code is read only as a plain data property, and a code outside the list is dropped. If inspecting the defect throws, the identity is `Unreadable` and the command's own failure is kept. - Dashboards that match `error:Defect` exactly need a prefix match. ## Linked issue None. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## TL;DR stops local Auth and the stack host from opening a new connection for every request. ## whats broken? Auth keeps no idle Postgres connections unless an idle pool size is set, so every Auth request opened and closed its own database connection and left it in `TIME_WAIT`. A busy test suite could use up the macOS port range, the same way gateway writes did before #7075. The stack host's HTTP client (readiness probes every 250 ms, log forwarding to Analytics) also used a non-keep-alive agent, so each call opened a new connection. ## now fixed by: - local Auth keeps its pooled connections open when idle: 2 in the stack (the cap of its image), 10 in `supabase start`. No new `config.toml` keys. - the stack host's HTTP client reuses connections and closes them after 4 s idle, before the shortest upstream keep-alive of 5 s. ## known limitation: Auth's database driver doesn't detect a pooled connection that Postgres closed while Auth kept running (`pg_terminate_backend`, or a Postgres restart without an Auth restart), so each such connection fails one Auth request before it is replaced. `db reset` restarts Auth and is unaffected. ## ref: - closes: #6981 - extends: #7075
## TL;DR syncs the shared effect skill with the latest upstream, which was refreshed for stable effect v4. ## whats introduced? - adds `references/V4_APIS.md` with the current v4 imports and common migration traps - updates `SKILL.md` and the config, schema, caching, http and testing references for the current v4 apis ## ref - extends: #6688
supabase-cli-releaser
Bot
requested review from
a team and
supabase-oss
as code owners
October 12, 2026 14:12
Member
|
Superseded by a fresh sync from the reworked workflow (#7083). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merging
developintonextconflicts. This branch starts at the tip ofdevelop(a1fa3b2);nextis at2ac84c2.Conflicting files:
.github/workflows/cli-go-api-sync.yml.github/workflows/cli-go-mirror.ymlCONTRIBUTING.mdapps/cli-go/pkg/config/templates/Dockerfileapps/cli/docs/release-process.mdapps/cli/src/cli/complete.tsapps/cli/src/command-internal/db-bootstrap/local-container-inputs.tsapps/cli/src/command-internal/db-bootstrap/shadow-cache.tsapps/cli/src/command-internal/db-config.integration.test.tsapps/cli/src/command-internal/db-config.parse.unit.test.tsapps/cli/src/command-internal/db-config.toml-read.tsapps/cli/src/command-internal/db-config.toml-read.unit.test.tsapps/cli/src/command-internal/db-connection.sql-pg.integration.test.tsapps/cli/src/command-internal/db-connection.sql-pg.unit.test.tsapps/cli/src/command-internal/db-image.unit.test.tsapps/cli/src/command-internal/debug-logger.layer.tsapps/cli/src/command-internal/debug-logger.layer.unit.test.tsapps/cli/src/command-internal/docker-ids.unit.test.tsapps/cli/src/command-internal/experimental-gate.unit.test.tsapps/cli/src/command-internal/global-flags.tsapps/cli/src/command-internal/go-proxy.layer.tsapps/cli/src/command-internal/go-proxy.layer.unit.test.tsapps/cli/src/command-internal/local-project-context.tsapps/cli/src/command-internal/local-project-context.unit.test.tsapps/cli/src/command-internal/pg-dump.run.tsapps/cli/src/command-internal/profile-load.tsapps/cli/src/command-internal/profile-load.unit.test.tsapps/cli/src/command-internal/project-environment.unit.test.tsapps/cli/src/command-internal/stack-shadow-cache.tsapps/cli/src/command-internal/string-slice-flag.tsapps/cli/src/command-internal/supabase-env.tsapps/cli/src/command-internal/viper-env.unit.test.tsapps/cli/src/commands/db/branch/branch.command.tsapps/cli/src/commands/db/branch/create/create.command.tsapps/cli/src/commands/db/branch/delete/delete.command.tsapps/cli/src/commands/db/branch/list/list.command.tsapps/cli/src/commands/db/branch/switch/switch.command.tsapps/cli/src/commands/db/diff/diff.command.tsapps/cli/src/commands/db/dump/SIDE_EFFECTS.mdapps/cli/src/commands/db/dump/dump.handler.tsapps/cli/src/commands/db/pull/SIDE_EFFECTS.mdapps/cli/src/commands/db/pull/pull.integration.test.tsapps/cli/src/commands/db/remote/changes/changes.command.tsapps/cli/src/commands/db/schema/declarative/generate/generate.integration.test.tsapps/cli/src/commands/db/schema/declarative/sync/sync.integration.test.tsapps/cli/src/commands/db/test/SIDE_EFFECTS.mdapps/cli/src/commands/functions/download/download.command.tsapps/cli/src/commands/gen/keys/keys.command.tsapps/cli/src/commands/gen/types/types.command.tsapps/cli/src/commands/gen/types/types.handler.tsapps/cli/src/commands/start/SIDE_EFFECTS.mdapps/cli/src/commands/start/start.handler.tsapps/cli/src/commands/storage/cp/cp.command.tsapps/cli/src/shared/cli/run.unit.test.tsapps/cli/src/shared/functions/deploy.tsapps/cli/src/shared/functions/download.tsapps/cli/src/shared/functions/serve.tsapps/cli/src/shared/init/project-init.templates.unit.test.tsapps/cli/src/shared/telemetry/error-actionability.tsapps/cli/src/telemetry/command-telemetry.unit.test.tsdocs/adr/README.mdknip.jsoncmise.lockmise.tomlTo 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-nextApprove to fast-forward
next; do not use the merge button.