Skip to content

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

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

supabase-cli-releaser[bot] merged 28 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 (a982140); next is at 8e5a4cb.

Conflicting files:

  • .github/workflows/test.yml
  • .oxlintrc.json
  • apps/cli-go/pkg/config/templates/Dockerfile
  • apps/cli/src/command-internal/config-pull-run.ts
  • apps/cli/src/command-internal/db-config.layer.ts
  • apps/cli/src/command-internal/output.encoders.ts
  • apps/cli/src/commands/bootstrap/bootstrap.command.ts
  • apps/cli/src/commands/branches/get/get.integration.test.ts
  • apps/cli/src/commands/config/diff/diff.integration.test.ts
  • apps/cli/src/commands/db/advisors/advisors.format.ts
  • apps/cli/src/commands/db/advisors/advisors.format.unit.test.ts
  • apps/cli/src/commands/db/advisors/advisors.integration.test.ts
  • apps/cli/src/commands/db/advisors/advisors.linked.ts
  • apps/cli/src/commands/domains/SIDE_EFFECTS.md
  • apps/cli/src/commands/domains/activate/activate.integration.test.ts
  • apps/cli/src/commands/domains/create/create.integration.test.ts
  • apps/cli/src/commands/domains/reverify/reverify.integration.test.ts
  • apps/cli/src/commands/encryption/SIDE_EFFECTS.md
  • apps/cli/src/commands/experimental/compute/delete/delete.command.ts
  • apps/cli/src/commands/experimental/compute/list/list.command.ts
  • apps/cli/src/commands/experimental/compute/list/list.integration.test.ts
  • apps/cli/src/commands/experimental/compute/new/new.command.ts
  • apps/cli/src/commands/experimental/compute/push/SIDE_EFFECTS.md
  • apps/cli/src/commands/experimental/compute/push/push.command.ts
  • apps/cli/src/commands/experimental/compute/status/status.command.ts
  • apps/cli/src/commands/functions/delete/delete.integration.test.ts
  • apps/cli/src/commands/functions/deploy/deploy.command.ts
  • apps/cli/src/commands/functions/deploy/deploy.integration.test.ts
  • apps/cli/src/commands/functions/download/SIDE_EFFECTS.md
  • apps/cli/src/commands/functions/download/download.command.ts
  • apps/cli/src/commands/functions/download/download.integration.test.ts
  • apps/cli/src/commands/functions/new/new.command.ts
  • apps/cli/src/commands/gen/bearer-jwt/bearer-jwt.command.ts
  • apps/cli/src/commands/gen/signing-key/signing-key.command.ts
  • apps/cli/src/commands/link/SIDE_EFFECTS.md
  • apps/cli/src/commands/link/link.command.ts
  • apps/cli/src/commands/postgres-config/delete/delete.handler.ts
  • apps/cli/src/commands/postgres-config/postgres-config.shared.ts
  • apps/cli/src/commands/postgres-config/update/update.handler.ts
  • apps/cli/src/commands/projects/SIDE_EFFECTS.md
  • apps/cli/src/commands/pull/pull.command.ts
  • apps/cli/src/commands/secrets/set/SIDE_EFFECTS.md
  • apps/cli/src/commands/secrets/set/set.command.ts
  • apps/cli/src/commands/secrets/set/set.integration.test.ts
  • apps/cli/src/commands/secrets/unset/SIDE_EFFECTS.md
  • apps/cli/src/commands/secrets/unset/unset.integration.test.ts
  • apps/cli/src/commands/seed/buckets/buckets.integration.test.ts
  • apps/cli/src/commands/services/services.command.ts
  • apps/cli/src/commands/snippets/download/download.handler.ts
  • apps/cli/src/commands/snippets/list/list.handler.ts
  • apps/cli/src/commands/snippets/list/list.integration.test.ts
  • apps/cli/src/commands/sso/add/SIDE_EFFECTS.md
  • apps/cli/src/commands/sso/add/add.handler.ts
  • apps/cli/src/commands/sso/update/SIDE_EFFECTS.md
  • apps/cli/src/commands/sso/update/update.handler.ts
  • apps/cli/src/commands/sso/update/update.integration.test.ts
  • apps/cli/src/commands/stop/stop.integration.test.ts
  • apps/cli/src/commands/vanity-subdomains/vanity-subdomains.integration.test.ts
  • apps/cli/src/telemetry/linked-project-cache.integration.test.ts
  • apps/cli/tests/helpers/compute.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 18 commits October 14, 2026 16:43
This bumps storage from v1.82.1-r0 to v1.83.0-r0.


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

Planned after supabase/slim-services published v1.83.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>
…7123)

## Summary

Every Management API call in `apps/cli` now goes through the typed
`@supabase/api` client. Each call gets an `api.operation` span named
after its OpenAPI operation ID, so telemetry can tell which operations a
command really calls. It complements the permission mapping added in
#7105, which declares the operations each module calls.

Before this PR, a dozen call sites built URLs by hand. Those calls
skipped the span, response decoding, and the client's retry and error
handling. Some of them existed because the generated client couldn't
express what they needed, so this PR fixes the generator and client
first, then moves the call sites, then adds a lint rule so new raw URLs
fail CI.

```mermaid
flowchart LR
  subgraph before["Before"]
    direction TB
    H1["command handler"] -->|"typed call"| C1["@supabase/api"]
    H2["sso / snippets / advisors /<br/>postgres-config / db query / login …"] -->|"hand-built /v1/... URL"| X1["HttpClient"]
    C1 --> X1
    X1 --> API1[("Management API")]
  end
  subgraph after["After"]
    direction TB
    H3["every command handler<br/>and shared module"] -->|"api.v1.op(input, options?)"| C2["@supabase/api<br/>span · decode · retry"]
    C2 --> X2["HttpClient"]
    X2 --> API2[("Management API")]
    L["lint rule<br/>supabase/no-raw-management-api-url"] -. "blocks new raw URLs" .-> H3
  end
```

## What changes

### 1. Generator and client (`packages/api`)

Four gaps forced callers back to raw HTTP:

| Gap | Fix |
| --- | --- |
| Response enums were closed, so a new server value broke decoding |
Multi-value response enums are open: `"ACTIVE" \| "PAUSED" \| (string &
{})`. Single-value enums stay closed. |
| Unknown request keys were dropped without an error | Request input
decodes with `onExcessProperty: "error"`, so a typo fails as
`SupabaseApiInputError` before any request is sent |
| `const` schemas weren't generated | `const` maps to a literal |
| One client meant one host and one token | Every wrapper takes an
optional second argument: `{ baseUrl?, accessToken?, headers? }` |

The last row is what let login and SSO profile reconciliation drop raw
HTTP:

```ts
// before: login built its own request because the client had no token yet
const response = yield* httpClient.execute(
  HttpClientRequest.get(`${apiHost}/v1/profile`).pipe(
    HttpClientRequest.setHeader("Authorization", `Bearer ${token}`),
  ),
);

// after
const api = yield* makeApiClient({ baseUrl: apiHost, accessToken: token, userAgent });
const profile = yield* api.v1.getProfile();
```

```ts
// per-request override on an existing client (sso update against a reconciled profile)
yield* api.v1.updateASsoProvider(input, { baseUrl: profile.apiUrl, accessToken: profile.token });
```

**Retries now back off.** The client used to retry immediately. It now
uses exponential backoff with full jitter:

```mermaid
xychart-beta
  title "Maximum delay before each retry (ms, full jitter picks 0 to max)"
  x-axis ["retry 1", "retry 2", "retry 3", "retry 4", "retry 5"]
  y-axis "ms" 0 --> 4500
  bar [250, 500, 1000, 2000, 4000]
```

| Response | Retried for | Delay |
| --- | --- | --- |
| `429` | every method | `Retry-After` if present, otherwise backoff |
| `5xx` / transport error | `GET` `PUT` `DELETE` `HEAD` only |
`Retry-After` if present, otherwise backoff |
| other `4xx` | never | — |

`POST` and `PATCH` aren't retried on 5xx because they aren't idempotent.
A `Retry-After` longer than 10 s isn't waited out: the response goes
straight back to the caller. Each retry records
`http.request.resend_count` on the span.

A single request can override the policy with `retry: { maxRetries,
requestTimeoutMs }`:

```ts
// functions deploy runs its own rate-limit loop, so the client stays out of it
api.executeRaw(operationDefinitions.v1DeployAFunction, input, { retry: { maxRetries: 0 } });
```

| Caller | Override | Why |
| --- | --- | --- |
| `functions deploy` upload and bulk update | `maxRetries: 0` | the
command's own `429` loop is the only retry layer |
| `postgres-config update/delete` PUT | `maxRetries: 0` | a resent write
with `restart_database` restarts the database twice |
| linked-project cache fill at exit | `maxRetries: 0` | exit isn't held
up when the API is failing |
| `db query --linked` | `requestTimeoutMs: Infinity` | long queries keep
running with no client timeout, as before |
| `sso add` / `sso update` | `requestTimeoutMs: Infinity` | the server
may fetch `--metadata-url` during the request; no client timeout, as
before |

### 2. Self-validating OpenAPI overrides

`openapi-overrides.json` patches upstream spec bugs. Patches used to
fail silently once upstream fixed the bug, so stale patches piled up.
The loader now rejects:

- a `replace` without a `test` on the same path directly before it, so
the patch states what it expects upstream to say;
- a `replace` whose value already matches upstream, because the fix has
landed upstream;
- a `remove` whose target doesn't exist;
- any entry without a `$comment` explaining the upstream bug.

```jsonc
{ "$comment": "Hostnames stored before the upstream fix can lack `status`; the fix covers only new writes.",
  "op": "test",    "path": "/components/schemas/.../required", "value": ["status", "..."] },
{ "op": "replace", "path": "/components/schemas/.../required", "value": ["..."] }
```

With these checks, the overrides go from 37 entries to 25. The removed
patches were ones upstream has since fixed, plus a lenient removal of
the v2 webhook paths, which now generate normally.

### 3. Call sites moved to the typed client (`apps/cli`)

| Area | Before | After |
| --- | --- | --- |
| `sso add` / `sso update` | string URLs, hand-written response views |
`createASsoProvider`, `getASsoProvider`, `updateASsoProvider`,
per-request host and token for reconciled profiles. Structured output
still prints the server body unchanged. |
| `db query` | raw `POST /database/query` | `v1RunAQuery` |
| `postgres-config get/update/delete` | raw GET and PUT | GET keeps the
raw record (stored keys may predate the schema). PUT validates the keys
the user passed against the same strict schema the platform enforces.
Stored overrides are resent unvalidated through `executeRaw`'s
`extraBody`, so one this CLI version doesn't know is kept. The returned
record prints unchanged. |
| `snippets list/download` | raw | typed operation. `--output
json/yaml/toml` still prints the server body unchanged. |
| `db advisors` (linked) | raw | `getSecurityAdvisors`,
`getPerformanceAdvisors` |
| `config push` cost check | raw | `listProjectAddons` |
| login profile, upgrade suggestion, linked-project cache | raw | typed
calls. Each builds its own client for its host and token. |
| `projects list` / `projects create` | typed client's `executeRaw` |
unchanged: `executeRaw` keeps fields the schema doesn't model |

The shared `raw-http.ts` helper is deleted. One raw call remains, the
device-login poll under `/platform/cli/login`. That route isn't in the
Management API spec, so no typed operation exists. It now URL-encodes
its parameters and has a commented lint exception.

### 4. Lint rule: `supabase/no-raw-management-api-url`

A local oxlint JS plugin (`tools/oxlint/supabase-plugin.js`) reports any
string or template literal in `apps/cli/src` (tests excluded) that
starts a `/v1/…`, `/v2/…` or `/platform/…` path, including path
constants that are joined to a base URL later. Service-scoped paths such
as `/auth/v1/` and `/storage/v1/` don't match.

```ts
const url = `${apiHost}/v1/projects/${ref}/config/database/postgres`;
//          ^ supabase/no-raw-management-api-url: Build Management API requests with the
//            typed `@supabase/api` client (`api.v1.*`, `execute`/`executeRaw`) so the call
//            emits the `api.operation` span; do not assemble `/v1/`, `/v2/` or `/platform/` URLs by hand.
```

### 5. cli-e2e placeholder ref

Recorded fixtures used `__PROJECT_REF__` as the project ref, which the
typed client rejects as a path parameter. That kept login, upgrade
suggestion and the linked-project cache on raw HTTP. Fixtures now use
`replayfixtureprojref`, a 20-character ref that passes the check, and
the replay server no longer rewrites placeholders back and forth. This
explains the large fixture rename in the diff. Injected `429`/`5xx`
replay responses send `Retry-After: 0`, so the new backoff doesn't slow
down the suite.

## User-visible behavior changes

Most of these come from validating input locally and decoding responses
strictly:

- `postgres-config update` and `config push` reject keys and values the
platform would refuse before sending a request. An unknown `--config`
key reports `unknown Postgres config parameter(s): …` and suggests
upgrading the CLI if the parameter is new. Stored overrides are never
checked locally. An invalid value reports `invalid Postgres config value
for <key>: …`, and a bare number for a size or duration suggests adding
a unit (`work_mem=4096kB`).
- The SSO attribute-mapping file is decoded strictly, so unknown keys
are an error. The `sso` table shows only modelled fields.
- `notebooks` rejects an unknown `view`.
- `functions deploy` rejects an unknown function status. Unknown
custom-domain statuses are shown as returned.
- `snippets` output follows the spec's nullability (`description: null`
instead of a missing field).
- `db query` error output caps the response body and strips control
characters.
- Idempotent requests now retry on `5xx` and transport errors with
backoff. `429` is retried for every method, except where a command opts
out (see the overrides table above).
This bumps storage from v1.83.0-r0 to v1.83.1-r0.


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

Planned after supabase/slim-services published v1.83.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 analytics from v1.53.0-r0 to v1.53.1-r0.


https://github.com/supabase/slim-services/releases/tag/analytics-v1.53.1-r0

Planned after supabase/slim-services published v1.53.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 PR was automatically created to sync the generated `@supabase/api`
package with the latest Management API OpenAPI document.

Changes were detected in the upstream OpenAPI documents exposed by
`https://api.supabase.com/api/v1-json` and
`https://api.supabase.com/api/v2-json`.

Co-authored-by: jgoux <1443499+jgoux@users.noreply.github.com>
)

Maps `gen types`, `gen signing-key` and `gen bearer-jwt` to the
Management API operations they call, so a scoped access token can be
granted per command. `gen keys` stays pending.

`gen types` picks its target from flag values, so it declares flag
conditions instead of a database target: `--local`, `--db-url` and
`--postgrest-v9-compat` turn every call off. TypeScript calls the types
endpoint. Other languages look the project up, fall back to the preview
branch config on a 404, and reach the database through the database
config resolver (login role, pooler config) and the pooler retry. The
project picker and the linked-project cache fill are declared too.
`signing-key` and `bearer-jwt` make no calls.

Shared block change: a target-free `dbConfigPoolerFallbackLinked` for
commands that choose their target from flag values
(`dbConfigPoolerFallback` is built from the same entries), and the first
fallback context is reworded to fit every command. Dump, pull and the
db-config tests are unchanged.

`gen types` runs through the real database config resolver and
linked-project cache with the Management API recorded, for the
TypeScript, pooler, IPv6 retry, preview branch, picker, `--local=false`
and `--db-url` paths. On this command the pooler, login-role and
network-ban calls are each declared by more than one source, so removing
one source alone is not caught by a test; the grants are per operation
either way. No operations without FGA permissions. Only `typescript` and
`go` run through the recording mocks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com>
Maps `branches create|delete|disable|get|list|pause|unpause|update` and
`backups list|restore` to the Management API operations they can call,
so scoped PATs can be granted per command. Drift tests keep each
declaration in step with what the command does.

**Shared changes.**
- New `branchPrompt` block (`v1-list-all-branches`, required) for the
branch listing shown when no branch is given on a TTY.
- The context text of `projectRefPicker`, `linkedProjectCache` and
`branchRef` is reworded so it fits every command that includes it. No
condition or label changed.

**Blocks used.** `projectRefPicker` and `linkedProjectCache` (all ten),
`branchPrompt` and `branchRef` (delete, pause, unpause, update; `get`
uses `branchPrompt` and declares its name lookup itself),
`upgradeSuggestion` (create, update).

**Conditions.** `branches get` names the global output flags: the
branch's API keys and pooler config are read for `-o` other than
`pretty`, and with no `-o` when the output format is json or stream-json
(`--output-format`, `--agent yes`, or a detected coding agent). This is
the first declaration to name global flags in `when`.

**Findings.**
- `pause` and `unpause` call the project-level pause and restore
operations, so they need `project_admin_write`, not a branching
permission.
- `disable` needs only `branching_production_delete`.
- A 4xx on `create` or `update` triggers the upgrade-suggestion lookups
(best-effort).

**Tests.** Each command's integration test runs the project picker, the
branch picker where it applies, and the real linked-project cache, and
checks the exact request sequence. `branches get` covers each output
mode that changes its calls; the agent-detected case is simulated
through the output format.

**Not covered.** Context entries (`branchPrompt`, `branchRef`, the
cache, the agent-detected entry) are asserted by request sequence only.
`--persistent=false` is not run on every command.

**Docs.** The `branches` `SIDE_EFFECTS.md` files now give the cache path
as `<workdir>/supabase/.temp/linked-project.json`, and `get`'s doc
states when the API keys and pooler config are read. All ten docs now
list the project picker, branch picker and linked-project cache routes,
and say when the cache file is written.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com>
Maps the Management API operations behind `config diff`, `config pull`
and `config push`, so scoped access tokens can be given matching
permissions. This changes no command behaviour.

**Commands:** `config diff`, `config pull`, `config push` (removed from
the pending list).

**New shared blocks**
- `configTarget` (`project-target.ts`): the branch lookup for a non-ref
`--project-ref` (`v1-get-a-branch-config` for a UUID, `v1-get-a-branch`
for a name), else the project picker. Reuses `branchRef` and
`projectRefPicker`.
- `configPullRun` (`config-pull-run.ts`): the remote config read
`v2-get-project-config`, shared with top-level `pull`.

**Declarations**
- `diff`: `configTarget`, the config read, linked-project cache.
- `pull`: `configTarget`, `configPullRun`, linked-project cache.
- `push`: `configTarget`; the target probe (best-effort); the add-ons
list and config read (required); one required write per resource (api,
db settings, network restrictions, SSL enforcement, auth, storage,
webhooks), each with a context naming what triggers it; the branch
listing (best-effort); linked-project cache.

**Conditions:** `--project-ref` present gates the branch lookups. Write
triggers, the probe and the branch listing are contexts, since they
depend on `config.toml` contents and `.temp` state rather than flags.

**Worth knowing**
- `config push` always needs the add-ons read, even when nothing is
billable.
- Which writes happen depends on which sections the token can read.
- Not covered by a drift check: `push`'s cache inclusion (its project
probe shares an operation), and the write contexts, which are asserted
by request.

**Docs:** three wrong rows in `config push/SIDE_EFFECTS.md` corrected
(branch lookup parent, cost matrix order, webhooks key).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Record the Management API operations behind 20 project-data commands, so
scoped access tokens can be built from what each command actually calls:
`sso add|info|list|remove|show|update`, `domains
activate|create|delete|get|reverify`, `secrets set|unset`, `snippets
download`, `notebooks pull|push` and `storage cp|ls|mv|rm`.

Each command declares its own operations and composes the existing
`projectRefPicker`, `linkedProjectCache`, `upgradeSuggestion` (sso
commands that call the upgrade gate) and `storageCredentials` blocks. No
user-facing behaviour changes.

New shared pieces:
- `notebooksList`, `notebookRead` and `notebookCreate` blocks in
`notebooks.shared.ts`, for the calls both notebooks commands make; each
command adds its own context.
- `STORAGE_PERMISSIONS` in `storage.flags.ts`. Storage routes on the
parsed `--local` value, so its credentials and cache entries use `{
flag: "local", is: false }` rather than a database target;
`--local=false` targets the linked project.
- A `recordManagementApi` option in the storage test setup and a
`realLayers` option in the notebooks test setup, so those tests run the
real picker, cache and credentials lookup and check the recorded
requests against the declarations.

Conditions: `secrets unset` lists secrets only when no names are given,
and the notebooks entries carry contexts for the id argument, the
reconcile answers and which files exist. `exact` drift checks skip
those, so they are asserted by request sequence.

Things worth knowing:
- `sso info` makes no call of its own, but needs a token and fills the
project cache; its doc said otherwise.
- `snippets download` resolves a project ref it never sends, so it fails
unlinked even though the snippet call needs no ref.
- `storage cp` resolves credentials before its source/destination
checks, and `rm` before its confirmation.
- The `--linked`/`--local` mutual-exclusion error isn't modelled, so
storage over-declares when both are set to false.
- The experimental gate on storage isn't modelled; declarations describe
a run with the gate open.
- Dropping `linkedProjectCache` from `sso add|list|remove|update` fails
no test, because `upgradeSuggestion` also declares the project lookup.
- The `SIDE_EFFECTS.md` files for these commands had the wrong
linked-project cache path and conditions, and were missing the picker
and cache-fill routes; corrected in the last commit.

No `OPERATIONS_WITHOUT_FGA` changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
#7170)

Maps the Management API operations behind the projects, organizations
and linking commands, so scoped access tokens can be given matching
permissions. This changes no command behaviour.

**Commands:** `projects api-keys|create|delete|list`, `orgs
create|list`, `link`, `unlink`, `bootstrap`, `services` (removed from
the pending list).

**New shared block:** `organizationPicker` (`projects.prompt.ts`): the
organization listing made when no organization ID is given.

**Declarations**
- `projects api-keys`: the keys read, with `reveal=true` when `--reveal`
is set; the project picker and the cache fill.
- `projects create`: the create call, the organization listing (via the
picker, when `--interactive` allows a prompt), the cache fill.
- `projects delete`: the delete call and a project listing for its own
picker (it ignores the env and `.temp` ref, so it doesn't reuse the
shared picker), the cache fill.
- `projects list`, `orgs create|list`: their single call; `list` also
fills the cache for a linked ref.
- `link`: project, API keys (`reveal=true`), storage and pooler reads,
the branch listings, the picker, the cache fill. `unlink` makes no API
calls.
- `bootstrap`: organization listing (always, since it passes no org ID),
project create, API keys, health, storage and pooler reads, cache fill.
The pooler read is required because the migration push depends on the
pooler URL it saves on IPv4-only networks. No login call is declared:
with no token the command fails before the login runs.
- `services`: the linked project's API keys and project reads (both
best-effort), cache fill.

**Conditions:** `--reveal` is tested by value. `--interactive` is
optional, so it is declared as two entries (absent, and present with "is
true" in the context). Interactive-terminal, config and argument-shape
prerequisites are contexts.

**Worth knowing**
- `bootstrap`'s browser login is unreachable when no token resolves; the
platform-API layer fails first.
- `link --password` and `SUPABASE_DB_PASSWORD` have no effect.
- Not covered by a drift check: `link`'s cache inclusion and its second
branch-listing entry (a required entry for the same operation shadows
them), and `bootstrap`'s pooler entry (asserted from the handler).

**Docs:** wrong rows corrected in the projects, bootstrap and link
`SIDE_EFFECTS.md` files (environment variable name, create body, org
listing, bootstrap request body and cache-fill attribution, the
`--password` row).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Follow-up to #7129. CLI e2e jobs now set the Test workflow's wall time.

- Split the `@supabase/cli-e2e` suite into two shards; it was the single
longest job.
- The e2e sequencer packs shards by estimated wall time: concurrent
files share half the `e2e` project's workers, because they contend for
one Docker daemon, and exclusive files add their full duration.
- Drop the `actions/cache` + `go build` steps in e2e jobs;
`supabase#build` already builds or restores `@supabase/cli-go` through
turbo.
- The `gen types` e2e readiness probe connects over TCP. The Postgres
entrypoint's init server listens only on the Unix socket, so a socket
probe could pass before the final server started and the seed then
failed mid-restart.
- macOS port tests run on Blacksmith macOS runners; GitHub-hosted macOS
runs took up to several times as long.

Measured over repeated CI runs against develop after #7129:

| | develop after #7129 | This PR | Change |
| --- | --- | --- | --- |
| Test workflow wall time (median) | 3.9 min | 2.75 min | about 30%
faster |
| Slowest CLI e2e job | 3.3 min | about 2.5 min | about 25% faster |
| macOS port tests job | 2.1–8.5 min | 0.7–0.9 min | 3–10x faster |
| Files on the Docker-heavy CLI shard | 32 | 10 | |

Required check names are unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…7139)

## Summary

`supabase db diff --from linked --to linked` failed with `password
authentication failed for user "cli_login_postgres"` when no database
password was available (no `--password`, `SUPABASE_DB_PASSWORD`, or
`supabase/.env`). Each linked side called the resolver separately,
minting two temporary login roles; the second mint invalidated the first
side's credentials.

The explicit-mode `linked` endpoint is now resolved once and reused for
both sides, so a run issues a single `POST
/v1/projects/{ref}/cli/login-role`. Runs with a password configured are
unchanged.

Also corrects routes in the `SIDE_EFFECTS.md` files for `db diff`, `db
pull`, `db dump`, `migration squash`, `inspect db`, and `test db`: temp
login role is `POST /cli/login-role`, pooler fallback is `GET
/config/database/pooler`, and ban listing is `POST
/network-bans/retrieve`.

## Linked issue

Supabase maintainer change; no linked issue.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Declares the Management API permissions for the project network
commands: `vanity-subdomains` (get, check-availability, activate,
delete), `ssl-enforcement` (get, update), `encryption` (get-root-key,
update-root-key), `network-bans` (get, remove), `network-restrictions`
(get, update) and `postgres-config` (get, update, delete). Each leaf
composes the project-ref picker and the linked-project cache.

**Shared change:** `postgresConfigRead` and `postgresConfigWrite` are
new blocks in `postgres-config.shared.ts`, next to the helpers that
issue the calls (`postgres-config` reaches the API through `executeRaw`
on the typed client, so the drift matcher resolves them). `get` uses the
read block, `update` the read block (only when
`--replace-existing-overrides` is false) plus the write block, and
`delete` both.

**Conditions declared**
- `network-restrictions update`: `is` on `--append` selects the POST
`/apply` or the PATCH.
- `ssl-enforcement update`: the PUT is declared once per switch
(`--enable-db-ssl-enforcement`, `--disable-db-ssl-enforcement`), each
with `is: true`.
- `vanity-subdomains activate` and `check-availability`: the call is
declared for `--desired-subdomain` present and for `oneOf: [""]`,
because the handlers send an empty value to the API. Both also compose
`upgradeSuggestion`.

**Findings**
- `v1-get-pgsodium-config` is a GET that needs `project_admin_write`,
and `check-availability` is a POST that needs `vanity_subdomain_write`.
- `postgres-config` makes no restart call and has no delete endpoint:
`delete` is a GET followed by a PUT, and `--no-restart` only shapes the
PUT body.
- `network-bans remove` fills the linked-project cache even when an IP
is invalid, while `network-restrictions update` and `ssl-enforcement
update` validate before resolving the ref and fill nothing.
`postgres-config update` only checks that each `--config` value is a
`key=value` pair before resolving; an unknown key is rejected after the
ref resolves and the GET, so the cache is still filled. `encryption`
resolves the ref outside the cache-fill scope.
- The SIDE_EFFECTS docs pointed the cache at
`~/.supabase/<workdir-hash>/`, described a `.supabase/config.json` that
nothing reads, and omitted the picker and cache-fill routes. They now
match the code.

**Not covered**
- The experimental gate is not modelled; declarations describe a run
whose gate is open.
- `ssl-enforcement update` over-declares when both switches are true, a
run that fails before any call.
- Picker, cache and upgrade-lookup entries carry a context, so they are
checked by request sequence rather than by the exact drift check.
Dropping `linkedProjectCache` from vanity `activate` or
`check-availability` fails no test, because `upgradeSuggestion` also
declares `v1-get-project`.
- `--switch=false` and `--desired-subdomain=` are exercised with parsed
values, not through the flag parser.
- No new entries in `OPERATIONS_WITHOUT_FGA`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Maps which Management API operations the `functions` and `compute`
commands call, and under which flags, so scoped tokens can be granted
the right permissions. The mapping is recorded in each command's
declaration, and integration tests check it against the requests the
handlers actually make. There is no user-facing change.

**Commands (12):** `functions` list, delete, download, deploy, new,
serve; `compute` list, status, delete, logs, push, new.

**Blocks used:** `projectRefPicker` and `linkedProjectCache` on every
command that calls the API.

**New shared blocks:**
- `functionsDownload` in `src/shared/functions/download.ts`, next to
`downloadFunctions`, so `pull` can compose it later.
- `computeRead` in `src/shared/compute/compute-api.ts`, used by status,
delete, logs and push.

**`is` conditions declared:**
- `functions deploy`: `use-api`, `use-docker`, `no-verify-jwt` and
`prune` select the API path, the Docker path, the JWT list lookup and
prune.
- `compute logs`: `follow`.
- `compute push`: `no-wait`.

**Notes**
- `functions download` lists `--use-api`, `--use-docker` and
`--legacy-bundle` as flags that don't change the call set. Under
`--legacy-bundle` the Go binary makes its own list, get and body calls,
which aren't recorded.
- `compute delete` marks its lookup best-effort: it carries on to the
DELETE after a 403 on the GET.
- `compute logs` needs the `analytics_logs_read` permission, unlike the
other compute commands.
- `functions new`, `functions serve` and `compute new` make no API calls
and declare none. Their layers provide no API client, so a call fails
type-checking.
- The context-only entries (deploy create, update, bulk update, prune
delete and the API-path list; download's get and list; logs' history and
compute lookup) carry a `context` and are asserted through explicit
request sequences, not `exact` drift checks.
- `--no-verify-jwt=false` on deploy over-declares the API-path list
call, and `compute logs --tail 0` can't be expressed as a condition.
- The registry unit test's "undeclared command in a gated tree" example
moves from `compute list` to `stack list`.
- `OPERATIONS_WITHOUT_FGA`: no change.

The `SIDE_EFFECTS.md` commit corrects the cache-fill wording and adds
the missing picker and cache rows for the functions and compute
commands.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
… --all (#7177)

`supabase stop --no-backup` no longer exits 1 when a Docker CLI older
than 23.0 talks to a newer daemon.

`docker volume prune --all` is a client-side flag. Docker CLI 20.10
doesn't have it, and newer CLIs reject it when the negotiated API
version is below 1.42. The gate only read the daemon's API version, so a
20.10 client against a 25.0 daemon was handed `--all`: the containers
were already gone, the volume prune failed, and `stop` reported
`StopVolumePruneError`. The gate now reads `{{.Client.APIVersion}}
{{.Server.APIVersion}}` and passes `--all` only when both are 1.42 or
later. A request negotiated below 1.42 already prunes named volumes
without the flag, so nothing is left behind.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This bumps realtime from v2.143.4-r0 to v2.144.0-r0.


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

Planned after supabase/slim-services published v2.144.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>
Maps the permissions of `login`, `whoami` and the local-only commands
(`logout`, `feedback add|delete`, `issue bug|docs|feature`, `completion
bash|fish|powershell|zsh`, `telemetry enable|disable|status`), so scoped
tokens can tell which of them need Management API access.

- `login` composes the existing best-effort `loginProfile` block: the
profile lookup only stitches the telemetry identity, and login succeeds
when it fails.
- `whoami` declares `v1-get-profile` as required, since the profile is
its whole output.
- The other 13 leaves can't reach the Management API, so they declare no
operations and classify their flags as having no API effect. They get no
drift checks, which would be vacuous.
- `v1-get-profile` has no FGA permission in the spec, so it becomes the
first `OPERATIONS_WITHOUT_FGA` entry (a shared test change).
- Tests: `login` now runs the real login API layer against a recording
HTTP mock (`--token` path, a 403 on the profile lookup, and the browser
flow); `whoami` gains drift checks on its happy and 401 paths.

Notes:
- `login`'s device-flow poll (`/platform/cli/login/{sessionId}`) isn't
in the spec, so it can't be declared.
- `bootstrap` can reach the same profile call when no token resolves;
that path isn't changed here.
- `whoami -o …` fails before its required call, so the declaration
over-declares that error run.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Maps the top-level `pull` command to the Management API operations it
calls.

`pull` composes the config-pull, linked-project cache, database config
and function-download blocks directly, because its sub-commands'
declarations describe different flags and gating. The database and
function steps are gated on `--dry-run` being false, since a dry run
stops after the target and config reads. `pull` also declares its own
pooler-config entry: its database steps always get the resolved ref, so
the pooler fetch happens without `--project-ref`.

Findings: a bootstrap run resolves the database twice, so it fetches the
pooler config and mints a login role twice; step failures are isolated
but `pull` still fails, so every step call is required.

Untested conditions: a declined confirmation (it over-declares, like
`--dry-run`), a failing step under the real layers, and a branch-name
target under the real layers. `dbConfigLinked`,
`dbConfigPoolerFallbackLinked` and the own pooler entry overlap, so
dropping one alone fails no test. No blocks without a real-layer test,
no best-effort label turned required, no `OPERATIONS_WITHOUT_FGA`
entries.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
@supabase-cli-releaser
supabase-cli-releaser Bot requested review from a team and supabase-oss as code owners October 15, 2026 11:18
@supabase-cli-releaser supabase-cli-releaser Bot added the do not merge Approve to apply; do not merge. label Oct 15, 2026
Prashansa-K and others added 4 commits October 15, 2026 11:24
…ns (#7179)

Records which Management API operations each of these commands calls, as
`withPermissions` declarations checked by the existing completeness and
drift tests.

- `init`, `stack destroy|list|logs|prepare|restart|start|status|stop`
and legacy `start` and `stop` make no Management API calls; each
declares no operations and classifies every own flag, hidden ones
included. The aliased `start|status|stop` in the stack tree are covered
by the same declarations.
- Legacy `status` declares one best-effort `v1-list-all-branches`
through the existing `branchTarget` block, with a context naming the
linked-ref, cached-parent and token prerequisites.
- Legacy `start` gets a drift check on the requests its bucket-seeding
test records, and legacy `status` gets HTTP-level 200 and 403
branch-lookup tests checked against the declaration.
- No new blocks, conditions or `OPERATIONS_WITHOUT_FGA` entries.
Untested: the stack `start` drift check and the `SUPABASE_PROJECT_ID=''`
case for `status`.
- The `declaredPermissions` test now asserts `Declared` for `stack list`
instead of `Undeclared`, because that leaf is no longer undeclared. A
second test asserts that every pending command still in the tree is
reported as `Undeclared`, and fails once the pending list is empty, at
which point it can be deleted.
- Reworded the `status` runtime-layer comment, which claimed `status`
makes no Management API calls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
# Conflicts:
#	.github/workflows/test.yml
#	.oxlintrc.json
#	apps/cli-go/pkg/config/templates/Dockerfile
#	apps/cli/src/command-internal/config-pull-run.ts
#	apps/cli/src/command-internal/db-config.layer.ts
#	apps/cli/src/command-internal/output.encoders.ts
#	apps/cli/src/commands/bootstrap/bootstrap.command.ts
#	apps/cli/src/commands/branches/get/get.integration.test.ts
#	apps/cli/src/commands/config/diff/diff.integration.test.ts
#	apps/cli/src/commands/db/advisors/advisors.format.ts
#	apps/cli/src/commands/db/advisors/advisors.format.unit.test.ts
#	apps/cli/src/commands/db/advisors/advisors.integration.test.ts
#	apps/cli/src/commands/db/advisors/advisors.linked.ts
#	apps/cli/src/commands/domains/SIDE_EFFECTS.md
#	apps/cli/src/commands/domains/activate/activate.integration.test.ts
#	apps/cli/src/commands/domains/create/create.integration.test.ts
#	apps/cli/src/commands/domains/reverify/reverify.integration.test.ts
#	apps/cli/src/commands/encryption/SIDE_EFFECTS.md
#	apps/cli/src/commands/experimental/compute/delete/delete.command.ts
#	apps/cli/src/commands/experimental/compute/list/list.command.ts
#	apps/cli/src/commands/experimental/compute/list/list.integration.test.ts
#	apps/cli/src/commands/experimental/compute/new/new.command.ts
#	apps/cli/src/commands/experimental/compute/push/SIDE_EFFECTS.md
#	apps/cli/src/commands/experimental/compute/push/push.command.ts
#	apps/cli/src/commands/experimental/compute/status/status.command.ts
#	apps/cli/src/commands/functions/delete/delete.integration.test.ts
#	apps/cli/src/commands/functions/deploy/deploy.command.ts
#	apps/cli/src/commands/functions/deploy/deploy.integration.test.ts
#	apps/cli/src/commands/functions/download/SIDE_EFFECTS.md
#	apps/cli/src/commands/functions/download/download.command.ts
#	apps/cli/src/commands/functions/download/download.integration.test.ts
#	apps/cli/src/commands/functions/new/new.command.ts
#	apps/cli/src/commands/gen/bearer-jwt/bearer-jwt.command.ts
#	apps/cli/src/commands/gen/signing-key/signing-key.command.ts
#	apps/cli/src/commands/link/SIDE_EFFECTS.md
#	apps/cli/src/commands/link/link.command.ts
#	apps/cli/src/commands/postgres-config/delete/delete.handler.ts
#	apps/cli/src/commands/postgres-config/postgres-config.shared.ts
#	apps/cli/src/commands/postgres-config/update/update.handler.ts
#	apps/cli/src/commands/projects/SIDE_EFFECTS.md
#	apps/cli/src/commands/pull/pull.command.ts
#	apps/cli/src/commands/secrets/set/SIDE_EFFECTS.md
#	apps/cli/src/commands/secrets/set/set.command.ts
#	apps/cli/src/commands/secrets/set/set.integration.test.ts
#	apps/cli/src/commands/secrets/unset/SIDE_EFFECTS.md
#	apps/cli/src/commands/secrets/unset/unset.integration.test.ts
#	apps/cli/src/commands/seed/buckets/buckets.integration.test.ts
#	apps/cli/src/commands/services/services.command.ts
#	apps/cli/src/commands/snippets/download/download.handler.ts
#	apps/cli/src/commands/snippets/list/list.handler.ts
#	apps/cli/src/commands/snippets/list/list.integration.test.ts
#	apps/cli/src/commands/sso/add/SIDE_EFFECTS.md
#	apps/cli/src/commands/sso/add/add.handler.ts
#	apps/cli/src/commands/sso/update/SIDE_EFFECTS.md
#	apps/cli/src/commands/sso/update/update.handler.ts
#	apps/cli/src/commands/sso/update/update.integration.test.ts
#	apps/cli/src/commands/stop/stop.integration.test.ts
#	apps/cli/src/commands/vanity-subdomains/vanity-subdomains.integration.test.ts
#	apps/cli/src/telemetry/linked-project-cache.integration.test.ts
#	apps/cli/tests/helpers/compute.ts
@supabase-cli-releaser

Copy link
Copy Markdown
Contributor Author

Claude resolved the merge of next

Resolved every conflict by keeping next's Go CLI removal and its renames of Go-named encoders, modules and test helpers, and porting develop's work onto them: the typed Management API client migration, the command permission mappings and drift tests, the linked-project cache fixes and the doc updates. I also updated remaining uses of the renamed goOutput option in tests outside the conflicts, added the config-values test layer to tests develop added, and remapped secrets unset permissions for next's --all/--dry-run behavior.

File Resolution
.github/workflows/test.yml Kept develop's --shard arguments for the cli-e2e suite and dropped the SUPABASE_GO_BINARY env, since next deletes apps/cli-go.
.oxlintrc.json Kept both new overrides as separate entries: develop's supabase/no-raw-management-api-url plugin rule and next's restriction on reading process.env/Bun.env.
apps/cli/src/command-internal/config-pull-run.ts Kept both new imports: next's config-validation helpers and develop's permission block.
apps/cli/src/command-internal/db-config.layer.ts Merged the doc comment: next's removal of db remote commit plus develop's gen types wording.
apps/cli/src/command-internal/output.encoders.ts Kept develop's trimmed doc comment, pointing at next's renamed encodeSortedJson.
apps/cli/src/commands/bootstrap/bootstrap.command.ts Kept develop's permission imports and next's config-flag imports.
apps/cli/src/commands/branches/get/get.integration.test.ts Used next's outputFlag setup option, including the table value develop added and two non-conflicting develop tests, and kept develop's api usage.
apps/cli/src/commands/config/diff/diff.integration.test.ts Kept both sides' imports.
apps/cli/src/commands/db/advisors/advisors.format.ts Took develop's typed apiLintsToAdvisorLints and dropped the old untyped parser; it now imports next's encodeHtmlSafeJsonIndented.
apps/cli/src/commands/db/advisors/advisors.format.unit.test.ts Took develop's apiLintsToAdvisorLints tests and dropped the untyped-parser tests.
apps/cli/src/commands/db/advisors/advisors.integration.test.ts Took develop's typed-client tests with next's test names that no longer mention Go.
apps/cli/src/commands/db/advisors/advisors.linked.ts Took develop's typed getSecurityAdvisors call and dropped the hand-built request.
apps/cli/src/commands/domains/SIDE_EFFECTS.md Used develop's linked-project cache row with next's 'post-run' wording.
apps/cli/src/commands/domains/activate/activate.integration.test.ts Kept develop's import list; FileSystem and Schema are still used.
apps/cli/src/commands/domains/create/create.integration.test.ts Kept develop's import list; FileSystem and Schema are still used.
apps/cli/src/commands/domains/reverify/reverify.integration.test.ts Kept develop's import list; FileSystem and Schema are still used.
apps/cli/src/commands/encryption/SIDE_EFFECTS.md Used develop's linked-project cache row with next's 'post-run' wording.
apps/cli/src/commands/experimental/compute/delete/delete.command.ts Kept both sides' imports.
apps/cli/src/commands/experimental/compute/list/list.command.ts Kept both sides' imports.
apps/cli/src/commands/experimental/compute/list/list.integration.test.ts Kept both sides' imports.
apps/cli/src/commands/experimental/compute/new/new.command.ts Kept both sides' imports.
apps/cli/src/commands/experimental/compute/push/SIDE_EFFECTS.md Used next's env table and added develop's SUPABASE_PROJECT_ID row, re-padded to fit.
apps/cli/src/commands/experimental/compute/push/push.command.ts Kept both sides' imports.
apps/cli/src/commands/experimental/compute/status/status.command.ts Kept both sides' imports.
apps/cli/src/commands/functions/delete/delete.integration.test.ts Kept develop's new picker and invalid-slug tests and next's test title that no longer cites Go.
apps/cli/src/commands/functions/deploy/deploy.command.ts Kept both sides' imports.
apps/cli/src/commands/functions/deploy/deploy.integration.test.ts Merged imports and added cliConfigValuesTestLayer to develop's picker test.
apps/cli/src/commands/functions/download/SIDE_EFFECTS.md Used next's --legacy-bundle removal sections with develop's cache-fill wording; dropped develop's Go-proxy notes.
apps/cli/src/commands/functions/download/download.command.ts Added develop's withPermissions around next's handler that rejects --legacy-bundle and builds the API layer lazily.
apps/cli/src/commands/functions/download/download.integration.test.ts Merged imports (next's functionsLocalConfigLoader), replaced develop's mockProxy layers with cliConfigValuesTestLayer, added develop's exact-request and permission checks to next's Docker test, and dropped the Go-proxy tests.
apps/cli/src/commands/functions/new/new.command.ts Kept both sides' imports.
apps/cli/src/commands/gen/bearer-jwt/bearer-jwt.command.ts Kept both sides' imports.
apps/cli/src/commands/gen/signing-key/signing-key.command.ts Kept both sides' imports.
apps/cli/src/commands/link/SIDE_EFFECTS.md Took next's env table, which documents the deprecation warning --password now prints.
apps/cli/src/commands/link/link.command.ts Kept both sides' imports.
apps/cli/src/commands/postgres-config/delete/delete.handler.ts Kept develop's { changes, preserved } call shape with next's parseError/parseMessage names and 'failed to parse' wording.
apps/cli/src/commands/postgres-config/postgres-config.shared.ts Took develop's typed executeRaw read/write with next's renamed encoders and float formatter, its parse* names, and 'failed to parse response body'.
apps/cli/src/commands/postgres-config/update/update.handler.ts Kept develop's { changes, preserved } call shape with next's parseError/parseMessage names.
apps/cli/src/commands/projects/SIDE_EFFECTS.md Used next's terminal-color note and develop's delete cache-fill note.
apps/cli/src/commands/pull/pull.command.ts Kept both sides' imports.
apps/cli/src/commands/secrets/set/SIDE_EFFECTS.md Used next's Files Read table plus develop's linked-project.json row, and develop's batching note plus next's config-reading notes.
apps/cli/src/commands/secrets/set/set.command.ts Kept both sides' imports.
apps/cli/src/commands/secrets/set/set.integration.test.ts Merged imports, using next's shared/output/debug-logger.service path, and added cliConfigValuesTestLayer to develop's picker test.
apps/cli/src/commands/secrets/unset/SIDE_EFFECTS.md Used develop's cache-fill rows and picker row, adjusted to next's --all/--dry-run; took next's consent-gate notes.
apps/cli/src/commands/secrets/unset/unset.integration.test.ts Took next's rewritten suite; added develop's permission checks to the named and --all tests, and kept develop's picker/cache test, adapted to --all.
apps/cli/src/commands/secrets/unset/unset.command.ts Not conflicted. Remapped permissions to next's flags: listing secrets requires --all, and the bulk delete runs only without --dry-run.
apps/cli/src/commands/seed/buckets/buckets.integration.test.ts Kept both sides' imports.
apps/cli/src/commands/services/services.command.ts Kept both sides' imports.
apps/cli/src/commands/snippets/download/download.handler.ts Kept develop's mapHttpError and imported next's quoteBytes instead of the old Go quote helper.
apps/cli/src/commands/snippets/list/list.handler.ts Took develop's typed executeRaw flow with next's struct encoders, renamed shape helpers and outputFlag naming.
apps/cli/src/commands/snippets/list/list.integration.test.ts Used next's outputFlag option with develop's response?: unknown type and empty-list TOML test.
apps/cli/src/commands/sso/add/SIDE_EFFECTS.md Used next's exit-code wording with develop's schema-mismatch and undecodable-2xx conditions, re-padded.
apps/cli/src/commands/sso/add/add.handler.ts Took develop's typed executeRaw POST and dropped the hand-built request; it outputs rawBody through next's encoders and SSO_PROVIDER_RESPONSE_SHAPE.
apps/cli/src/commands/sso/update/SIDE_EFFECTS.md Used next's wording with develop's typed-client and per-request profile behavior and develop's exit-code changes.
apps/cli/src/commands/sso/update/update.handler.ts Took develop's typed executeRaw PUT with next's encoders and response shape.
apps/cli/src/commands/sso/update/update.integration.test.ts Dropped the tests for the old raw-HTTP GET, which develop removed, and kept next's test title that no longer cites Go.
apps/cli/src/commands/stop/stop.integration.test.ts Used next's test shape and name with develop's dockerServerApiVersion route option.
apps/cli/src/commands/vanity-subdomains/vanity-subdomains.integration.test.ts Kept develop's schema-valid SAMPLE_PROJECT and next's OutputFlagValue type.
apps/cli/src/telemetry/linked-project-cache.integration.test.ts Used next's test shape with develop's schema-valid project body.
apps/cli/tests/helpers/compute.ts Kept develop's real-layer tty, settings and project-ref wiring and added next's configValuesLayer().
apps/cli/src/commands/projects/list/list.integration.test.ts Not conflicted. Renamed develop's leftover goOutput: to next's outputFlag:.
apps/cli/src/commands/projects/create/create.integration.test.ts Not conflicted. Renamed develop's leftover goOutput: to next's outputFlag:.
apps/cli/src/commands/sso/add/add.integration.test.ts Not conflicted. Renamed develop's leftover goOutput: to next's outputFlag:.
apps/cli/src/commands/postgres-config/postgres-config.integration.test.ts Not conflicted. Updated the expected error messages to next's 'failed to parse … response' wording.

Deleted: apps/cli-go/pkg/config/templates/Dockerfile.

Decisions for @supabase/cli. Confirm them, or push a change to this branch:

  • Next redesigned secrets unset (names or --all, --dry-run, refusal without --yes), while develop mapped its permissions and documented the old empty-args and piped-confirm behavior. Which wins? Chose: Next's behavior. Develop's permission mapping is ported to it (listing secrets only with --all, delete only without --dry-run), and develop's permission and cache tests are adapted to --all.
  • functions download docs: develop documented the Go proxy behind --legacy-bundle, which next removed. Chose: Next's removal sections plus develop's cache-fill wording; develop's Go-proxy notes are dropped.
  • link docs for SUPABASE_DB_PASSWORD / --password: develop says neither is read; next says the hidden flag is accepted and prints a deprecation warning. Chose: Next's wording, because next's handler prints that warning.

Quick checks. pnpm run check:all --continue (exit 1) failed on the merged tree.

Claude's fix. Fixed the types:check failure: develop's new tests that compare real requests against the permission map in link, functions deploy, config diff and gen types built their test layers without the CliConfigValues service that next's handlers now require, so they now also merge in cliConfigValuesTestLayer like the other tests in those files. There were no open review findings.

Approve to fast-forward next once checks pass (workflow run).

@supabase-cli-releaser supabase-cli-releaser Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Workflow changes for a maintainer

Claude's edits under .github/ are not pushed, because workflows on this branch run with repository secrets. Review them, then use Commit suggestions so they run.

Comment thread .github/workflows/test.yml Outdated
Comment thread .github/workflows/test.yml Outdated
Comment thread .github/workflows/test.yml Outdated
Comment thread .github/workflows/test.yml Outdated
Comment thread .github/workflows/test.yml Outdated
Comment thread .github/workflows/test.yml Outdated
Comment thread .github/workflows/test.yml Outdated
Comment on lines +416 to +417
env:
SUPABASE_GO_BINARY: ${{ github.workspace }}/apps/cli-go/supabase-go

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
env:
SUPABASE_GO_BINARY: ${{ github.workspace }}/apps/cli-go/supabase-go

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Superseded: 8a806fd removes these Go-CLI leftovers directly.

🤖 Addressed by Claude Code

Comment thread .github/workflows/test.yml Outdated
with:
dependency-firewall-token: ${{ secrets.DF_FIREWALL_TOKEN }}
sticky-disks: "true"
go-cache: "false"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
go-cache: "false"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Superseded: 8a806fd removes these Go-CLI leftovers directly.

🤖 Addressed by Claude Code

Comment thread .github/workflows/test.yml Outdated
with:
dependency-firewall-token: ${{ secrets.DF_FIREWALL_TOKEN }}
sticky-disks: "true"
go-cache: "false"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
go-cache: "false"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Superseded: 8a806fd removes these Go-CLI leftovers directly.

🤖 Addressed by Claude Code

Comment thread apps/cli/src/commands/link/link.integration.test.ts Fixed

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 AI Review

Verified all eight findings from both reviews: seven confirmed and one refuted. Confirmed three response-compatibility regressions, a retry-test coverage gap, and three obsolete CI configurations. Corrected the affected command examples and go-cache count. The SAML finding is refuted because the generated schemas already support default mappings. Tests were not run because dependencies are absent.

Findings

Severity Location Category Sources Claim
🟠 MAJOR packages/api/src/generated/contracts.ts:3370 backward-compatibility codex Requiring nimbus_oauth_email_optional rejects previously accepted auth-config responses that omit it, including successful auth-update responses decoded during config push.
🟠 MAJOR packages/api/src/generated/contracts.ts:258 backward-compatibility codex Removing nullable import_map_path support makes functions deploy reject existing function-list responses containing import_map_path: null.
🟠 MAJOR apps/cli/src/commands/snippets/download/download.handler.ts:159 backward-compatibility codex The full-response decoder makes snippets download fail for previously supported responses without description, even when content.sql is valid.
🟡 MINOR .github/workflows/test.yml:76 merge-resolution claude The check job unnecessarily runs a third-party keyring-unlock action for the removed cli-go package.
🟡 MINOR .github/workflows/test.yml:113 merge-resolution claude Six setup calls pass go-cache even though the local composite action no longer declares that input.
🟡 MINOR .github/workflows/test.yml:410 merge-resolution claude Both e2e steps set an unused SUPABASE_GO_BINARY variable pointing to the removed Go CLI.
🟡 MINOR apps/cli/src/commands/functions/deploy/deploy.integration.test.ts:1113 test-coverage codex The deploy retry test cannot detect removal of the production client-retry opt-out because its shared mock already disables client retries.
Refuted findings (kept for transparency, not posted as review comments)
  • apps/cli/src/commands/sso/sso.saml.ts:130 (backward-compatibility): Strict attribute-mapping validation rejects supported SAML default mappings because the generated schema does not model default.
    Refuted: Both generated request schemas already include default and accept JSON values such as 3. packages/api/scripts/generate.ts:219-276 preserves property names like default during generation, and sso.saml.unit.test.ts:109-117 retains the default: 3 case. Excess-property rejection does not reject this modeled field.

Stats

Claude findings: 3 · Codex findings: 5 · Confirmed: 7 · Refuted: 1 · Uncertain: 0


Models: claude-opus-5-5 + gpt-6.1-sol · Trigger: manual · Workflow run

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

Comment thread .github/workflows/test.yml Outdated
Comment thread .github/workflows/test.yml Outdated
Comment thread .github/workflows/test.yml Outdated
@@ -3266,7 +3367,7 @@ export const V1GetAuthServiceConfigOutput = Schema.Struct({
Schema.Null,
]),
nimbus_oauth_client_id: Schema.Union([Schema.String, Schema.Null]),
nimbus_oauth_email_optional: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])),
nimbus_oauth_email_optional: Schema.Union([Schema.Boolean, Schema.Null]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 MAJOR · backward-compatibility · source: codex

Requiring nimbus_oauth_email_optional rejects previously accepted auth-config responses that omit it, including successful auth-update responses decoded during config push.

Evidence: packages/api/src/generated/contracts.ts:3370,8935 require the field in both GET and PATCH auth outputs. apps/cli/src/commands/config/push/push.handler.ts:678-687 uses the typed updateAuthServiceConfig method. The diff removes the optional-field override and adds the field to historical auth-response fixtures.

Suggested fix: Restore the optional-field override for AuthConfigResponse_Output and retain regression coverage for responses omitting the field.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not introduced by this sync: packages/api and this code are identical to develop, so the change came from develop's typed Management API client migration. Out of scope for a branch sync; it should be fixed on develop and will flow into next through the next sync.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The required nimbus_oauth_email_optional field comes from the regenerated API contracts and matching fixtures, not from how the merge resolved a conflict. It is not introduced by the merge and is out of scope for the sync; please raise it as a separate issue.

@@ -239,7 +255,7 @@ export const FunctionResponse_Output = Schema.Struct({
verify_jwt: Schema.optionalKey(Schema.Boolean),
import_map: Schema.optionalKey(Schema.Boolean),
entrypoint_path: Schema.optionalKey(Schema.String),
import_map_path: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])),
import_map_path: Schema.optionalKey(Schema.String),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 MAJOR · backward-compatibility · source: codex

Removing nullable import_map_path support makes functions deploy reject existing function-list responses containing import_map_path: null.

Evidence: packages/api/src/generated/contracts.ts:258 accepts only an optional string. apps/cli/src/shared/functions/deploy.ts:167-172 omits other nullable fields but excludes import_map_path; lines 216-225 decode the resulting list against FunctionResponse_Output. Lines 1714-1721 turn decoding failure into a command error.

Suggested fix: Restore nullable import_map_path output schemas through guarded OpenAPI overrides and cover a deploy list response containing null.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not introduced by this sync: packages/api and this code are identical to develop, so the change came from develop's typed Management API client migration. Out of scope for a branch sync; it should be fixed on develop and will flow into next through the next sync.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The non-nullable import_map_path schema and the separate list and deploy null-stripping sets came in with the generated API refresh and deploy code, and they match each other. It is not introduced by the merge and is out of scope for the sync.

Comment on lines +159 to +161
const snippet = yield* decodeSnippet(rawBody).pipe(
Effect.catch(mapDownloadError),
Effect.tapError(() => fetching?.fail() ?? Effect.void),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 MAJOR · backward-compatibility · source: codex

The full-response decoder makes snippets download fail for previously supported responses without description, even when content.sql is valid.

Evidence: apps/cli/src/commands/snippets/download/download.handler.ts:110,159-161 decodes the complete generated output before either SQL or JSON output. packages/api/src/generated/contracts.ts:2731 requires description. The diff replaces the content-only decoder and adds description: null to the existing recorded response.

Suggested fix: Make description optional through an OpenAPI response override and test the original response without adding a synthetic field.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not introduced by this sync: packages/api and this code are identical to develop, so the change came from develop's typed Management API client migration. Out of scope for a branch sync; it should be fixed on develop and will flow into next through the next sync.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Decoding the full snippet response with a required description is existing code from one side of the merge, not something the merge produced. It is not introduced by the merge and is out of scope for the sync.

Comment on lines +1113 to +1115
it.effect("retries a rate-limited deploy only through the command's own loop", () => {
let deployAttempts = 0;
const { layer, out, api } = apiDeployHarness((request) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MINOR · test-coverage · source: codex

The deploy retry test cannot detect removal of the production client-retry opt-out because its shared mock already disables client retries.

Evidence: apps/cli/src/commands/functions/deploy/deploy.integration.test.ts:710-715 constructs apiDeployHarness with mockCommandPlatformApi. apps/cli/tests/helpers/command-mocks.ts:595-602 sets maxRetries: 0. The test at lines 1113-1144 checks two POSTs and the command warning, while production passes NO_CLIENT_RETRY at apps/cli/src/shared/functions/deploy.ts:1843.

Suggested fix: Construct this test's API client with production retries enabled and verify that removing NO_CLIENT_RETRY makes the warning assertion fail.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not introduced by this sync: packages/api and this code are identical to develop, so the change came from develop's typed Management API client migration. Out of scope for a branch sync; it should be fixed on develop and will flow into next through the next sync.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This test-coverage gap in the deploy retry test is in existing test code and was not caused by combining the branches. It is not introduced by the merge and is out of scope for the sync.

## Summary

**TL;DR:** A new `Flaky check` workflow runs one commit on many fresh
runners with retries off and reports every test that both passed and
failed. It runs nightly on `develop`, weekly for e2e, and on demand
through the `run-flaky-check` PR label, so PRs that fix flaky tests can
show the fix holds.

```mermaid
flowchart LR
  T["nightly develop / weekly e2e<br/>run-flaky-check label / dispatch"] --> P["plan: commit, suites, N runs"]
  P --> M["N fresh runners per suite<br/>retries off, JUnit output"]
  M --> R["report: flaky / always failing<br/>runs without results"]
  R --> O["artifact + job summary<br/>PR comment"]
```

### Why

Flaky tests surface one at a time in unrelated PRs and get retried away.
There is no way to ask "is this commit stable?" or to show that a
flaky-test fix actually holds. `stack-stress.yml` covers two stack
scenarios only.

### What changed

- `flaky-check.yml` runs:
  - nightly: unit + integration ×10 on `develop`
  - weekly: CLI e2e (4 shards + `cli-e2e`) and stack whole-stack e2e ×3
- `run-flaky-check` label: unit + integration ×10 on the PR merge
commit, plus a `focused` suite that repeats the tests the PR affects
(`vitest --changed` against the merge base, `--repeats=4`, ×10 runs)
- manual dispatch: any ref, suites, run count, repeats, and file filter
- The label is removed when the run starts, so re-adding it starts
another run.
- A report job classifies each test as flaky (mixed results) or always
failing. It also lists runs that produced no usable results: timeouts,
crashes, missing JUnit reports, or missing uploads. Each failed
`--repeats` execution counts separately.
- The report goes to the job summary, a `flaky-check-report` artifact
(`report.md`, `report.json`), and one sticky PR comment. The report job
fails when it finds anything.
- `.github/MAINTAINERS.md` documents the triggers and the `focused`
caveats.

### Linked issue

None; maintainer change. The `run-flaky-check` label already exists.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
avallete and others added 5 commits October 15, 2026 12:42
Local Studio logs pages fail with "Backend error" on the default
Postgres analytics backend (#7155). Logflare 1.52.0 and later cast
endpoint query parameters such as `@project` to `jsonb` when translating
to Postgres, so every logs query fails with `invalid input syntax for
type json` (Logflare/logflare#4158).

- Pins `analytics` back to Logflare 1.50.15 (slim `v1.50.15-r1`), the
last release before the regression, in the stack catalog and both
service Dockerfiles.
- Adds an `UPGRADE_HOLDS` entry for `analytics` to the slim release
planner so the bump bot can't upgrade it again. Hotfix revisions of
1.50.15 still go through. Remove the entry once Logflare ships a fix.

The per-minute log chart still fails on the Postgres backend because
`IFNULL` is never translated (Logflare/logflare#4159); that has been the
case in every Logflare version.

A local database first created by Logflare 1.53.x (CLI 2.121.0) keeps
its Oban tables only in `_analytics`, which 1.50.15 doesn't read. On
those databases the analytics alerting and event-touch workers restart
in a loop and log `relation "public.oban_jobs" does not exist`. Log
ingestion and queries are unaffected, and `supabase stop --no-backup`
clears it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This bumps storage from v1.83.1-r0 to v1.83.3-r0.


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

Planned after supabase/slim-services published v1.83.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>
Closes the command permission mapping: every command leaf now declares a
permission status, so the pending list is gone.

The six commands that still hand off to the bundled Go binary (`db
branch create|delete|list|switch`, `db remote changes`, `gen keys`)
declare `unmapped` with reason `go-delegated`. The completeness test now
requires a declaration on every leaf, and a second check fails if a path
on the go-delegation allowlist stops being a real leaf declared
`unmapped`. The pending list and the registry test that depended on it
are removed; the `Undeclared` lookup result stays for command groups.

Findings: `unmapped` records how these commands are implemented, not
what they need. Reading the Go source, the four `db branch` leaves make
no Management API calls, `gen keys` makes one
(`V1GetPostgrestServiceConfig`), and `db remote changes` runs the same
diff as `db diff` against the linked database. All six could be mapped
later, which would let the `unmapped` status and its allowlist go.

Untested conditions: the six `unmapped` commands make no claim, so
nothing checks them. No blocks without a real-layer test, no best-effort
label turned required, no `OPERATIONS_WITHOUT_FGA` entries.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
…next

Keeps next's removal of the db branch, db remote changes/commit and gen keys
commands and declares empty permissions on those tombstones, so the
go-delegation allowlist is now empty. Passes the --all/--dry-run switch
values in the secrets unset drift assertions, and drops the go-cache,
SUPABASE_GO_BINARY and keyring-unlock leftovers from the workflows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@supabase-cli-releaser

Copy link
Copy Markdown
Contributor Author

Claude repair round

No CI checks failed, so no code changes were needed for this sync. All four review findings are about code that one side already had, not about how the merge combined them, so they are declined as out of scope for the sync.

0 findings fixed, 4 declined (workflow run).

@avallete avallete left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

CI is green on d78b1ed (the fast-forward guard fails as designed). Approving to fast-forward next.

@supabase-cli-releaser
supabase-cli-releaser Bot merged commit d78b1ed into next Oct 15, 2026
72 of 73 checks passed
@supabase-cli-releaser
supabase-cli-releaser Bot deleted the sync/develop-into-next branch October 15, 2026 14:04
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.

5 participants