chore: production deploy - #6514
Open
supabase-cli-releaser[bot] wants to merge 155 commits into
Open
supabase-cli-releaser[bot] wants to merge 155 commits into
supabase-cli-releaser[bot] wants to merge 155 commits into
Conversation
) ## What kind of change does this PR introduce? Tooling/chore — adds commitlint, tied to a fixed scope list. ## What is the current behavior? There is no commitlint or commitizen setup. PR titles must follow conventional-commits format (checked in CI by `amannn/action-semantic-pull-request`), but scopes are unrestricted free text, enforced only by human review. ## What is the new behavior? - Adds `commitlint.config.js` with a `scope-enum` rule: one scope per real turbo/pnpm workspace project (`api`, `cli`, `cli-e2e`, `cli-go`, `cli-test-helpers`, `config`, `docs`, `process-compose`, `stack` — verified against `pnpm -r list`) plus escape scopes for changes that don't map to a single project (`ci`, `repo`, `misc`, `release`). The 8 per-platform `packages/cli-{platform}` binary-wrapper packages are folded into `cli`. `release` isn't a turbo project (`tools/release` has no `package.json`) but is kept as an escape scope because `propose-release-notes.ts` genuinely commits with that scope. - Adds a local `commit-msg` git hook via husky that runs commitlint on every commit. CI checkouts skip installing this hook (`HUSKY=0` in the shared setup action) so bot-authored commits are never gated by it — scope enforcement for those stays on the PR-title CI check. - Mirrors the same scope list into the `amannn/action-semantic-pull-request` step in `lint-pull-request.yml`, so PR titles are held to the same list in CI. - Updates `.github/dependabot.yml`: the `npm` and `docker` ecosystems previously auto-generated scopes (`deps`/`deps-dev`/`docker`) that aren't in the new fixed list, which would have started failing their own PR-title check — both remapped to `misc`. The `gomod` ecosystem had no `commit-message` config at all, so it fell back to a repository-detected scope also outside the allowlist — mapped to `chore(cli-go): ` since that's precisely the project those updates belong to. `github-actions` (already `ci`) is untouched. - Documents the local commit-msg hook in `CONTRIBUTING.md`, and adds one clarifying sentence to `AGENTS.md` pointing at `commitlint.config.js` as the source of truth for allowed scopes. No commitizen/interactive prompt added — commitlint validates whatever message is typed.
…2285) (#6497) ## Summary An explicit `--workdir`/`SUPABASE_WORKDIR` could silently let `loadCliConfig`/`findCliProjectRoot` climb ancestor directories to find `supabase/config.{toml,json}` — so `--workdir ./sub` where `sub/supabase/` doesn't exist could silently load, or **push**, an unrelated parent project's config instead of failing. A defaulted (unset) workdir still climbs exactly as before. Linear: [CLI-2285](https://linear.app/supabase/issue/CLI-2285/explicit-workdir-must-not-climb-to-a-parent-project-config-diffpush). ## What changed - `LegacyCliSettings` gains `explicitWorkdir: boolean`; a new `legacyShouldSearchAncestors(cliSettings)` helper (`command-internal/legacy-workdir-search.ts`) gates the ancestor search at every affected call site: `config diff/push/pull`, `gen types`, `seed buckets`, `storage ls/mv/rm/cp`, `functions new`, `experimental workers`, and `functions serve/deploy`. - `packages/config`'s `findCliProjectRoot` gains an optional `FindCliProjectPathsOptions` parameter (additive), matching `findCliProjectPaths`'s existing `search: false` support. - `config diff/push/pull`, `gen types`, `storage`, and `seed buckets` now hard-fail with a clear error instead of silently falling back to embedded defaults (or an unrelated ancestor's config) when an explicit workdir has no project. - The same commands now validate the workdir is an existing directory up front (reusing the existing `start`/`stop`/`status` pattern), so a typo'd path fails with "no such directory" instead of a confusing "file not found". - The missing-project message (`command-internal/legacy-workdir-project.ts`) no longer suggests `supabase init` for an explicit workdir — which could scaffold a fresh config at the wrong path, leading to a subsequent `push` overwriting the real project — and instead names the resolved path, suggesting an ancestor's path when one genuinely has a project. - `gen types` no longer leaks a raw `CliConfigParseError` tag as its error message on a malformed config. - `experimental workers new` gained the same workdir-existence guard `functions new` already had, closing an identical scaffold-at-a-nonexistent-path gap. ## Follow-ups filed separately (explicitly out of scope here) - `secrets set` ignores `--workdir` entirely (loads from `runtimeInfo.cwd`). - Extending the explicit-workdir hard-fail policy to the `db`/`migration` TOML-only loaders. - `--debug` workdir logging, `--workdir` help-text tightening, and a couple of smaller consistency nits (error-code unification across the `config` family, `workers push`'s hardcoded error paths).
….4 in /apps/cli-go in the go-minor group across 1 directory (#6504) Bumps the go-minor group with 1 update in the /apps/cli-go directory: [github.com/posthog/posthog-go](https://github.com/posthog/posthog-go). Updates `github.com/posthog/posthog-go` from 1.24.3 to 1.24.4 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/posthog/posthog-go/releases">github.com/posthog/posthog-go's releases</a>.</em></p> <blockquote> <h2>1.24.4</h2> <h2>Unreleased</h2> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/PostHog/posthog-go/blob/main/CHANGELOG.md">github.com/posthog/posthog-go's changelog</a>.</em></p> <blockquote> <h2>1.24.4</h2> <h3>Patch Changes</h3> <ul> <li>c3270b6: Align local feature flag property matching with the flags service, including boolean-array precedence, canonical JSON stringification, and operator-specific case folding.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/PostHog/posthog-go/commit/0216c2384b67ef39914e20fd0065c57243fb42d2"><code>0216c23</code></a> chore: release v1.24.4 [version bump] [skip ci]</li> <li><a href="https://github.com/PostHog/posthog-go/commit/c3270b6bd8138865c0f0d0a57affaceb7a2bb6cb"><code>c3270b6</code></a> fix(flags): align local exact matching with the flags service (<a href="https://redirect.github.com/posthog/posthog-go/issues/300">#300</a>)</li> <li><a href="https://github.com/PostHog/posthog-go/commit/d5152ea6c4155c781cbdc0512eb99b60977fe90e"><code>d5152ea</code></a> chore(deps): bump the github-actions group with 2 updates (<a href="https://redirect.github.com/posthog/posthog-go/issues/304">#304</a>)</li> <li><a href="https://github.com/PostHog/posthog-go/commit/518931f315c1ff5bb2786d4b53b0c9fc316a1d1b"><code>518931f</code></a> chore(deps-dev): bump <code>@changesets/cli</code> from 3.0.0 to 3.0.1 in the release-tool...</li> <li>See full diff in <a href="https://github.com/posthog/posthog-go/compare/v1.24.3...v1.24.4">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…sumer (CLI-2339) (#6498) ## Summary CLI-2320 confined `auth.email.template.*.content_path`/`auth.email.notification.*.content_path` resolution to the project root, but only inside `config push`'s own content loader. This centralizes that containment into the shared resolver `legacyResolveEmailTemplateContentPath` (`legacy-config-validate.ts`), so it now protects every consumer, with no flag and no opt-out: `config push`, `start` (an eager pre-Docker validation pass covering every configured template plus every enabled notification — the same set Kong's mount builder consumes), and the shared config-validation path reached by `db`/`migration`/`status`/`stop`/`functions deploy`/`functions serve`/`functions download`/`gen types`/`inspect`/`bootstrap`. Linear: CLI-2339 (follow-up from CLI-2320's own PR review, #6489). While extending the check's reach, two bugs surfaced and are fixed in the same change: - The canonicalization helper treated any `realpath` failure as "this path doesn't exist yet" and fell back to lexical resolution — which also covers a dangling symlink, an `EACCES`-blocked target, or a symlink loop, all of which exist on disk but couldn't be canonicalized. That let an in-root symlink pointing outside the project root bypass containment silently, most seriously for `start`'s Kong mount (a root-privileged, `rw` Docker bind mount). Fixed by distinguishing "genuinely absent" from "exists but uncanonicalizable" and following a symlink to its real target before checking it. The ancestor walk was also rewritten iteratively to remove a stack-depth limit on deeply nested missing paths. - `start`'s Kong mount resolved and validated a path early, then independently re-derived and used a second, unresolved path much later when building the Docker bind mount — a check/use gap and duplicated resolution logic. The validated, read-verified path is now threaded straight through to the bind-mount builder instead of being re-derived. The rejection message now includes the declared `content_path` value and the project root (not the fully symlink-dereferenced target, to avoid echoing back where an escaping symlink actually points). ## What changed - `legacy-config-validate.ts` — `legacyResolveEmailTemplateContentPath` now canonicalizes and containment-checks its result before returning; new `canonicalPathForContainment`/ `canonicalizeExistingPath`/`isPathContainedInRoot` helpers. - `push.auth-email-content.ts` — deleted its local, now-redundant containment helpers; both template and notification loading route through the shared resolver. - `start.handler.ts`/`kong.service.ts` — `resolveKongEmailTemplateMounts` resolves, containment- checks, and read-verifies every Kong-mounted template/notification once, early, before any Docker work; `LegacyKongEmailTemplateMount` carries the resolved path, and `legacyBuildKongEmailTemplateBind` is now a pure formatter with no resolution logic of its own. - `SIDE_EFFECTS.md` updates across `start`, `status`, `stop`, `db diff`, `migration squash`, `functions deploy/serve/download`, and one line in `apps/cli/AGENTS.md`'s "config validation has one home" section. Follow-ups filed for the adjacent untrusted-path fields this ticket didn't touch (CLI-2344), and a message-polish gap where an `EACCES` behind a followed symlink surfaces a raw filesystem error instead of the usual containment message (CLI-2345) — in both cases the path is still rejected, just with a less specific error.
## TL;DR Adds live e2e coverage for `branches get`, `branches update` and `branches disable` ## whats introduced? - `branches get`: creates a branch, fetches it by name and asserts the pretty connection table renders - `branches update`: creates a branch, renames it with `--name --output json`, asserts the confirmation and payload, then proves the new name resolves through `branches get` - `branches disable`: creates and deletes a branch so branching is enabled with no preview branches left, disables preview branching for the project and asserts the confirmation on stdout ## ref: - closes: CLI-2327 - passed here: https://github.com/supabase/cli/actions/runs/34112181467
## TL;DR fixes `supabase sso update --log-level error <id>` failing with `accepts 1 arg(s), received 2` by registering the built-in `--log-level` as value taking in the raw argv scanners.. ## whats biting the user? `--log-level` shows up in every command's help and the parser accepts it, but the raw argv scanners did not know it consumes a value so `error` was counted as an extra positional and the command refused to run. A typed `--log-level` also killed shell completion for the rest of the line. ## now fixed by: - registering `log-level` in `PERSISTENT_VALUE_FLAG_NAMES` and `globalFlagsWithValues`, so positional counting consumes its value like every other global - registering the built-in flags where output format and shell completion resolve, so `--version` output and tab completion keep working around them also added regression tests for the issue's exact spelling plus the pre-path, inline, completion, and version spellings ## ref: - closes CLI-2329 - closes #6482
## Summary Rewrites `@supabase/stack` around one managed-only runtime shared by strict native and container execution modes. The package owns durable configuration and secrets, sticky ports, artifact preparation, lifecycle arbitration, per-service eager or lazy activation, service migrations, ingress, retained and live logs, and exact resource cleanup. A stopped stack has no resident supervisor or runtime resources: status and retained logs come from durable state, while a later start creates a fresh owner and performs clean recovery. PostgreSQL 17 is the only eager service by default; other enabled services activate through stack ingress, and callers can configure eager activation. Dependency-ready workloads start concurrently. Docker-compatible engines, including Podman, share the same container path. Enabled lazy services prepare their artifacts in the background after startup by default. `preparation: "on-demand"` retains full lazy downloading, while explicit `prepare()` remains available in either mode. Foreground activation prepares its dependency closure concurrently and shares in-flight downloads with background preparation. All selected workload downloads can run concurrently. Native archives are streamed to disk while hashing, verified before extraction, and decompressed without retaining whole archives in memory. Runtime cleanup cancels unfinished transfers and retains completed cache entries. Status exposes artifact preparation separately from service readiness, and explicit preparation reports progress through `onProgress`. Edge Functions are served through the stack-owned Edge Runtime for package consumers. The package runs independently of the CLI and accepts normalized `StackConfig` values without reading `config.toml`. All CLI integration, including `supabase functions serve` and lifecycle commands under `experimental start`, belongs to M5 in separate PRs. Existing CLI Functions behavior is preserved. The deleted `next` CLI was a disposable proving ground and is not part of this PR. Service preparation now lives in the published runtime artifacts: PostgreSQL owns first boot and bundled migrations, service helpers own migration and Pooler tenant provisioning, and Node services expose public launchers shared with their images. The stack supplies instance settings and sequences those commands. Default images use the configured slim-services tags or digests, including the artifacts from [slim-services #299](supabase/slim-services#299) and the BEAM versions republished after [slim-services #302](supabase/slim-services#302). Native downloads are checked against the checksum published with the same release. BEAM launchers own the shared runtime defaults in native and container modes; Vector configuration and Edge Functions bootstrap remain stack-owned. Unix control sockets bind inside owner-private directories. Container mount paths preserve CSV special characters, and default state paths use the user home directory when `HOME` is absent. Obsolete process-compose integration and superseded runtime helpers are removed. Supersedes #6385
) ## TL;DR adds live e2e coverage for `network-restrictions get` and `update`, covering the command family ## whats introduced? - `network-restrictions get`: reads the target project's restrictions and proves the json payload carries `entitlement`, `config` and `status` - `network-restrictions update`: captures the current allowlist, replaces it with documentation ranges, proves the replacement in its own output and through get, then restore s... ## ref: - closes: CLI-2288 - tested here: https://github.com/supabase/cli/actions/runs/33969368307
Bumps the actions-major group with 2 updates: [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) and [linear/linear-release-action](https://github.com/linear/linear-release-action). Updates `docker/setup-qemu-action` from 4.2.0 to 4.3.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/docker/setup-qemu-action/releases">docker/setup-qemu-action's releases</a>.</em></p> <blockquote> <h2>v4.3.0</h2> <ul> <li>Bump <code>@docker/actions-toolkit</code> from 0.92.0 to 0.96.0 in <a href="https://redirect.github.com/docker/setup-qemu-action/pull/336">docker/setup-qemu-action#336</a></li> <li>Bump <code>@sigstore/verify</code> from 3.1.0 to 3.1.1 in <a href="https://redirect.github.com/docker/setup-qemu-action/pull/316">docker/setup-qemu-action#316</a></li> <li>Bump brace-expansion from 1.1.15 to 1.1.18 in <a href="https://redirect.github.com/docker/setup-qemu-action/pull/332">docker/setup-qemu-action#332</a></li> <li>Bump js-yaml from 4.2.0 to 4.3.1 in <a href="https://redirect.github.com/docker/setup-qemu-action/pull/334">docker/setup-qemu-action#334</a></li> <li>Bump postcss from 8.5.10 to 8.5.25 in <a href="https://redirect.github.com/docker/setup-qemu-action/pull/331">docker/setup-qemu-action#331</a></li> <li>Bump sigstore from 4.1.0 to 4.1.1 in <a href="https://redirect.github.com/docker/setup-qemu-action/pull/317">docker/setup-qemu-action#317</a></li> <li>Bump undici from 6.27.0 to 6.28.0 in <a href="https://redirect.github.com/docker/setup-qemu-action/pull/333">docker/setup-qemu-action#333</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/docker/setup-qemu-action/compare/v4.2.0...v4.3.0">https://github.com/docker/setup-qemu-action/compare/v4.2.0...v4.3.0</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/docker/setup-qemu-action/commit/1f40c72289eff860ee54a304f1438e3cff362e0a"><code>1f40c72</code></a> Merge pull request <a href="https://redirect.github.com/docker/setup-qemu-action/issues/336">#336</a> from docker/dependabot/npm_and_yarn/docker/actions-to...</li> <li><a href="https://github.com/docker/setup-qemu-action/commit/932216e29e2417c3aa0bc5aec3c57089030cef2c"><code>932216e</code></a> [dependabot skip] chore: update generated content</li> <li><a href="https://github.com/docker/setup-qemu-action/commit/a39e895360e601ae54e9ac97b8ea3b99e5f40491"><code>a39e895</code></a> build(deps): bump <code>@docker/actions-toolkit</code> from 0.92.0 to 0.96.0</li> <li><a href="https://github.com/docker/setup-qemu-action/commit/a98ae9ffe777adf16ca44873bab9926427b262fa"><code>a98ae9f</code></a> Merge pull request <a href="https://redirect.github.com/docker/setup-qemu-action/issues/333">#333</a> from docker/dependabot/npm_and_yarn/undici-6.28.0</li> <li><a href="https://github.com/docker/setup-qemu-action/commit/8ebc9d118344dda0af3e25d2a7330010dd33e951"><code>8ebc9d1</code></a> [dependabot skip] chore: update generated content</li> <li><a href="https://github.com/docker/setup-qemu-action/commit/c41e3fcbc0d6742101e0310c3b008ac3b16a9529"><code>c41e3fc</code></a> build(deps): bump undici from 6.27.0 to 6.28.0</li> <li><a href="https://github.com/docker/setup-qemu-action/commit/5fc60dfac60f723a3386e73530ff8067f2848f60"><code>5fc60df</code></a> Merge pull request <a href="https://redirect.github.com/docker/setup-qemu-action/issues/332">#332</a> from docker/dependabot/npm_and_yarn/brace-expansion-1...</li> <li><a href="https://github.com/docker/setup-qemu-action/commit/a26e892bb646b50218299a9b391e7a4b0322d96a"><code>a26e892</code></a> Merge pull request <a href="https://redirect.github.com/docker/setup-qemu-action/issues/328">#328</a> from docker/dependabot/github_actions/actions/checkou...</li> <li><a href="https://github.com/docker/setup-qemu-action/commit/aa6d04232374700651c6e7be400e859600041423"><code>aa6d042</code></a> Merge pull request <a href="https://redirect.github.com/docker/setup-qemu-action/issues/324">#324</a> from docker/dependabot/github_actions/actions/setup-n...</li> <li><a href="https://github.com/docker/setup-qemu-action/commit/d381ce5c16de15c000da8929fd1fc6e8fdef19e1"><code>d381ce5</code></a> Merge pull request <a href="https://redirect.github.com/docker/setup-qemu-action/issues/317">#317</a> from docker/dependabot/npm_and_yarn/sigstore-4.1.1</li> <li>Additional commits viewable in <a href="https://github.com/docker/setup-qemu-action/compare/96fe6ef7f33517b61c61be40b68a1882f3264fb8...1f40c72289eff860ee54a304f1438e3cff362e0a">compare view</a></li> </ul> </details> <br /> Updates `linear/linear-release-action` from 0.17.1 to 0.17.2 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/linear/linear-release-action/releases">linear/linear-release-action's releases</a>.</em></p> <blockquote> <h2>v0.17.2</h2> <h2>What's Changed</h2> <ul> <li>Release v0.17.2 by <a href="https://github.com/axelniklasson"><code>@axelniklasson</code></a> in <a href="https://redirect.github.com/linear/linear-release-action/pull/67">linear/linear-release-action#67</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/linear/linear-release-action/compare/v0.17.1...v0.17.2">https://github.com/linear/linear-release-action/compare/v0.17.1...v0.17.2</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/linear/linear-release-action/commit/53ad0f863963e7f8e270fba18426bbb55ef55384"><code>53ad0f8</code></a> Release v0.17.2 (<a href="https://redirect.github.com/linear/linear-release-action/issues/67">#67</a>)</li> <li>See full diff in <a href="https://github.com/linear/linear-release-action/compare/3f31fcf14c110cc53579fcc3575a26d469c413b4...53ad0f863963e7f8e270fba18426bbb55ef55384">compare view</a></li> </ul> </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…stat throws (CLI-2345) (#6518) ## What kind of change does this PR introduce? Bug fix. ## What is the current behavior? `canonicalizeExistingPath` in `apps/cli/src/command-internal/legacy-config-validate.ts` follows an in-root symlink one hop by hand (via `readlinkSync`) when `realpathSync` fails, so a `content_path` containment check can catch a dangling/looping/unsearchable-target symlink escaping the project root. When the symlink's target sits one hop inside a directory that's unsearchable (`EACCES`, e.g. `chmod 000`), the fallback `lstatSync(path, { throwIfNoEntry: false })` call itself throws — `throwIfNoEntry: false` only suppresses `ENOENT`, not `EACCES` — and that throw was unguarded, escaping as a raw filesystem `Error` instead of the polished `LegacyConfigValidateError` ("resolves outside the project root") every other containment-rejection case produces. Not a security regression — the path was still rejected in every tested environment — it was a message-polish gap. Code review while fixing this surfaced the identical bug in `legacyIsExistingFile` (the `"notification"` email-content section's twin resolution path, via `statSync`), which had the same unguarded `throwIfNoEntry: false` gap. Fixes CLI-2345. ## What is the new behavior? - `canonicalizeExistingPath`'s `lstatSync` fallback is now guarded: any non-`ENOENT` throw there returns the path as-is (same fallback already used for a non-symlink entry or too-deep symlink chain), so the caller's containment check still runs and rejects normally. - `legacyIsExistingFile` is guarded the same way: an unstattable dirent is treated as present, so the declared path keeps winning over the legacy `supabase/`-relative fallback and the real cause surfaces instead of a raw fs error or a silent retarget. - Updated the `canonicalizeExistingPath` JSDoc to accurately describe what this guard does and doesn't guarantee (the lexical comparison isn't fully fail-closed on its own; every caller's own read of the resolved file's bytes is the actual backstop). - Tightened the existing EACCES regression test to assert the specific error/message, parametrized the three symlink-containment tests across both `template`/`notification` sections, and added a permission-free `ENAMETOOLONG` regression test so this code path stays covered in environments where `chmod 000` isn't enforced (root, some containers, Windows).
…he slim-services feed (#6521) ## Summary Dependabot's docker updates on `apps/cli-go/pkg/config/templates/Dockerfile` have been landing red — see #6502 (realtime) and #6503 (postgres). Two independent causes, plus the automation the second one leaves behind. **1. A unit test asserted the exact current pins while reading them from the live manifest.** `slim-images.unit.test.ts` had a `maps current docker.io pins onto the published slim tags` case that fed `dockerfileServiceImageRaw(alias)` in and asserted a spelled-out version for `pg`, `supavisor`, `realtime`, and `storage`. Any bump of those four failed the unit suite by construction. The assertions that must track the manifest — which slim repository each alias maps to — already live in the `it.each` above and slice the tag off before comparing, so they stay. Live-tag validation also survives more strongly elsewhere: `start.slim-images.e2e.test.ts` translates the current manifest pins and actually pulls them, so an unpublished translated tag fails CI on the registry rather than on a hand-typed string. The version-bearing block only encoded the per-service tag-prefix scheme, so it is replaced with fixed pins covering the same scheme, plus the uppercase-`V` normalization arm in `slimTagForService` that had no coverage. **2. `sync-stack-service-versions.yml` targeted files that no longer exist.** It ran `pnpm sync:versions` in `packages/stack` and committed `packages/stack/src/ServiceCatalog.ts`. #6440 deleted both the script and that file, so the workflow would have hard-failed on the next dependabot Dockerfile PR. It survived #6502/#6503 only because those were opened about two hours before #6440 merged. **3. The stack's pins now ride the feed that can actually maintain them.** Deleting that workflow leaves `WorkloadCatalog.ts` — `ServiceCatalog.ts`'s replacement — with no automation, so this adds it. The catalog pins each workload to an exact slim-services artifact release: a version **plus its `ghcr.io/supabase/cli` image digest**, per ADR 0017, which makes the artifact release the boundary for service startup defaults. Dependabot owns the Dockerfile and structurally cannot own this table — it resolves registry tags and never produces a `sha256:` digest, which is why repointing the old workflow was not an option. slim-services already sends this repo a `mirror-slim-image` `repository_dispatch` per release carrying `service`/`version`/`digest`, to drive the ECR mirror. `sync-stack-workload-catalog.yml` subscribes to that same dispatch and opens a PR pinning the release. It is deliberately a separate workflow from `mirror-slim-image.yml`: that mirror runs against the sender's 15-minute verification poll, and a catalog PR must never delay it or turn its run red. ## Reviewer notes Only two source values change per release. `artifactFor` derives `releaseTag`, `assetName`, and every download URL from `service` + `version`, and `releases` is derived from `defaultVersion` plus the container image, so rewriting the `native(...)` positional version and image is the whole change. **postgres is the one service carrying two supported release lines** (17.x and 15.x via `additionalReleases`), so the plan picks its target by release line — a 15.x release moves the additional entry and can never overwrite the 17.x default. That is the main correctness risk here and it has a dedicated test. A release on a line the catalog does not carry, a service it does not model, and a re-dispatch of an already-pinned release are all successful no-ops, so the sender's retry path does not open duplicate PRs. The dispatch payload arrives with whatever authority holds the dispatch token, so `sync-workload-catalog.ts` revalidates `service`/`version`/`digest` against the same patterns `mirror-slim-image.yml` uses rather than trusting the workflow. Those patterns are what stop a version or digest breaking out of the TypeScript string literals it writes into. `planCatalogUpdate` is pure and covered by 21 `bun:test` cases in `.github/scripts/`, which `github-scripts-ci.yml` already tests and type-checks. One of them sweeps every service the real catalog models, so a newly modelled workload is covered without editing a fixture list. `WorkloadCatalog.ts` also gains a provenance comment: it and the Dockerfile list overlapping service versions and are meant to diverge, so the next reader needs to know not to "reconcile" them. ## Linked issue No Linear ticket — repository maintenance prompted by the two failing dependabot PRs above. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PWXmTVTiQCwuyjZ8Mfw9NL --------- Co-authored-by: Claude <noreply@anthropic.com>
…#6519) ## Summary The `Codegen` check fetched the live staging spec on every pull request and diffed the result against the committed `pkg/api`. That conflated two questions: whether the pull request left generated code inconsistent, and whether staging had drifted ahead of the repository. The second dominated, so a spec change turned every open pull request touching `apps/cli-go` red at once — none of which the authors caused or could fix — and it made all of those runs depend on staging being reachable. This pins the spec instead: - `apps/cli-go/api/v1-openapi.yaml` is a committed snapshot of the staging spec, and `go generate` reads it instead of `https://api.supabase.green/api/v1-yaml`. The per-PR `Codegen` check is now hermetic: it fails only when `pkg/api` no longer matches the snapshot it was generated from, and it reproduces offline. - The API Sync workflow becomes the sole reader of the live spec. It refreshes the snapshot and regenerates the client together in one pull request, so upstream drift produces that one pull request instead of a failure on every open one. Its diff now shows the upstream API change rather than only generated Go. - Its change detection covers the snapshot as well as `pkg/api`, so an upstream edit that codegen ignores (a description, an example) is committed rather than refetched and discarded on every run. - `api/README.md` is rewritten. It still documented the pre-URL `beta.yaml` flow, and its links to the generated files were broken relative paths. This restores the model `packages/api` already uses, where `pnpm generate` runs only in the sync workflow and per-PR drift is checked against the committed `openapi.json`. ## Drift the snapshot exposed Seeding the snapshot was expected to regenerate `pkg/api` byte-identically. It did not: staging had drifted ahead of the committed client, which is exactly the accumulation the old check could never land. Two changes came in, and they are worth a look: - `StorageConfigResponseOutput.MigrationVersion` is now `nullable.Nullable[string]`. Assigning it to the `string` field `storage.TargetMigration` no longer compiles, so `FromRemoteStorageConfig` unwraps it with the same `Get()` guard `FromRemoteAuthConfig` already uses. Behavior change worth noting: when the platform omits the field, the local value is left untouched rather than overwritten with `""`, consistent with the surrounding intent that unset config should not change platform defaults. - Several `UpdateCustomHostnameResponseOutput` result fields became optional pointers. Nothing outside `pkg/api` consumes that type, so no call sites needed changes. ## Generated-file marking Committing a 468 KB spec snapshot raised the question of generated-file marking, and `.gitattributes` carried no `linguist-*` entries at all, so the repository's roughly 3.5 MB of generated output was skewing GitHub's language statistics and expanding in diffs. All of it is now marked `linguist-generated`: the Go client and spec snapshot, `packages/api/src/generated/`, the docs config schemas, and the lockfiles. `turbo.json`'s `generate` outputs and the `go generate` directives are the source of truth for that list, so only generated files are marked. Hand-written codegen inputs (`pkg/api/*.cfg.yaml`, `api/overlay.yaml`) are untouched, as are large but authored files such as the integration test suites. The attribute is GitHub-only — git, CI, and local diffs behave identically, and the files are collapsed behind a click rather than hidden, so the sync PR's spec diff and lockfile changes remain reviewable. ## Linked issue N/A — CI reliability change, no linked issue. ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/). ## Reviewer notes One open decision: the snapshot's file name. `v1-openapi.yaml` matches the `/api/v1-yaml` endpoint; `beta.yaml` was the name before codegen moved to the live URL, if continuity is preferred. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01TKDPB9bwSx5WM7juDAM7CT --------- Co-authored-by: Claude <noreply@anthropic.com>
## Summary #6465 removed the `next/` shell and #6486 flattened `legacy/` into `src/`, but the two-shell world lived on in the names: every exported symbol in the CLI tree still carried the mandatory `Legacy`/`legacy`/`LEGACY` prefix, 368 files were named `legacy-*.ts`, `apps/cli/AGENTS.md` still told agents the prefix was required, and the harness, build, and release tooling still selected a "shell". This PR removes the concept end to end so `src/` reads as the one CLI it is. ### The rename (`bad664be1`) - ~3,050 identifiers lose the prefix (`LegacyBranchesCreateFlags` → `BranchesCreateFlags`, `legacyRoot` → `rootCommand`, …), together with their `Data.TaggedError` tags, `Effect.fn` span names (`legacy.branches.create` → `branches.create`), and service tags (`supabase/legacy/*` → `supabase/cli/*`). - 368 files are renamed (`legacy-foo.ts` → `foo.ts`); `src/shared/legacy/*` moves into `src/command-internal/`; `tests/helpers/legacy-mocks.ts` becomes `command-mocks.ts` because `mocks.ts` already existed. - Where a CLI-tree service collides with a same-named `src/shared/` service, the CLI-tree one is qualified with `Command` rather than getting a new shell prefix: `CommandSettings` (was `LegacyCliSettings`), `CommandCredentials`, `CommandPlatformApi`. AGENTS.md documents this and marks the pairs as slated to consolidate. Other clash-driven names: `withCommandTelemetry` (vs shared `withCommandInstrumentation`), `AccessTokenRequiredError`, `ProjectRefNotLinkedError`, `GoOutputFormat`. - Wrappers and aliases that existed only to satisfy the prefix rule are deleted instead of renamed (`functions serve` re-exports, `usesSlimRuntime`, the `formatDebugId` alias). - Three variable shadows the rename would have introduced silently (`lang`, `globalFlagValues`, `resolved`) were caught with an oxlint `no-shadow` before/after diff and renamed. Genuine product concepts keep the word: `--legacy-bundle`, legacy API keys and signing keys, the pre-profile keyring account fallback, the pre-consent `telemetry.json` format, the migra "legacy engine" vs the pg-delta "next" engine, and the pg-delta legacy-tree export. ### The rule and the framing (`442bc60b1`) - `apps/cli/AGENTS.md`: the "Mandatory `Legacy`/`legacy` prefix on all exports" section is replaced by a short "Naming" section; the header note now says the prefix and both shell trees are gone; the `next/` dual-write and "legacy-only" guidance is removed. - README, CONTRIBUTING, the lint config comment, `packages/config/docs`, `SIDE_EFFECTS.md` files and ~300 code comments drop "legacy shell"/"legacy command" wording. ### The remaining shell plumbing (`994f75685`) - Compiled binary is `dist/supabase` (was `dist/supabase-legacy`). - `@supabase/cli-test-helpers`: `createHarness(options)` — the `CLITarget`/`CLI_HARNESS_TARGET` axis (`ts-legacy`/`ts-next`) is gone from the harness, `apps/cli-e2e`, `test.yml`, and the `live-e2e.yml` matrix. The harness always uses the profile-file path, which is the one the CLI actually reads. - `runSupabase`/`spawnSupabase` drop the `entrypoint: "legacy"` option (111 call sites). - `scripts/build.ts` drops `--shell`; the `shell` input is removed from `build-cli-artifacts`, `release-shared`, `release`, `release-smoke-test`, and `publish-preview-cli-packages`, and the artifact cache keys drop the shell segment on both the producer and consumer side. - `pnpm cli-release` drops `--legacy|--next`. It was also still compiling `src/<shell>/main.ts`, a path that stopped existing in #6486, so the local release ring works again. - `pnpm dev:legacy` → `pnpm dev`, `pnpm build:legacy` → `pnpm build:binary`. - `docs/platform-command-generation.md` (a `next/`-only feature) is deleted; the `next/`-only rows are dropped from `go-cli-divergences.md`; "`undefined` in `next`"-style comments in `shared/` are reworded to describe library callers. ## Reviewer notes - **User-visible:** `--output-format json` error `code` values are the tagged-error tags, so they lose the `Legacy` prefix (e.g. `LegacyPlatformAuthRequiredError` → `AccessTokenRequiredError`). Span names lose `legacy.` and service tags move, but neither leaves the machine. - The `Command*` qualifier for the three shared/CLI service pairs is the one naming judgment call worth a look; each is a single-token rename if a different name is preferred. - `@supabase/cli-go#lint:check` fails on this branch exactly as it does on `develop` under a current local golangci-lint (gosec G115/G118); no Go source is touched here.
`supabase experimental stack start` creates or resumes a managed stack for the current project and branch, with named-stack and explicit-ID targeting, Docker/native selection, and eager activation or background artifact preparation. Translate project configuration at the CLI boundary and embed the supervisor and native-process dispatch in the compiled binary. The stack package owns lifecycle and persistent state, and resolves PostgreSQL major versions through its release catalog. --------- Co-authored-by: Colum Ferry <cferry09@gmail.com>
…plates with 5 updates (#6533) Bumps the docker-minor group in /apps/cli-go/pkg/config/templates with 5 updates: | Package | From | To | | --- | --- | --- | | supabase/studio | `2026.08.24-sha-8ec45b2` | `2026.09.07-sha-7996410` | | supabase/edge-runtime | `v1.74.3` | `v1.76.2` | | supabase/realtime | `v2.130.0` | `v2.134.12` | | supabase/storage-api | `v1.72.1` | `v1.74.1` | | supabase/logflare | `1.50.6` | `1.50.11` | Updates `supabase/studio` from 2026.08.24-sha-8ec45b2 to 2026.09.07-sha-7996410 Updates `supabase/edge-runtime` from v1.74.3 to v1.76.2 Updates `supabase/realtime` from v2.130.0 to v2.134.12 Updates `supabase/storage-api` from v1.72.1 to v1.74.1 Updates `supabase/logflare` from 1.50.6 to 1.50.11 Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…dates (#6532) Bumps the go-minor group with 2 updates in the /apps/cli-go directory: [golang.org/x/mod](https://github.com/golang/mod) and [golang.org/x/oauth2](https://github.com/golang/oauth2). Bumps the go-minor group with 1 update in the /apps/cli-go/pkg directory: [golang.org/x/mod](https://github.com/golang/mod). Updates `golang.org/x/mod` from 0.40.0 to 0.41.0 <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/golang/mod/commit/d0a27b2d4a48460806692bf5c87fc157c3c65292"><code>d0a27b2</code></a> modfile: fix Cleanup and DropTool documentation</li> <li><a href="https://github.com/golang/mod/commit/d12008c62d74c94d91b58e8bc6c3eb168eda8381"><code>d12008c</code></a> all: upgrade go directive to at least 1.26.0 [generated]</li> <li>See full diff in <a href="https://github.com/golang/mod/compare/v0.40.0...v0.41.0">compare view</a></li> </ul> </details> <br /> Updates `golang.org/x/oauth2` from 0.36.0 to 0.37.0 <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/golang/oauth2/commit/c624b89dadc3221560b7345c090bbe69e90808ee"><code>c624b89</code></a> google: change the snake case endpoint to kebab-case</li> <li><a href="https://github.com/golang/oauth2/commit/09a82f63d4c718720369edfee3c7d0ff953c0b6f"><code>09a82f6</code></a> all: upgrade go directive to at least 1.26.0 [generated]</li> <li>See full diff in <a href="https://github.com/golang/oauth2/compare/v0.36.0...v0.37.0">compare view</a></li> </ul> </details> <br /> Updates `golang.org/x/mod` from 0.40.0 to 0.41.0 <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/golang/mod/commit/d0a27b2d4a48460806692bf5c87fc157c3c65292"><code>d0a27b2</code></a> modfile: fix Cleanup and DropTool documentation</li> <li><a href="https://github.com/golang/mod/commit/d12008c62d74c94d91b58e8bc6c3eb168eda8381"><code>d12008c</code></a> all: upgrade go directive to at least 1.26.0 [generated]</li> <li>See full diff in <a href="https://github.com/golang/mod/compare/v0.40.0...v0.41.0">compare view</a></li> </ul> </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…pps/cli-go/pkg/config/templates (#6534) Bumps supabase/postgres from 17.6.1.167 to 17.6.1.169. [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Port allocation could change an existing automatic assignment when an earlier listener was enabled, or let a fresh candidate collide with an exact or retained private assignment. Validate all retained and exact claims first, then acquire public listeners and temporary private reservations inside one registry transaction. Commit assignments once acquisition succeeds and let scopes release unsuccessful attempts, removing the probe/replan/rollback path. Use a shared, randomized port pool with bounded retries for occupied or inaccessible candidates. Allocate native listener resources separately for each Effect evaluation, avoid duplicate internal API listeners when a public wildcard already covers the address, and preflight only private bindings still requested by the candidate plan. Document the reservation guarantees and add a focused Bun CI matrix for macOS, Linux, and Windows.
## TL;DR fixes `supabase start` and `functions serve` dying since 2.116.0 with ``` failed to copy edge runtime main service into container: destination "supabase_edge_runtime_<id>:/" must be a directory ``` on projects whose functions import local workspace packages through import map directory mappings - the trigger is #6273 moving the bootstrap onto docker create + cp + start: the daemon refuses to resolve the copy target when a file bind is nested inside a read only parent bind - the overlapping binds themselves are much older, the import walker adds a file bind per imported module while import map target enumeration adds the package directory that already contains them, harmless until a cp step landed between create and start so now the mount list is pruned before `docker create`, a bind is dropped only when another bind of the same mode already supplies the same content at the same container path, so the container sees the same files at the same paths and the cp delivery from #6273 stays intact... ## ref: - closes: supabase/supabase#50088 - extends: #6273 --------- Co-authored-by: Colum Ferry <cferry09@gmail.com>
Derive stack identity from the canonical project root, Git branch context, and stack name. Supported parallel-stack use cases: - **A worktree per LLM chat session:** each distinct worktree directory gets a separate stack, including worktrees on the same branch or detached commit. - **Branch-specific stacks in one clone:** switching from `main` to `feat-a` selects a separate stack; switching back to `main` selects its previous stack. - **Multiple Supabase projects in a monorepo:** each project has its own project-root directory and therefore its own stack. - **Named stacks for one project:** different names create separate stacks within the same project and branch context, for both Git and non-Git projects. Repeated calls with the same canonical project root, branch context, and name select the same stack. An omitted name is `default`. Remove the redundant repository and checkout identity fields, common Git directory resolution, and ordinary-folder identity module. Moving a project selects a new stack. The unreleased private state uses the new hash directly without migration or legacy-hash support.
<!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary pnpm/pnpm#14557 is resolved so we no longer need the workaround in `.gitattributes` that i added in #6461 (but I kept it just in case and updated the comment accordingly). this pnpm bump should also speed up dependency resolution/installation.
…el (#6524) <!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary - Gate `pkg.pr.new` preview CLI package publishes behind the `run-preview-packages` label (re-publish on push while labeled; remove label to cancel). - Stop publishing on every ready `develop` PR and remove preview from the `run-ci` suite so large binaries are only uploaded when someone needs a shareable install. - Document the opt-in in `MAINTAINERS.md` and sync related workflow comments. ## Linked issue No linked GitHub issue (maintainer follow-up from Slack). - [x] The linked issue is **open** and carries the `open-for-contribution` label (or I'm a Supabase maintainer). ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`). - [x] Tests added or updated for the change. - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace (or workspace declaring it).
## What kind of change does this PR introduce? CI reliability fix. ## What is the current behavior? AI Review's Codex jobs (`codex-review`, `adjudicate`) intermittently hang and get killed on job timeout, discarding a completed review. Most recently: [run 34323125644](https://github.com/supabase/cli/actions/runs/34323125644) on #6535 died at ~55 minutes against a 45-minute timeout. This is a regression. #6380 deliberately pinned `openai/codex-action` to v1.11 because v1.12 had a confirmed hang bug (openai/codex-action#150). #6484 — a Dependabot `actions-major` group bump bundling 6 unrelated action updates — silently reverted that pin back to v1.12; the workflow's own comments (still saying "pinned to v1.11, NOT v1.12") went stale rather than catching the drift, since nothing diffed them against the actual `uses:` line. Checking upstream today turned up two separate, still-open v1.12 regressions, both matching this workflow's exact config (`safety-strategy: drop-sudo`, `sandbox: read-only`, `output-schema-file`): - openai/codex-action#151 — the v1.12 wrapper waits on the child process's `close` event with inherited stdio; a lingering descendant keeps the step alive forever after Codex has already written its output and finished. - openai/codex-action#160 — v1.12's `drop-sudo` rewrite chmods root-owned `/run` service sockets, breaking `systemd-resolved` on the GitHub-hosted runner itself, which kills the job 52-65 minutes in regardless of the job's own timeout — matching our job's 55-minute death exactly. Neither has a released fix. Both are action-level bugs independent of the pinned Codex CLI version (reproduced across CLI versions 0.147.0-0.150.1 in the upstream threads). This is not a diff-size or token-limit problem: #6535's diff was only ~2200 lines, and v1.11 has cleanly handled 130k-270k-token diffs in under 15 minutes per the upstream reports and our own prior testing. ## What is the new behavior? - Re-pin `openai/codex-action` to v1.11 (`52fe01ec70a42f454c9d2ebd47598f9fd6893d56`) in both Codex jobs — verified it's a safe drop-in, since v1.11's `action.yml` supports every input this workflow uses. - Refresh the stale inline comments to cite the actual issues (#151, #160) instead of just the original #150. - Add `openai/codex-action` to `.github/dependabot.yml`'s `ignore` list (no `update-types` restriction, so it blocks all automated bumps) so a grouped bump can't silently regress this pin again. Any future bump now requires a deliberate PR that checks the upstream changelog/issue tracker first.
….1 in /apps/cli-go in the go-minor group across 1 directory (#6539) Bumps the go-minor group with 1 update in the /apps/cli-go directory: [github.com/posthog/posthog-go](https://github.com/posthog/posthog-go). Updates `github.com/posthog/posthog-go` from 1.24.4 to 1.25.1 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/posthog/posthog-go/releases">github.com/posthog/posthog-go's releases</a>.</em></p> <blockquote> <h2>1.25.1</h2> <h2>Unreleased</h2> <h2>1.25.0</h2> <h2>Unreleased</h2> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/PostHog/posthog-go/blob/main/CHANGELOG.md">github.com/posthog/posthog-go's changelog</a>.</em></p> <blockquote> <h2>1.25.1</h2> <h3>Patch Changes</h3> <ul> <li>c159621: Fix <code>not_regex</code> local flag evaluation erroring on non-string/int property values. The <code>not_regex</code> operator used a manual string/int type switch and returned an error for other types, most notably <code>float64</code>, which is what JSON numbers deserialize to, so it failed on a numeric property value even though <code>regex</code> handled it. <code>not_regex</code> now coerces both sides with <code>valueToString</code>, mirroring <code>regex</code>. An explicit <code>nil</code> property value is represented as <code>null</code>, matching the feature flags evaluation service rather than Go's default <code><nil></code> representation.</li> </ul> <h2>1.25.0</h2> <h3>Minor Changes</h3> <ul> <li>897a0b4: Add the OpenTelemetry bridge for AI observability as an independently installable nested Go module.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/PostHog/posthog-go/commit/a5e539c68b8471a86dd746a4bff64601340f4e9f"><code>a5e539c</code></a> chore: release v1.25.1 [version bump] [skip ci]</li> <li><a href="https://github.com/PostHog/posthog-go/commit/c1596215af2b186a870871e2d169b198851ed150"><code>c159621</code></a> fix: not_regex should handle all value types like regex (<a href="https://redirect.github.com/posthog/posthog-go/issues/305">#305</a>)</li> <li><a href="https://github.com/PostHog/posthog-go/commit/50569874ea80f8f28f3318962668218d34eb9a64"><code>5056987</code></a> chore: release v1.25.0 [version bump] [skip ci]</li> <li><a href="https://github.com/PostHog/posthog-go/commit/897a0b4e5f2e9b49bc58b4ace7d5080502525b18"><code>897a0b4</code></a> feat: add OpenTelemetry bridge for AI observability (<a href="https://redirect.github.com/posthog/posthog-go/issues/306">#306</a>)</li> <li>See full diff in <a href="https://github.com/posthog/posthog-go/compare/v1.24.4...v1.25.1">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
`supabase experimental stack stop` stops the current or named managed stack, or an explicit stack ID, while preserving its identity and data. Selection works without loading project configuration, including when the config file has been removed or changed. Use the stack package’s lifecycle API and report whether a stack was found in both human and structured output. This PR builds on the experimental stack start integration.
## What kind of change does this PR introduce? CI reliability fix (follow-up to #6538). ## What is the current behavior? #6538 re-pinned `openai/codex-action` to v1.11 and added a Dependabot ignore entry scoped to `versions: ["1.12.x"]`, intending to still let Dependabot propose v1.13+ once the upstream hang bugs (openai/codex-action#151, #160) are fixed, while blocking the known-bad v1.12 line specifically. That scoping never actually worked. 9 minutes after #6538 merged, Dependabot opened #6541 proposing the exact v1.12 bump we were trying to block — config propagation wasn't the issue; the `versions` syntax was. The `github-actions` ecosystem's `ignore.versions` strings are parsed as Ruby `Gem::Requirement` (RubyGems comparator syntax: `>= x`, `~> x`, etc.), not npm-style semver ranges. `"1.12.x"` isn't a wildcard in that grammar — it parses as a literal version string with an implicit `=` operator, which never equals the real dependency version (`"1.12"`), so the ignore condition silently never matched anything. Verified directly against the actual parsing logic dependabot-core uses (`Dependabot::GithubActions::Requirement`, a thin wrapper around `Gem::Requirement`): ``` GithubActionsRequirement.new("1.12.x").satisfied_by?(Gem::Version.new("1.12")) # => false (bug) GithubActionsRequirement.new(">= 1.12, < 1.13").satisfied_by?(Gem::Version.new("1.12")) # => true GithubActionsRequirement.new(">= 1.12, < 1.13").satisfied_by?(Gem::Version.new("1.12.5")) # => true GithubActionsRequirement.new(">= 1.12, < 1.13").satisfied_by?(Gem::Version.new("1.11")) # => false GithubActionsRequirement.new(">= 1.12, < 1.13").satisfied_by?(Gem::Version.new("1.13")) # => false ``` ## What is the new behavior? Replace `versions: ["1.12.x"]` with `versions: [">= 1.12, < 1.13"]` — a real Gem::Requirement comparator range, confirmed to correctly match the 1.12 line (including any 1.12.x patch) while excluding v1.11 and v1.13+. #6541 should be closed as superseded once this merges.
…/cli-go/pkg/config/templates in the docker-minor group (#6545) Bumps the docker-minor group in /apps/cli-go/pkg/config/templates with 1 update: supabase/storage-api. Updates `supabase/storage-api` from v1.74.1 to v1.74.3 [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…#6689) ## Summary Native artifact preparation failed on the first non-2xx response, so a single gateway error from the slim-services release host aborted a whole stack start. Today that took `Test` red across three unrelated PRs: `github.com/supabase/slim-services/releases/download/...` answered HTTP 504 for about an hour, on whichever asset was requested, and the failure cascaded from artifact preparation into `Composition start had failures`. Artifact requests now retry transient failures with jittered exponential backoff, and keep deterministic failures single-attempt. Key changes: - `transferFault` classifies retryable failures: HTTP 408, 429, and 5xx, plus `HttpClientError` whose reason is `TransportError` (connect-level) or `DecodeError` (a transfer cut mid-body). `StatusCodeError`, `EncodeError`, `InvalidUrlError`, and `EmptyBodyError` fail on the first attempt. - `PreparationError` carries an optional `status`, so classification reads the response code rather than parsing a message. - Retry policy is `Effect.retry({ schedule, times: TRANSFER_MAX_RETRIES, while })` — 4 retries, so 5 attempts, over a 500ms jittered exponential delay. This matches the mechanism in `apps/cli/src/commands/bootstrap/bootstrap.retry.ts`. - `fetchBytes` and `downloadToFile` retry through `withTransferRetry`, which logs the URL and cause of each retried transfer. - `downloadToFile` retries the whole transfer, so an attempt reopens the sink in truncating mode and replaces any partial download instead of appending to it. Digest comparison stays outside the retry, keeping a checksum mismatch terminal. - The backoff is injectable on `makeSlimServicesSource` and `slimServicesChecksum`, so retry coverage runs without waiting on real delays. The attempt cap is not injectable. ## Linked issue None; this came out of a CI incident rather than a filed issue. ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/). - [x] Tests added for the change: checksum recovery from a 504, archive recovery from a transfer cut after partial bytes, exactly five attempts against a persistent 504, and a single attempt on 404. - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace. https://claude.ai/code/session_019zn4vRJ2rkx5UXwNS1ndnj --------- Co-authored-by: Claude <noreply@anthropic.com>
) ## TL;DR - **A failed lazy wake was invisible.** It surfaced only as a `502` or a dead socket, with the cause discarded and `error=undefined` in `stack status`. The proxy now logs the route and cause, and the failure reaches the service observation. - **Ordinary client disconnects stay quiet.** A client that goes away is its own typed error, not a proxy failure, so normal traffic adds no error logs. - **`stack port tests (windows-latest)` could not allocate a port.** The auto scan walked contiguously and died inside a Windows reserved block. It now walks `20000..32767` with stride `257` per [ADR 0017](docs/adr/0017-simplified-managed-stack-architecture.md), so a reserved block up to 12511 of the 12768 ports is escaped within the bounded attempts. - **Port allocation is reproducible.** The scan start derives from the stack rather than a random draw, so a stack reassigns the same port and a future failure repeats instead of depending on the draw. ## Details Two independent stack failures, both surfaced while investigating the 2026-09-21 `Test` breakage. ### A failed lazy wake was unobservable A wake that failed reached clients only as a dead connection. `HttpProxy` discarded the cause in both arms — the request path answered `502` and the upgrade path destroyed the socket — and `Service.startAt` runs `definition.prepare` (where native artifact preparation happens) before it touches the observation, so a preparation failure left `error` undefined. Every wake failure was therefore indistinguishable from a flake. Both proxy arms now log the route id and the underlying cause before responding, and a failed wake preparation reaches the service observation, so `stack status` and the reopened-stack diagnostics name the cause instead of printing `error=undefined`. The two halves cover different topologies. A detached owner is spawned with `stdout`/`stderr` ignored, so the proxy log lines land only where the runtime shares the caller's process; the recorded observation is what names the cause through `stack status` and the e2e diagnostics in the detached topology. Retaining a detached owner's output is a separate pre-existing gap. Client exits stay quiet, and are told apart from upstream faults by type rather than by message: a client that disconnects while the target is waking, goes away mid-response, or resets an established upgrade fails with `HttpProxyDisconnected`, while upstream faults keep failing with `HttpProxyError` and log. Both paths settle before destroying their sockets, because destroying a partially received upstream response emits `aborted` synchronously and would otherwise resettle a disconnect as a proxy failure. A preparation failure is recorded only while the service is still the stopped, registered attempt that prepared it, so a concurrent start that already relaunched keeps its own state. ### `stack port tests (windows-latest)` could not allocate an auto port The auto scan walked contiguously from a random start over `20000..49999` and gave up after 64 consecutive bind failures. Windows publishes reserved TCP ranges as contiguous blocks commonly wider than 64 ports, so a start landing inside one failed with `No public port is available` while tens of thousands of ports were free. That range also overlapped the Linux default ephemeral range. The scan follows ADR 0017 again: `20000..32767` with stride `257`, which is co-prime with the span and so traverses every candidate once across a full scan. Within the ADR's 64-attempt bound, a contiguous reserved block up to 12511 of the 12768 ports is always escaped, worst case 49 failures, verified over every start and block offset. Wider blocks can still exhaust the bound — that limit is the ADR's, and the stride does not remove it — but they are far beyond the width of a published excluded range. The one deliberate divergence from the ADR is the scan start, which derives from the stack's project root, id, and listener key rather than a random draw. Allocation is reproducible: a stack reassigns the same port across runs, separate checkouts stay apart, and a future failure repeats instead of depending on the draw. The ADR records this. The exhausted error also carries the last bind failure, so a reserved range (`EACCES`) reads differently from an occupied port (`EADDRINUSE`) from the log alone. ## Changes - `HttpProxy.ts`: log route request and upgrade failures with the route id and cause; give client-originated disconnects a distinct tagged error; settle before destroying sockets - `Ports.ts`: walk the documented range with a co-prime stride from a derived start; attach the last bind failure to the exhausted error. No longer needs the platform crypto service, so `HostProcess` stops carrying that requirement - `Service.ts`: record a failed wake preparation on the observation, guarded against a concurrent relaunch - `docs/adr/0017`: record the derived scan start `Service.ts` here is the wake path only; `restart` is unchanged because its caller already receives the error. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01LcUaThuQfDKPwi9mCE9XeD --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Adds tool-independent review checkpoints with bounded rounds and evidence-based consensus. Strengthens existing guidance to design from consumer requirements, justify complexity with current needs, exercise shared contracts across implementations, and verify contract-required cleanup. Effect coding practices remain owned by the repository-local skill.
…6690) ## Summary Infrastructure for the public-read S3 mirror of slim native artifacts, in the dedicated `cli-artifacts-prod` AWS account (created in `supabase/aws-org-root`). The CLI will fall back to this host where registry blob CDNs and GitHub release assets are blocked, for example in agent sandboxes that allow `*.amazonaws.com`. This PR is infrastructure only; the upload job in the mirror workflow and the CLI-side candidate follow in separate PRs. `infra/cli-artifacts/template.yaml` (CloudFormation): - Bucket `supabase-cli-artifacts`: anonymous `GetObject` through the bucket policy, TLS required, no `ListBucket`, ACL-based public access blocked, SSE-S3, versioning with 30-day noncurrent expiry and abort of stale multipart uploads. Retained on stack delete or replace. - Role `slim-artifacts-publisher`: trusts the account's GitHub OIDC provider for exactly `repo:supabase/cli:ref:refs/heads/develop` and can do nothing but `s3:PutObject` and `s3:AbortMultipartUpload` on the bucket's objects. `.github/workflows/cli-artifacts-infra.yml`: runs `cfn-lint` on pull requests that touch this directory or the workflow, and deploys the stack on pushes to `develop` with the account's `github-deploy` role, passing the bucket name and trusted subject explicitly. Pull requests never touch AWS, because only `develop` can assume that role. The deploy job is skipped until the `CLI_ARTIFACTS_AWS_ACCOUNT_ID` repository variable exists, clears a stack left in `ROLLBACK_COMPLETE` by a failed first create, and prints failed stack events on error. The workflow file is placed under CLI maintainer ownership in CODEOWNERS. Object layout, kept identical to the GitHub release asset names so checksum files match without rewriting: ``` https://supabase-cli-artifacts.s3.us-east-1.amazonaws.com/<service>/<version>/<service>-<version>-<target>.tar.zst https://supabase-cli-artifacts.s3.us-east-1.amazonaws.com/<service>/<version>/<service>-<version>-<target>.manifest.json https://supabase-cli-artifacts.s3.us-east-1.amazonaws.com/<service>/<version>/<service>-<version>-<target>.SHA256SUMS ``` ## Linked issue Tracked in Linear (CLI-2451); no GitHub issue. - [x] The linked issue is **open** and carries the `open-for-contribution` label (or I'm a Supabase maintainer). ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`). - [ ] Tests added or updated for the change. Not applicable: CloudFormation template and workflow only; the template is linted by `cfn-lint` in the new workflow. - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace (or workspace declaring it). No TypeScript workspace is touched. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PeXSyQtKtGuwrdNW7uVKom --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…6661) ## Summary - Extract GHCR → ECR Public slim-image mirroring into bun scripts (`validate`, digest checks, repo create, `copy-image`, `copy-natives`). - Copy `:version-native-<target>` OCI archives best-effort after the digest-preserving image copy; catalog sync still consumes only image `service` / `version` / `digest`. - ADR 0026 records the publish path. CLI/stack fail-through is a follow-up PR. Companion: supabase/slim-services#308
## Summary Second step of the public S3 mirror for slim native artifacts (the bucket and publisher role landed in #6690). This adds an `upload-natives-s3` job to `mirror-slim-image.yml` so every slim-services dispatch also copies the native triplets to the bucket, for sandboxes that allow `*.amazonaws.com` but block registry blob CDNs and unattached GitHub release assets. How the job works: - Runs only on `repository_dispatch`, only while `CLI_ARTIFACTS_AWS_ACCOUNT_ID` is set, and only after the `mirror` job succeeded (`success()`), so nothing reaches the public bucket from a dispatch whose image digest check failed. It is `continue-on-error: true`, so like the native ECR copy it never affects the image digest the sender polls; a release whose mirror failed for ECR-side reasons is covered by the sender's backfill re-dispatch. - Re-validates the payload, then `fetch-natives` resolves each native tag on GHCR and requires it to match the dispatched digest (the same check the ECR copy makes), pulls the triplet by that digest (`regctl manifest get` + `regctl blob get`), writes the files under their release asset names, checks the archive against its own `SHA256SUMS`, and checks the manifest's `service` / `version` / `target` against the dispatch fields. A target that fails any check, repeats an earlier target, or ships malformed manifest JSON is dropped with a warning. - Assumes `slim-artifacts-publisher` (PutObject and AbortMultipartUpload on the bucket only) with a session name that carries the workflow run ID, then `upload-natives-s3` copies archive, manifest, and sums in that order with plain `aws s3 cp` to `s3://supabase-cli-artifacts/<service>/<version>/`. No `sync`, since the role cannot list. - Verifies every uploaded object is anonymously readable and that the bucket root still returns 403. Both commands live in `.github/scripts/mirror-slim-image.ts` next to the existing mirror commands, with the triplet parsing and naming helpers in `slim-mirror-payload.ts`, so the flow is replayable locally and covered by the `bun:test` suite. ## Linked issue Tracked in Linear (CLI-2451); no GitHub issue. - [x] The linked issue is **open** and carries the `open-for-contribution` label (or I'm a Supabase maintainer). ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`). - [x] Tests added or updated for the change. - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace (or workspace declaring it). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PeXSyQtKtGuwrdNW7uVKom --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…nt (CLI-2459) (#6693) ## TL;DR brings `supabase functions` delete, list and new under the effect lint ## whats introduced? effect lint applied to `functions` delete, list and new: - four allow list entries in `.oxlintrc.effect.json`, the family root plus the three subcommands - `new` yields its two tagged errors directly instead of wrapping them in `Effect.fail` - `list` timestamps format through `DateTime` while out-of-range millis still render `NaN-NaN-NaN NaN:NaN:NaN` as before, pinned by a new unit test - integration tests move onto the `FileSystem`/`Path` services, the env case runs through `withEnvVar`, cause assertions use `Cause.pretty` - live tests run through the effect native `cliEffect` fixture ## ref: - related: CLI-2459
…effect lint (CLI-2459) (#6694) ## TL;DR brings `supabase functions deploy` and the `serve` handler under the effect lint ## whats introduced? effect lint applied to `functions` deploy and the serve handler: - two allow list entries in `.oxlintrc.effect.json`, `deploy` plus `serve.handler.ts`, with `deploy.integration.test.ts` re-excluded for the next slice - `deploy` and `serve` handlers join paths through the `Path` service instead of `node:path` - e2e tests run through the effect native `runSupabaseEffect` harness with `withTempHome` and the `FileSystem` service - live tests run through the effect native `cliEffect` fixture ## ref: - related: CLI-2459
… lint (CLI-2459) (#6696) ## TL;DR brings the `supabase functions deploy` integration suite under the effect lint ## whats introduced? effect lint applied to the `functions deploy` integration tests: - drops the bare `deploy.integration.test.ts` re-exclusion from `.oxlintrc.effect.json`, so the whole `deploy` directory is covered - fixture writes and temp cleanup run on the `FileSystem`/`Path` services instead of `node:fs` - env cases run through `withEnvVar` instead of setting and restoring `process.env` by hand - the `deno.json` fixture is a string literal instead of `JSON.stringify` ## ref: - related: CLI-2459
…6698) ## TL;DR brings the rest of `supabase functions serve` under the effect lint ## whats introduced? effect lint applied to the whole `functions serve` directory: - swaps the `serve.handler.ts` entry in `.oxlintrc.effect.json` for `serve/**`, since the command, errors, stack handler and their unit, stack integration and e2e tests already pass - the integration suite's fixture reads and writes run on the `FileSystem`/`Path` services instead of `node:fs` - `waitFor` polls on `Clock` and fails with a tagged `WaitForTimeoutError` - env cases run through `withEnvVar` instead of setting and restoring `process.env` by hand - JSON fixtures are literals instead of `JSON.stringify` - the container functions config and JWKS parse through schemas instead of `JSON.parse` ## ref: - related: CLI-2459
Adds the five `/v2/projects/{ref}/notebooks` routes — list, get, create,
update, delete — to the generated Management API client, so the notebook
commands later in this stack have a typed client to drive.
Pure codegen. The routes are live on `api.supabase.com`, so `generate`
picks them up from the published v2 spec; no override block is involved.
## How to try it
```sh
pnpm --filter @supabase/api run generate
git diff --exit-code -- packages/api/src/generated # regeneration is reproducible
```
## Notes
- The deployed spec requires `row_limit` on database cells and
`time_range` on log cells in notebook responses.
- Cell schemas are closed: a key the spec does not declare is dropped
rather than passed through.
- `page` / `filter` on these operations are `style: deepObject`, which
the client does not serialize correctly yet. Fixed in the next PR in
this stack.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Use the legacy local-development JWT secret and PostgreSQL encryption root key as defaults owned by `@supabase/stack`. The Effect API, Promise API, and experimental CLI use the same values when configuration is omitted; explicit overrides remain supported. Apply these defaults consistently during database creation, composition, and restart, and supply the root key through a stack-owned file for native and container runtimes. This PR is limited to development defaults; new-stack snapshot reuse is deferred.
…#6713) ## TL;DR brings `supabase functions download`, the last uncovered subcommand, under the effect lint ## whats introduced? effect lint applied to `download`, so the whole `functions` family is covered now: - the six `functions` allow list entries in `.oxlintrc.effect.json` collapse into one `!apps/cli/src/commands/functions/**`, which adds exactly the five `download` files - the handler joins paths through the `Path` service instead of `node:path` - integration and live tests move onto the `FileSystem`/`Path` services - env cases run through `withEnvVar` instead of setting and restoring `process.env` by hand, and the ambient env assertion reads through `Config` over a `ConfigProvider.fromEnv` - the project id fixture is a string literal instead of `JSON.stringify` - e2e tests run through the effect native `runSupabaseEffect` harness with `withTempHome`, live tests through the `cliEffect` fixture ## ref: - closes: CLI-2459
…I-2471) (#6704) ## TL;DR stops `projects create` resending a POST after a dropped connection, which surfaced "already exists" for a project the server had just created. ## whats broken? transport errors (a connection reset or the 60s timeout) were retried for any method while the 5xx retry was already gated on idempotency when the server had already accepted the first `projects create` POST, the resend hit 409 and the new ref was never printed ## now fixed by: gating transport error retries in the `@supabase/api` client on the same idempotency check as the 5xx path, so GET, PUT, DELETE and HEAD still retry while POST and PATCH thru the client are sent once... ## ref: - closes: #6699 - missed in: #5392
## TL;DR fixes `db reset` stalling on a seed with a large `DO $$` block or `/* */` comment. ## prob the statement splitter built each statement one character at a time, and on every character inside a `$$` body or block comment it sliced the tail of that string. in bun each slice copies the whole statement so far so splitting grew quadratically and a 1 MB `DO $$` block took about 15 seconds. seeds, migrations and `db push` all go through this splitter... ## sol tracking start and end offsets and slicing the original input instead, so the split stays linear and the same 1 MB block takes about 40 ms. the split output is unchanged.... ## ref: - closes: #6686 - introduced in: #5715
…#6717) ## Summary In `mirror-slim-image.yml`, `upload-natives-s3` needed the `mirror` job to succeed. The ECR Public `cli/*` repositories don't exist yet, so every dispatch fails at "Ensure ECR Public repository exists" and no native ever reaches the S3 bucket. The S3 job now runs alongside the ECR copy. It checks the source image digest on GHCR itself, so nothing reaches the bucket from a dispatch whose claimed image digest doesn't match. The ECR job is unchanged. This is split out of #6716 so the S3 mirror can start filling before the CLI fallback lands. Once this merges, #6716 carries the same change with no remaining diff. ## Linked issue None; maintainer change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_016ctyhVP3n3xNy7YRtGYp4p --- _Generated by [Claude Code](https://claude.ai/code/session_016ctyhVP3n3xNy7YRtGYp4p)_ Co-authored-by: Claude <noreply@anthropic.com>
Object-valued query parameters in the v2 spec are `style: deepObject`,
which puts one `param[key]=value` pair on the wire per entry. The client
serialized them as a JSON blob, so a caller passing `page: { size: 100,
after: cursor }` reached the server with no page size and no cursor — a
paginated walk silently returned the first default-sized page forever,
with no error to notice.
`buildRequest` now expands every object-valued query parameter into its
own `param[key]=value` pairs. Arrays keep the repeated-key form
`normalizeUrlValue` already handles, and entries whose value is
`undefined` are dropped rather than sent empty.
## How to try it
```sh
pnpm --filter @supabase/api run test:unit
```
The added cases in `src/internal/client.unit.test.ts` cover expansion,
array handling, and dropped entries.
## Notes
- The expansion applies to all object-valued query parameters rather
than a per-parameter style recorded in the contract, because every
object-valued query parameter in the spec is `deepObject`. If that stops
being true, the contract needs to carry the style and this needs to read
it.
- Also unblocks `page` / `filter` on `v2-list-organization-members`,
`v2-list-organization-projects`, and
`v2-list-organization-github-connections`, which the README documented
as unusable. The README is updated accordingly.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…g stream (#6615) ## TL;DR An edge runtime container that gets killed during `supabase functions serve` — most often by the out-of-memory killer — is retried until the re-attach cap gives up, and then reported as a lost log stream against a container the message claims is still running. This reports the kill instead, and separates a memory-limit kill from one the CLI cannot attribute. Refs [CLI-2427](https://linear.app/supabase/issue/CLI-2427) — *`functions serve` misreports a killed edge runtime container as a lost log stream (exit 137)*. This is the `137` gap [#6594](#6594) left open. ## What was wrong **The retry can never succeed.** `streamContainerLogs` treats container exit `137` as retriable, but the container is created with no `--restart` policy, so once it is killed it stays dead. `docker logs -f` is respawned, exits, the container is inspected, `137` comes back. **The resulting message says the opposite of what happened.** After the cap the command fails with `lost the Edge Runtime log stream 5 times; container … is still running`. The container is not running — that is the one fact the preceding `docker container inspect` established. **The classification sends the user the wrong way.** `EdgeRuntimeLogStreamLostError` declares `external_service` / `network` with a "rerun with `--debug`" remediation. An out-of-memory kill is not a network problem, and that remediation leads nowhere. The retry also contradicts both of its neighbours: `apps/cli-go/internal/utils/docker.go` maps `137` to `ErrContainerKilled` with no retry, and `db diff` treats `137` as a genuine failure. ## What changed `137` falls through to `EdgeRuntimeContainerCrashedError`, which now carries `State.OOMKilled` from the `docker container inspect` the code already makes. That call uses `--format "{{json .State}}"`, so this is one more field read in `parseContainerState` — no format string changes. | Container state | `error_kind` / `error_category` | Suggestion | | --- | --- | --- | | `137`, `OOMKilled: true` | `user_actionable` / `resource_limit` | raise the container's memory limit, or free up memory on the host | | `137`, `OOMKilled: false`, container still present | `unknown` / `unknown` | none | | `137`, `OOMKilled: false`, container gone on re-inspect | unchanged — the session ends successfully | — | | `129`/`130`/`131`/`143` | unchanged — the session ends successfully | — | | any other non-zero | unchanged — `internal_bug` / `runtime_crash` | — | `resource_limit` is a new `user_actionable` category. Both failing `137` rows get their own fingerprint suffix, so they stay separable from each other and from the untagged bulk of their categories. A non-OOM `137` gets one re-inspect before failing: `supabase stop` force-kills a runtime that ignores `SIGTERM` and prunes it right after, and that prune racing the CLI's own inspect is what the deleted retry backed into fixing by accident. The re-inspect makes the fix deliberate instead — still failing fast for a kill from outside that leaves the container in place. ## Two calls worth reviewing **An out-of-memory kill is not `internal_bug` / `runtime_crash`.** It is Docker's memory allocation or the user's own function, and the user can act on it. Filing it against the internal-bug counter would be wrong in the direction this work exists to correct. **A non-OOM `137` is `unknown`, not `user_cancelled`.** Docker sets `OOMKilled` reliably only for container-limit OOMs; a host or VM out-of-memory kill on macOS lands here with `OOMKilled: false`. Calling that "the user cancelled" asserts something we do not know. `unknown` with a named fingerprint keeps it separable so it can be reclassified once there is data on which cause dominates — at the cost of knowingly adding to the `unknown` bucket. ## Behaviour change to be aware of A container killed for a reason the CLI cannot attribute still ends the session successfully if a supervisor (e.g. `supabase stop`) prunes it before the CLI's one re-inspect runs — that is unchanged. Otherwise, a killed container now fails after that single re-inspect rather than after five re-attaches, and fails with a different tagged error than before. A `functions serve &` CI step relying on the old re-attach window to survive a kill will now fail sooner, at the kill. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Colum Ferry <cferry09@gmail.com>
…errors (#6714) ## CLI-2476: `functions serve` skips OOM classification when the `docker logs` stream itself errors `streamContainerLogs` ends in one of two places depending on how `docker logs -f` itself exited. When it exits `0`, the follow-up inspect's `State.OOMKilled` (added in #6615 / CLI-2427) classifies a memory-limit kill as `user_actionable` / `resource_limit` with a remediation. When `docker logs -f` itself errors, the same follow-up inspect runs and produces the same `oomKilled` value — but `DockerLogsStreamError` had no field to carry it, so the kill fell into `unknown` with no suggestion. This gives `DockerLogsStreamError` an `oomKilled` field, sourced from the same inspect that already produces `daemonDown`, and branches its actionability/`suggestion` getters OOM-first, mirroring `EdgeRuntimeContainerCrashedError`. **Stacks on #6615** (base branch `fix/serve-container-killed`) — this diff is additive on top of that PR and should be reviewed/merged after it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Colum Ferry <cferry09@gmail.com>
## Summary Points the AI review pipeline's Codex side at `gpt-6-sol`, which shipped on 2026-09-22 and supersedes `gpt-5.6-sol` for complex coding and agentic work. It is also cheaper — $2/$10 per million input/output tokens against 5.6-sol's $4/$20 — with a 1.05M context window, so both the independent-review and adjudication passes get more diff headroom per run at lower cost. The model only entered the Codex CLI's model catalog in **0.156.1** (a hotfix on 0.156.0, released 2026-09-23), so the `codex-version` input moves with it. Three things worth stating explicitly, since the pinning here is deliberate: - **The action pin does not move.** `openai/codex-action` stays on the v1.11 commit: openai/codex-action#151 (descendant process keeps the step alive) and openai/codex-action#160 (drop-sudo chmods `/run` sockets) are both still open, and `codex-version` is an independent input to the action, so the CLI can be bumped without touching the action SHA or the `dependabot.yml` ignore entry. - **The `codex exec` flag surface is unchanged between 0.150.1 and 0.156.1.** `codex-rs/exec/src/cli.rs` is identical across the two tags, so everything the pinned action passes — `--skip-git-repo-check`, `--cd`, `--output-last-message`, `--output-schema`, `--model`, `--config model_reasoning_effort=…`, `--sandbox` — still parses. - **0.156's new background daemon is TUI-scoped.** `--no-daemon` and the daemon startup path live under `codex-rs/tui/` and `codex-rs/cli/src/main.rs` only, so `codex exec` will not spawn one and this cannot reintroduce the lingering-descendant hang class that forced the v1.11 downgrade. `effort: high` is unchanged and still valid; `gpt-6-sol` additionally supports `xhigh` and `max`, which we can revisit separately if review depth turns out to matter more than runtime. It is a six-minor jump on the CLI against a release that is hours old, so this wants a `workflow_dispatch` run against a real PR before it is trusted on the automatic path. ## Linked issue No linked issue — maintainer change. ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`). - [ ] Tests added or updated for the change. — n/a, workflow configuration only. The `gpt-5.6-sol` strings in `post-review.test.ts` are fixture inputs to the footer builder, not assertions about the live model (they already pair it with `claude-fable-5`), so they are left alone. - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace (or workspace declaring it). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…ts (#6700) The stack shadow cache currently exports and restores tar archives, adding archive creation, extraction, and host/container transfers to cache reuse. Replace that boundary with managed, keyed database snapshots: ```ts await database.saveSnapshot(key); const restored = await database.restoreSnapshot(key); // false on a cache miss ``` Remove `exportSnapshot` and the path-based restore contract, and migrate the CLI baseline cache to the new API. Docker keeps database data and snapshots in separate namespaces within a managed volume, using a reusable helper and filesystem cloning when available. Native snapshots use directory cloning with ordinary-copy fallback; Windows uses ordinary copies. Podman, older Docker engines, and existing host-backed data retain the host-backed path. Snapshots require stopped instances with wake disabled; restore rejects nonempty targets. Managed storage owns compatibility checks, atomic publication, replacement, locking, and retention of three entries by last use. The CLI rebuilds unusable cached baselines. Snapshots survive source-instance destruction; Docker reuse requires the same daemon, state root, and cache root. Cached helper images are resolved with image inspection to avoid unnecessary pulls for digest references. ## Cache rotation and lifetime Each cache bucket retains at most three published snapshots after a successful save: the newly saved entry and the two most recently used other entries. Successful saves and restores update the entry's last-used timestamp; saving evicts older entries under the same lock used by save and restore. Interrupted cache publication files are cleaned up under that lock. For a typical developer setup with one Supabase home, one Docker daemon, and the default cache location, this means **three Docker snapshots total, shared across projects—not three per stack**. The Docker volume is scoped to the state root and daemon; its cache namespace is derived from the canonical cache root. Native and host-backed caches have their own buckets, so the limit is per bucket rather than host-wide, and limits entry count rather than bytes. Destroying a stack removes its database instance data but retains the shared snapshot cache for subsequent reuse. Docker also retains the managed volume. Repeated stack creation/destruction does not add an unbounded number of snapshots to the same bucket; reclaiming abandoned buckets or whole volumes is outside this change. ## Public API benchmarks: cloning and copying Milliseconds, median of three measured repetitions after one warmup. Combined is the median of each repetition's save + restore, rather than the sum of the two independent medians. | Runtime / filesystem | Mechanism | Dataset | Save | Restore | Combined | Start + ready, separately | |---|---|---|---:|---:|---:|---:| | Docker on macOS / Linux VM Btrfs | Clone | Small | 106 | 370 | **471** | 395 | | Docker on macOS / Linux VM Btrfs | Clone | Large | 167 | 392 | **551** | 524 | | Docker on Linux / XFS | Clone | Small | 239 | 400 | **643** | 749 | | Docker on Linux / XFS | Clone | Large | 238 | 410 | **644** | 450 | | Docker on Linux / ext4 | Ordinary copy | Small | 226 | 428 | **653** | 451 | | Docker on Linux / ext4 | Ordinary copy | Large | 583 | 1,336 | **1,909** | 1,279 | | Native macOS / APFS | Clone | Small | 446 | 468 | **952** | 581 | | Native macOS / APFS | Clone | Large | 577 | 496 | **1,142** | 581 | These use real PostgreSQL 17 data: the small dataset has 96 rows; the large dataset has 32,768 rows containing 256 MiB of payload. The physical native trees are approximately 46.8 MiB and 428.8 MiB. Every measured restore starts PostgreSQL and verifies row counts and a content checksum, outside the save/restore timing. Artifacts and images are already present. The source is stopped with its helper warm; each restore uses a fresh target component, including helper creation on Docker. Startup/readiness is shown separately; verification queries, stop, destroy, and initial source setup are excluded from the combined result. Filesystem caches are warm. The macOS large-data run was repeated unchanged after one SQL transport failure; the table uses the complete, verified rerun. The macOS measurements are local; Linux measurements use CI runners. XFS and the local Docker Btrfs volume support forced reflinks; ext4 rejects them and exercises copying. Different machines and filesystems prevent interpreting these as controlled operating-system comparisons. [Linux Docker benchmark run and artifacts](https://github.com/supabase/cli/actions/runs/35660747889) ## Ordinary-copy fallback by platform Milliseconds, median of five measured repetitions after one warmup. These call the unchanged native snapshot storage backend directly, including compatibility validation, locking, staging, publication, and retention. They exclude public API/RPC overhead and PostgreSQL startup, so they are a separate benchmark from the table above. | Platform / filesystem | Dataset | Save | Restore | Combined | Combined min–max | |---|---|---:|---:|---:|---:| | Windows / NTFS | Small | 1,023 | 921 | **1,938** | 1,855–2,211 | | Windows / NTFS | Large | 1,172 | 1,027 | **2,186** | 2,181–2,208 | | macOS / HFS+ disk image | Small | 576 | 496 | **1,076** | 979–1,479 | | macOS / HFS+ disk image | Large | 1,360 | 1,677 | **3,037** | 2,301–3,556 | | Linux glibc / ext4 | Small | 366 | 352 | **698** | 685–728 | | Linux glibc / ext4 | Large | 486 | 458 | **944** | 928–965 | | Linux musl / ext4 | Small | 357 | 343 | **696** | 687–706 | | Linux musl / ext4 | Large | 485 | 463 | **954** | 862–964 | The fixtures reproduce the real PostgreSQL file layouts with deterministic synthetic bytes: **46.8 MiB / 1,317 files** and **428.8 MiB / 1,326 files**, with 28 directories each. No original database contents are copied. Full file hashes and source/cache/restore write isolation are checked outside timing; no PostgreSQL process runs in this benchmark. macOS uses HFS+ because Bun can automatically clone large files on APFS even without a clone flag. Forced-clone probes return `ENOTSUP` on HFS+ and Linux ext4. Windows uses the production ordinary-copy path on NTFS. These are warm-cache, non-fsync measurements on Bun 1.4.1. The macOS runner uses a virtual Apple M1, Windows an AMD EPYC 7763, and both Linux variants Intel Xeon Platinum 8573C runners; differences are not attributable to the OS or libc alone. Windows results establish storage-backend behavior, not availability of a native Windows PostgreSQL artifact. [Cross-platform ordinary-copy benchmark run and artifacts](https://github.com/supabase/cli/actions/runs/35690660783) --------- Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com>
Adds a `[compute.<name>] exclude` list so a compute's build context can leave out secrets and generated trees instead of uploading them for the platform to ignore, and gives each runtime scaffolded by `compute new` a sensible default list. - Add an `exclude: string[]` field to the compute entry schema in `packages/config`. The schema checks only that the key holds a list of strings; pattern syntax is validated by `push`, which can then refuse a single bad pattern by name instead of failing the whole config load. - Teach `push` to compile the recorded patterns with `.gitignore` semantics (name-anywhere, `/`-anchoring, trailing-`/` for directories, `**` spanning, glob syntax per segment) and skip matched paths — including excluded symlinks, checked before the existing escaping-link validation — while pruning excluded directories entirely rather than descending into them. - Refuse re-inclusion (`!...`) and malformed/empty patterns up front, before any packaging or upload, and report the packaged line's excluded count; a source excluded down to nothing now fails naming the offending patterns instead of reporting an empty directory. - Let a runtime declare default `exclude` patterns via `COMPUTE_RUNTIME_EXCLUSIONS`, written into `config.toml` by `compute new` (extending the TOML section writer to render string-list values) rather than applied invisibly at push time, so the list stays visible and editable. - Populate each runtime's actual default list: every runtime excludes env files and VCS metadata, `node` also drops `node_modules/` and `*.log`, `deno` drops `*.log`, and `dockerfile` adds nothing further since the user's own `Dockerfile` decides what it copies.
Adds the `supabase notebooks` command family and its first subcommand, `notebooks pull`. Notebooks live in `supabase/notebooks/<name>.json`, one committed JSON file each, alongside `supabase/functions/` and `supabase/compute/`. ```sh supabase notebooks pull # write notebooks missing locally supabase notebooks pull <notebook-id> # replace one local copy ``` ## How to try it ```sh supabase link --project-ref <ref> supabase notebooks pull ``` The notebook id for the single-notebook form is the UUID in the notebook's dashboard URL. Notebooks are behind a dashboard feature preview; switching it on lets you create and edit them in the dashboard, which is the quickest way to set up states worth pulling — several notebooks at once, charts and log cells, a notebook renamed or deleted after a pull, or two notebooks sharing a name. ## Notes - **Identity is the file name, not the uuid.** A checkout is shared through git, where a uuid in a filename is unreadable. Names the filesystem cannot hold are reported and skipped rather than sanitised, since a sanitised name would push back later as a rename of somebody's notebook. Portable-filename aliases (`Sales` vs `sales`, NFC vs NFD) are refused before anything is written. - **Duplicate names are refused, not guessed at.** Worth knowing for review: the dashboard names new notebooks "New Notebook", so a project with a few unrenamed ones fails every command that lists notebooks until they are renamed. - **Local files naming no project notebook** get three answers — leave them, create them in the project, delete them locally — because such a file is either one somebody deleted in the dashboard or one somebody added locally, and the lists do not say which. An unattended run (non-TTY, machine output format, cancelled prompt) reports the divergence and changes nothing. - Files are published through a temp file plus a hard link, so an interrupted pull leaves no partial file. The list walk follows the server's `links.next` cursor and fails closed on a missing or repeated cursor. `pull/SIDE_EFFECTS.md` records the full side-effect surface. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Adds `supabase notebooks push`, the mirror of `notebooks pull` from the previous PR in this stack. Every file in `supabase/notebooks/` is written to the project notebook of that name, or to a new one when the project has none. ```sh supabase notebooks push # push the whole directory supabase notebooks push <name> # push one notebook ``` ## How to try it ```sh supabase notebooks pull # edit a file in supabase/notebooks/, or add a new one supabase notebooks push <name> supabase notebooks pull <notebook-id> # see what the project stored ``` Notebooks are behind a dashboard feature preview; switching it on lets you create and edit them in the dashboard, so both sides can be moved independently — edit the same notebook in each place, set `favorite` in the dashboard and leave it out of the file, or add a notebook the directory does not have to reach the reconciliation prompt. ## Notes - **Read everything before writing anything.** All selected files are read and decoded before the first upload, so a directory holding one unreadable notebook fails without having half-pushed the rest. The reconciliation plan is resolved before the first upload for the same reason. - **Absent keys stay absent.** Keys a file leaves out are omitted from the request rather than sent as explicit nulls, which is how `favorite` keeps whatever the dashboard set on a notebook whose file never mentions it. - **Cell identities survive.** Cell `id`s written out on pull are echoed on push, so a cell keeps its identity across an update instead of being replaced by a copy. The API rejects a cell carrying an id the notebook does not have. - **Reconciliation points the other way.** Project notebooks naming no local file get the three answers `pull` offers, mirrored. Passing a notebook name pushes just that one and reconciles nothing — and because it only checks that one name for duplicates, it still works in a project where other notebooks share a name. - `push/SIDE_EFFECTS.md` records the side-effect surface. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
#6740) ## Summary Moves the AI review pipeline's Claude pass (`claude-review`) from `claude-opus-5` to `claude-opus-5-5`. The Codex side stays on `gpt-6-sol` from #6731. The repo's `ANTHROPIC_API_KEY` doesn't have access to every model (it returned 404 for `claude-fable-5` when the pipeline was first set up), so the key was checked before making this change. A throwaway push-triggered workflow on a now-deleted branch called `GET /v1/models/{id}` with the secret and got HTTP 200 for both `claude-opus-5` and `claude-opus-5-5` ([run 35860464428](https://github.com/supabase/cli/actions/runs/35860464428)). The pinned Claude Code also has to move. The first automatic review on this PR failed in `claude-review` because the API rejects `2.1.247` for this model ("version 2.1.280 or newer is required"), so the pin goes to `2.1.280`. That is npm's current `latest`, published 2026-09-22. The `stable` tag is still on `2.1.267`, which is too old for this model. ## Linked issue No linked issue — maintainer change. ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`). - [ ] Tests added or updated for the change. — n/a, workflow configuration only. - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace (or workspace declaring it). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## TL;DR brings the `supabase inspect` command family under the effect lint ## whats introduced? effect lint applied to `inspect`: - one allow list entry in `.oxlintrc.effect.json` - the query runner, the report config and the report handler yield their tagged errors directly instead of wrapping them in `Effect.fail` - report rule fields resolve `env(VAR)` through `Config`, and both test tiers now provide the CLI config provider, so a set but empty shell variable keeps the literal text in tests the same way it does in production - the `env(VAR)` form is named once by a helper that `expandEnv` shares - `InspectCsvqError` becomes a tagged error, which adds it to the error tag fixture - the dated report folder formats through `DateTime` in the local zone, the same folder name the reports have always written - cause assertions across the family use `Cause.pretty`, exit checks use `Exit.isFailure`, and env cases in the report config tests run through `withEnvVar` - e2e tests run through the effect native harness with `withTempHome`, the live test through the `cliEffect` fixture with the test signal forwarded ## ref: - closes: CLI-2445
## Summary - Slim-image mirroring no longer opens its own pull request to pin `packages/stack/src/Artifacts.ts`. - A Dependabot bump of the service-image Dockerfile commits the matching catalog pins onto that same pull request. - OrioleDB tags have no slim image. They stay on docker.io, and a missing slim pin does not block the other services. --------- Co-authored-by: Claude <noreply@anthropic.com>
…er (CLI-2462) (#6759) ## TL;DR fixes `supabase functions serve` intermittently returning a 500 with `WorkerAlreadyRetired` when a request lands on a retired worker. ## what's hurting the user(s)? the serve bootstrap could hand a request to a user worker that edge runtime had already retired. edge runtime rejects it before the req reaches the worker & w no retry for that error the req failed with a generic 500, so local test suites saw flaky 500s for reqs their function never even ran ## now fixed by introducing a single retry on a fresh worker when the rejection is `WorkerAlreadyRetired` and the req carries no body. the replay is safe since the req never reached the worker, and bodyless ones have nothing to replay reqs with a body keep today's behaviour their body is already forwarded so it cant be replayed without cloning, and cloning is what - #6564 was about that half waits on supabase/edge-runtime#742 + a way to do that w/o cloning... ## ref: - closes: #6675
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
branchesget, update and disable (CLI-2327) (test(cli): coverbranchesget, update and disable (CLI-2327) #6492)--log-levelvalue (CLI-2329) (fix(cli): consume--log-levelvalue (CLI-2329) #6483)network-restrictionsget and update (CLI-2288) (test(cli): covernetwork-restrictionsget and update (CLI-2288) #6478)