Skip to content

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

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

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

Conversation

@supabase-cli-releaser

Copy link
Copy Markdown
Contributor

Merging develop into next conflicts. This branch starts at the tip of develop (57f336e); next is at 3d62653.

Conflicting files:

  • .oxlintrc.effect.json
  • apps/cli/src/command-internal/db-bootstrap/db-setup.unit.test.ts
  • apps/cli/src/command-internal/db-bootstrap/shadow-cache.integration.test.ts
  • apps/cli/src/command-internal/db-bootstrap/start-local-database.ts
  • apps/cli/src/command-internal/stack-storage.native.integration.test.ts
  • apps/cli/src/command-internal/test-db.handler.ts
  • apps/cli/src/command-internal/upgrade-notice.integration.test.ts
  • apps/cli/src/command-internal/upgrade-notice.ts
  • apps/cli/src/command-internal/upgrade-notice.unit.test.ts

To resolve:

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

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

7ttp added 2 commits October 16, 2026 11:14
…7150)

## TL;DR
brings  `upgrade-notice` to effect & the effect lint

## whats introduced?

- the check reads files through `FileSystem`, 
the latest release through `HttpClient`, env through `Config` and the
working and home directories through `RuntimeInfo`
- `runCli`'s post-success hook now takes these services from the cli
runtime instead of providing its own
- release-lookup failures are typed as `UpgradeNoticeFetchError`
- the cache write keeps the final entry link-safe without `O_NOFOLLOW`: 
the old entry is removed, which deletes a symlink or hard link itself,
and the file is recreated exclusively with mode `0644`
- so a stale read-only cache file is now replaced, and a
stale cache file in a read-only cache directory no longer refreshes, so
each command checks the release again

## ref

- closes: CLI-2648
…s with effect lint (CLI-2655) (#7167)

## TL;DR

brings the `db-bootstrap`, `stack`, `start` and `test-db` modules under
the effect lint, tests included

## whats introduced?

- `db-bootstrap/**`, `stack-*`, `start-*` and `test-db.*` join the allow
list,
with `db-bootstrap/local-db-running` kept out that for now since it
probes the docker engine socket through `node:http`
- `start-secrets-cleanup` removes staged secrets through `FileSystem`,
and `test-db` builds its `pg_prove` args through `Path`, instead of
`node:fs` and `node:path`
- the stack shadow-cache key is encoded through `Schema` with the same
bytes, and yieldable errors are yielded directly instead of through
`Effect.fail`
- the tests swap `node:` imports and `JSON` for effect services and
schemas, and the start-secrets traversal test now aims at a real canary
outside the staging root

## ref

- closes: CLI-2655
@supabase-cli-releaser
supabase-cli-releaser Bot requested a review from a team as a code owner October 16, 2026 11:33
@supabase-cli-releaser supabase-cli-releaser Bot added the do not merge Approve to apply; do not merge. label Oct 16, 2026
# Conflicts:
#	.oxlintrc.effect.json
#	apps/cli/src/command-internal/db-bootstrap/db-setup.unit.test.ts
#	apps/cli/src/command-internal/db-bootstrap/shadow-cache.integration.test.ts
#	apps/cli/src/command-internal/db-bootstrap/start-local-database.ts
#	apps/cli/src/command-internal/stack-storage.native.integration.test.ts
#	apps/cli/src/command-internal/test-db.handler.ts
#	apps/cli/src/command-internal/upgrade-notice.integration.test.ts
#	apps/cli/src/command-internal/upgrade-notice.ts
#	apps/cli/src/command-internal/upgrade-notice.unit.test.ts
@supabase-cli-releaser

Copy link
Copy Markdown
Contributor Author

Claude resolved the merge of next

I resolved all nine conflicted files and no conflict markers remain anywhere in the tree. Nothing has been run yet: the job's check:all and unit tests still need to pass on the merged tree. The approach throughout was to keep next's changes (the Go delegation is gone, config.json is found alongside config.toml, a BOM in .env is ignored, and the Go references in test titles are removed) and carry develop's Effect-native rewrite of the touched modules and their tests onto them.

File Resolution
.oxlintrc.effect.json Dropped the workdir-search.ts entry because next deleted that file. Kept develop's two exclusions for db-bootstrap/local-db-running*, placed after the ! include entries so they still take effect.
apps/cli/src/command-internal/db-bootstrap/start-local-database.ts Kept next's simpler checks on config.studio and config.local_smtp (the env-override checks are gone). Applied develop's lint fix to them: return yield* new DbConfigLoadError(...) instead of yield* Effect.fail(...).
apps/cli/src/command-internal/test-db.handler.ts Took next's network name, supabase_network_${toml.projectId}. On next, readDbToml already returns projectId as a plain string, so develop's Option fallback plus sanitizing no longer applies.
apps/cli/src/command-internal/db-bootstrap/shadow-cache.integration.test.ts Kept next's nesting (the cache env wraps the SUPABASE_HOME override) and its yield* shadowCacheDir(path). Used develop's nodePath.join and its DateTime-based anHourAgo.
apps/cli/src/command-internal/db-bootstrap/db-setup.unit.test.ts Kept develop's Effect-native test bodies (FileSystem and makeWorkdir effects instead of rmSync). Applied next's shorter test titles without Go references, and reformatted the two tests whose titles now fit on one line.
apps/cli/src/command-internal/stack-storage.native.integration.test.ts Kept develop's removal of the duplicate BunServices.layer from mergeAll, since provideMerge already supplies it. Added next's cliConfigValuesTestLayer.
apps/cli/src/command-internal/upgrade-notice.ts Kept develop's Effect-native version (FileSystem/Path, HttpClient release lookup, Config-based env, RuntimeInfo, actionability error). Removed the delegatedToGo branch, made the ancestor walk accept supabase/config.json as well as config.toml, and read dotenv files with readFileString so a leading BOM is dropped. Imported candidateDotenvFilenames from cli-config-env.ts and removed next's now-unused UPGRADE_NOTICE_ENV_NAMES, readShellEnvironment and async fetch.
apps/cli/src/command-internal/upgrade-notice.integration.test.ts Took develop's Effect-native version (withConfigEnv, runtimeInfoLayer, an Effect release stub). It already supplies the ConfigProvider, so next's cliConfigProviderLayer is not needed.
apps/cli/src/command-internal/upgrade-notice.unit.test.ts Kept develop's Effect-native suites. Removed the delegatedToGo option, its doc comment, the delegated-to-Go test, and the delegatedToGo: false argument. Ported next's new test that a .env with a BOM still opts out. Dropped next's runHookWithProvider tests, which develop's release lookup suite already covers through the ambient ConfigProvider.

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

  • upgradeNoticeHook env and GITHUB_TOKEN source: next's readShellEnvironment with the token passed to an async fetch, or develop's Config-based reads with an HttpClient fetch? Chose: develop's Config.option/Config.Redacted reads with the Effect HttpClient lookup. Both read the same ambient ConfigProvider, so next's goal of not using process.env still holds, and develop's tests already cover the token and opt-out cases.
  • Dotenv BOM handling in the upgrade notice: develop's readUtf8, which keeps the BOM, or next's BOM-stripping decode? Chose: next's behaviour via fs.readFileString, which strips the BOM, for dotenv files only. The cache-tag read still uses readUtf8, so a BOM-prefixed cached tag is still rejected as develop intends.

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

Claude's fix. The effect lint check failed because develop added effect lint coverage for db-bootstrap, and a test merged in from next wrapped a single return yield* in an Effect.gen. I removed that wrapper in local-container-inputs.precedence.integration.test.ts and now call buildLocalDbContainerInputs(...).pipe(Effect.provide(layer)) directly; there were no review findings to answer.

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

return Effect.void;
}
/* Interruptible even in the start and stop finalizers, so the first failure ends cleanup. */
return Effect.interruptible(fs.remove(target, { recursive: true, force: true }));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚪ Severity: LOW

While the change appears deliberate, SIGINT/SIGTERM rollback and stop invoke this cleanup from finalizers after container removal; making deletion interruptible lets pending cancellation stop the parallel removals. Staged JWT, service-role, and configured-secret files can therefore remain in the project tree for later same-account processes to read.
Helpful? Add 👍 / 👎

💡 Fix Suggestion

Suggestion: Remove the Effect.interruptible wrapper around fs.remove so the deletion inherits the uninterruptible context of the start rollback and stop finalizers. If you want to be sure it finishes even when called from an interruptible context, wrap it in Effect.uninterruptible instead. The cleanup already ends in Effect.ignore, so failures are swallowed either way. Update or remove the comment on line 30, which wrongly says interruptibility makes the first failure end cleanup. Interruption is fiber cancellation, not error handling.

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

Suggested change
return Effect.interruptible(fs.remove(target, { recursive: true, force: true }));
return Effect.uninterruptible(fs.remove(target, { recursive: true, force: true }));

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 AI Review

Verified all five submitted findings and merged the duplicate cache finding into four entries. Confirmed the cache-refresh regression, a pre-existing test-cleanup weakness, and the test-naming nit. The secret-cleanup impact remains uncertain because the filesystem adapter implementation is unavailable. No next-context file was present. Tests were not run.

Findings

Severity Location Category Sources Claim
🟡 MINOR apps/cli/src/command-internal/upgrade-notice.ts:175 compatibility claude+codex Refreshing an existing writable cache now requires write permission on its parent directory. With a read-only directory, the stale cache cannot record a fetched version or offline backoff, so subsequent invocations repeat the network lookup.
🟡 MINOR apps/cli/src/command-internal/start-secrets-cleanup.ts:31 error-handling claude A failed secret-directory removal can interrupt sibling cleanup effects and leave other containers' staged-secret directories behind.
⚪ NIT apps/cli/src/command-internal/db-bootstrap/db-setup.unit.test.ts:254 test-hygiene claude Temporary directories remain on disk when these tests fail before reaching their trailing fs.remove call.
⚪ NIT apps/cli/src/command-internal/upgrade-notice.unit.test.ts:597 test-naming codex Renamed tests add Go implementation comparisons instead of describing the CLI contract in its own terms.

Stats

Claude findings: 3 · Codex findings: 2 · Confirmed: 3 · Refuted: 0 · Uncertain: 1


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

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

Comment on lines +175 to +183
const writeCacheFile = Effect.fnUntraced(function* (cacheFile: string, contents: string) {
const fs = yield* FileSystem.FileSystem;
yield* fs
.remove(cacheFile)
.pipe(Effect.catchReason("PlatformError", "NotFound", () => Effect.void));
yield* fs
.writeFileString(cacheFile, contents, { flag: "wx", mode: 0o644 })
.pipe(Effect.catchReason("PlatformError", "AlreadyExists", () => Effect.void));
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MINOR · compatibility · source: claude+codex

Refreshing an existing writable cache now requires write permission on its parent directory. With a read-only directory, the stale cache cannot record a fetched version or offline backoff, so subsequent invocations repeat the network lookup.

Evidence: upgrade-notice.ts:177-182 removes the cache before recreating it with flag "wx". Lines 322-331 determine freshness from its unchanged mtime and fetch whenever stale. upgrade-notice.unit.test.ts:378-390 explicitly expects EACCES and the old cache contents when the directory mode is 0555.

Suggested fix: Preserve a no-follow in-place writer for existing regular files through an Effect adapter, retaining exclusive creation for absent files and the read-only-directory regression test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The remove-then-wx cache writer and its read-only-directory test come from develop's effect-native upgrade-notice change, not from the merge. It is out of scope for this sync.

Comment on lines +31 to +34
return Effect.interruptible(fs.remove(target, { recursive: true, force: true }));
},
{ concurrency: "unbounded", discard: true },
).pipe(Effect.ignore);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MINOR · error-handling · source: claude

A failed secret-directory removal can interrupt sibling cleanup effects and leave other containers' staged-secret directories behind.

Evidence: start-secrets-cleanup.ts:21-34 runs interruptible fs.remove effects concurrently and ignores errors only outside Effect.forEach. The helper runs in finalizers at commands/stop/stop.handler.ts:160-162 and commands/start/start.handler.ts:1436-1438, and during rollback at db-bootstrap/rollback.ts:56.

Suggested fix: Ignore removal errors within each iteration so a failure cannot interrupt sibling cleanup effects, and remove the explicit interruptible wrapper unless required.

Adjudication (uncertain): The fail-fast effect structure and finalizer callers are verified. However, the installed filesystem adapter source is absent, so I could not establish whether interruption cancels native removals already underway or merely stops awaiting operations that continue deleting. The available tests do not exercise concurrent cleanup with a failing removal.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The concurrent cleanup in start-secrets-cleanup.ts is existing develop code that the merge did not change. It is out of scope for this sync.

expect(execSql.some((sql) => sql.endsWith(SCHEMA_14_FINGERPRINT_SUFFIX))).toBe(true);
expect(execSql.some((sql) => sql.includes(SCHEMA_13_FINGERPRINT))).toBe(false);
expect(docker.runs.length).toBe(0);
yield* fs.remove(workdir, { recursive: true, force: true });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚪ NIT · test-hygiene · source: claude

Temporary directories remain on disk when these tests fail before reaching their trailing fs.remove call.

Evidence: db-setup.unit.test.ts:161-164 creates an unscoped temporary directory. Lines 248-254 perform the operation and assertions before cleanup; the same pattern appears at lines 265-271 and 282-289. The afterEach at lines 236-238 only restores environment stubs.

Suggested fix: Use makeTempDirectoryScoped with a scoped test, or register cleanup through an acquisition finalizer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The unscoped temp directories in db-setup.unit.test.ts come from develop, not from the merge. They are out of scope for this sync.

ctx.cleanup();
});
it.effect(
"--help ignores the project dotenv opt-out — Go never loads config for the built-ins",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚪ NIT · test-naming · source: codex

Renamed tests add Go implementation comparisons instead of describing the CLI contract in its own terms.

Evidence: upgrade-notice.unit.test.ts:597 adds "Go never loads config for the built-ins"; lines 363 and 444 add "Go-compatible modes" and "like godotenv before the Execute tail". trusted/CLAUDE.md:115 discourages Go-parity framing, and line 118 requires test names to carry intent.

Suggested fix: Remove implementation-comparison suffixes and retain the concrete behavior or expected permission modes in each test name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These test names come from develop's upgrade-notice change, not from the merge. They are out of scope for this sync.

@supabase-cli-releaser

Copy link
Copy Markdown
Contributor Author

Claude repair round

No CI check failed on this sync, so no code changes were needed. All four review findings are about code develop already had, so they are declined as out of scope for the sync.

0 findings fixed, 4 declined (workflow run).

@supabase-oss supabase-oss left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

CI is green and the AI review raised nothing the merge introduced, so this approves Claude's resolution of the sync (https://github.com/supabase/cli/actions/runs/38901653729).

@supabase-cli-releaser
supabase-cli-releaser Bot merged commit e9da236 into next Oct 16, 2026
64 of 65 checks passed
@supabase-cli-releaser
supabase-cli-releaser Bot deleted the sync/develop-into-next branch October 16, 2026 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do not merge Approve to apply; do not merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants