Repository navigation
chore(repo): sync develop into next - #7183
Conversation
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>
…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
Claude resolved the merge of
|
| 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 downloaddocs: 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.linkdocs forSUPABASE_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).
| env: | ||
| SUPABASE_GO_BINARY: ${{ github.workspace }}/apps/cli-go/supabase-go |
There was a problem hiding this comment.
| env: | |
| SUPABASE_GO_BINARY: ${{ github.workspace }}/apps/cli-go/supabase-go |
There was a problem hiding this comment.
Superseded: 8a806fd removes these Go-CLI leftovers directly.
🤖 Addressed by Claude Code
| with: | ||
| dependency-firewall-token: ${{ secrets.DF_FIREWALL_TOKEN }} | ||
| sticky-disks: "true" | ||
| go-cache: "false" |
There was a problem hiding this comment.
| go-cache: "false" |
There was a problem hiding this comment.
Superseded: 8a806fd removes these Go-CLI leftovers directly.
🤖 Addressed by Claude Code
| with: | ||
| dependency-firewall-token: ${{ secrets.DF_FIREWALL_TOKEN }} | ||
| sticky-disks: "true" | ||
| go-cache: "false" |
There was a problem hiding this comment.
| go-cache: "false" |
There was a problem hiding this comment.
Superseded: 8a806fd removes these Go-CLI leftovers directly.
🤖 Addressed by Claude Code
There was a problem hiding this comment.
🤖 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.
| @@ -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]), | |||
There was a problem hiding this comment.
🟠 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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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), | |||
There was a problem hiding this comment.
🟠 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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
| const snippet = yield* decodeSnippet(rawBody).pipe( | ||
| Effect.catch(mapDownloadError), | ||
| Effect.tapError(() => fetching?.fail() ?? Effect.void), |
There was a problem hiding this comment.
🟠 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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
| it.effect("retries a rate-limited deploy only through the command's own loop", () => { | ||
| let deployAttempts = 0; | ||
| const { layer, out, api } = apiDeployHarness((request) => { |
There was a problem hiding this comment.
🟡 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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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>
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>
Claude repair roundNo 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). |
Merging
developintonextconflicts. This branch starts at the tip ofdevelop(a982140);nextis at8e5a4cb.Conflicting files:
.github/workflows/test.yml.oxlintrc.jsonapps/cli-go/pkg/config/templates/Dockerfileapps/cli/src/command-internal/config-pull-run.tsapps/cli/src/command-internal/db-config.layer.tsapps/cli/src/command-internal/output.encoders.tsapps/cli/src/commands/bootstrap/bootstrap.command.tsapps/cli/src/commands/branches/get/get.integration.test.tsapps/cli/src/commands/config/diff/diff.integration.test.tsapps/cli/src/commands/db/advisors/advisors.format.tsapps/cli/src/commands/db/advisors/advisors.format.unit.test.tsapps/cli/src/commands/db/advisors/advisors.integration.test.tsapps/cli/src/commands/db/advisors/advisors.linked.tsapps/cli/src/commands/domains/SIDE_EFFECTS.mdapps/cli/src/commands/domains/activate/activate.integration.test.tsapps/cli/src/commands/domains/create/create.integration.test.tsapps/cli/src/commands/domains/reverify/reverify.integration.test.tsapps/cli/src/commands/encryption/SIDE_EFFECTS.mdapps/cli/src/commands/experimental/compute/delete/delete.command.tsapps/cli/src/commands/experimental/compute/list/list.command.tsapps/cli/src/commands/experimental/compute/list/list.integration.test.tsapps/cli/src/commands/experimental/compute/new/new.command.tsapps/cli/src/commands/experimental/compute/push/SIDE_EFFECTS.mdapps/cli/src/commands/experimental/compute/push/push.command.tsapps/cli/src/commands/experimental/compute/status/status.command.tsapps/cli/src/commands/functions/delete/delete.integration.test.tsapps/cli/src/commands/functions/deploy/deploy.command.tsapps/cli/src/commands/functions/deploy/deploy.integration.test.tsapps/cli/src/commands/functions/download/SIDE_EFFECTS.mdapps/cli/src/commands/functions/download/download.command.tsapps/cli/src/commands/functions/download/download.integration.test.tsapps/cli/src/commands/functions/new/new.command.tsapps/cli/src/commands/gen/bearer-jwt/bearer-jwt.command.tsapps/cli/src/commands/gen/signing-key/signing-key.command.tsapps/cli/src/commands/link/SIDE_EFFECTS.mdapps/cli/src/commands/link/link.command.tsapps/cli/src/commands/postgres-config/delete/delete.handler.tsapps/cli/src/commands/postgres-config/postgres-config.shared.tsapps/cli/src/commands/postgres-config/update/update.handler.tsapps/cli/src/commands/projects/SIDE_EFFECTS.mdapps/cli/src/commands/pull/pull.command.tsapps/cli/src/commands/secrets/set/SIDE_EFFECTS.mdapps/cli/src/commands/secrets/set/set.command.tsapps/cli/src/commands/secrets/set/set.integration.test.tsapps/cli/src/commands/secrets/unset/SIDE_EFFECTS.mdapps/cli/src/commands/secrets/unset/unset.integration.test.tsapps/cli/src/commands/seed/buckets/buckets.integration.test.tsapps/cli/src/commands/services/services.command.tsapps/cli/src/commands/snippets/download/download.handler.tsapps/cli/src/commands/snippets/list/list.handler.tsapps/cli/src/commands/snippets/list/list.integration.test.tsapps/cli/src/commands/sso/add/SIDE_EFFECTS.mdapps/cli/src/commands/sso/add/add.handler.tsapps/cli/src/commands/sso/update/SIDE_EFFECTS.mdapps/cli/src/commands/sso/update/update.handler.tsapps/cli/src/commands/sso/update/update.integration.test.tsapps/cli/src/commands/stop/stop.integration.test.tsapps/cli/src/commands/vanity-subdomains/vanity-subdomains.integration.test.tsapps/cli/src/telemetry/linked-project-cache.integration.test.tsapps/cli/tests/helpers/compute.tsTo 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.