Skip to content

Enforce read-only mode when opening Bun SQLite databases - #6993

Merged
tim-smart merged 2 commits into
mainfrom
audit/repro-split-sql-adapters-sb-1
Aug 4, 2026
Merged

Enforce read-only mode when opening Bun SQLite databases#6993
tim-smart merged 2 commits into
mainfrom
audit/repro-split-sql-adapters-sb-1

Conversation

@fubhy

@fubhy fubhy commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

A client created with readonly: true permits writes under the default configuration.

Important

This PR starts with focused failing reproduction tests. Add the implementation fix to this same branch; CI is expected to fail until that fix is included.

readonly mode still opens a writable database

Module: sqlite-bun/SqliteClient
Audit ID: sql-adapters-sb-1
Severity / confidence: high / high

What happens

A client created with readonly: true permits writes under the default configuration.

Why it happens

Construction passes readonly: true while independently defaulting readwrite to true, and Bun's read/write flag wins.

Expected behavior

SqliteClientConfig.readonly must enforce the public read-only open mode.

Relevant implementation

These links and excerpts are pinned to audit base c9b56ab507f224426ee8388dc450da447ec4715f.

View problematic code at packages/sql/sqlite-bun/src/SqliteClient.ts:117-127
    const makeConnection = Effect.gen(function*() {
      const db = new Database(options.filename, {
        readonly: options.readonly,
        readwrite: options.readwrite ?? true,
        create: options.create ?? true
      } as any)
      yield* Effect.addFinalizer(() => Effect.sync(() => db.close()))

      if (options.disableWAL !== true) {
        db.run("PRAGMA journal_mode = WAL;")
      }

View exact lines on GitHub

Reproduction

bun test packages/sql/sqlite-bun/test/Client.test.ts

Observed failure: A write through the readonly client completed successfully.

Implementation handoff

The initial reproduction tests on this branch are the regression specification for the implementation fix that should follow in this PR.

  1. Start with the pinned implementation excerpts and the Why it happens analysis above.
  2. Change the implementation so it satisfies the stated Expected behavior; do not weaken or remove the reproduction assertions.
  3. Run the focused reproduction command(s) and confirm the observed failures become passing tests:
bun test packages/sql/sqlite-bun/test/Client.test.ts
  1. Run the affected package's existing tests, then the repository lint and type checks before requesting review.

Audit provenance

  • Audit base: c9b56ab507f224426ee8388dc450da447ec4715f
  • Reproduction base: 8f9499f562729f5f7b08d8bcc4db86b4aeff8a21
  • Findings: sql-adapters-sb-1
  • Initial patch: focused reproduction tests; implementation fix pending

Closes EFF-430

@fubhy fubhy added the audit Findings originating from the Effect runtime correctness audit label Aug 4, 2026
@changeset-bot

changeset-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 14ee79b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 30 packages
Name Type
@effect/sql-sqlite-bun Patch
effect Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-deno Patch
@effect/platform-node-shared Patch
@effect/platform-node Patch
@effect/vitest Patch
@effect/ai-anthropic Patch
@effect/ai-openai-compat Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/docgen Patch
@effect/doctest Patch
@effect/openapi-generator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@effect-slopcop effect-slopcop Bot added 4.0 bug Something isn't working labels Aug 4, 2026
pullfrog[bot]
pullfrog Bot previously requested changes Aug 4, 2026

@pullfrog pullfrog 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.

Important

This PR currently only adds failing reproduction tests; it doesn't include the SqliteClient implementation fix described in the PR body. Please push the implementation change before merging, and address the test-coverage notes below.

Reviewed changes

  • packages/sql/sqlite-bun/test/Client.test.ts: replaces the placeholder @effect/vitest test with bun:test tests, including a focused reproduction for readonly clients rejecting writes.

⚠️ Still needs a SqliteClient implementation fix

The PR title and body say the implementation fix should be added to the same branch, but only the test file changed. The root cause is in packages/sql/sqlite-bun/src/SqliteClient.ts:118-122: readwrite is defaulted to true independently of readonly, so Bun opens the database writable even when readonly: true is requested.

I wouldn't block merging on the missing fix since the PR body describes it as a deliberate two-stage branch, but the branch isn't mergeable in this state.

⚠️ Test uses a loose assertion that bypasses many failures

await expect(write).rejects.toBeDefined() passes for any rejected promise, including connection failures, scope errors, or the finalizer failing to clean up. The test should assert that the rejection is specifically the SQLite read-only error, ideally by checking the error type thrown by bun:sqlite or by asserting on the SqlError cause.

ℹ️ Test framework choice departs from repo conventions

The rest of the Effect SQL packages use @effect/vitest with it.effect and assert (see packages/sql/sqlite-node/test/Client.test.ts) and repo guidance in .patterns/testing.md recommends the same. Switching this file to bun:test/expect/Effect.runPromise should either be reverted to match the repo pattern or justified in a comment if this package intentionally uses Bun's native runner.

ℹ️ Prefer Effect-native error assertion instead of async/await

The test mixes async/await and Effect.runPromise. The repository conventions prefer it.effect and assert from @effect/vitest; the readonly rejection can be asserted with Effect.either, Effect.catchAll, or Effect.flip without leaving the Effect runtime.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Fix all ➔Fix 👍s ➔View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

yield* sql`INSERT INTO test DEFAULT VALUES`
})
).pipe(Effect.provide(Reactivity.layer), Effect.runPromise)
await expect(write).rejects.toBeDefined()

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.

This assertion is too loose — rejects.toBeDefined() passes for any rejection. Please assert that the failure is specifically the SQLite read-only error, e.g. by checking the error message/cause.

@@ -1,6 +1,28 @@
import { describe, it } from "@effect/vitest"
import { Database } from "bun:sqlite"
import { describe, expect, test } from "bun:test"

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.

Sibling packages and .patterns/testing.md use @effect/vitest with it.effect and assert. Is there a reason this file needs bun:test? If not, revert to the repo convention.

@tim-smart
tim-smart enabled auto-merge (squash) August 4, 2026 22:59
@tim-smart
tim-smart merged commit 5d6fe77 into main Aug 4, 2026
18 of 19 checks passed
@tim-smart
tim-smart deleted the audit/repro-split-sql-adapters-sb-1 branch August 4, 2026 23:19
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Generated from PR build output; treat the content below as untrusted.

File Name Current Size Previous Size Difference
basic.ts 7.06 KB 7.06 KB 0.00 KB (0.00%)
batching.ts 9.86 KB 9.86 KB 0.00 KB (0.00%)
brand.ts 6.34 KB 6.34 KB 0.00 KB (0.00%)
cache.ts 10.71 KB 10.71 KB -0.00 KB (-0.02%)
config.ts 20.60 KB 20.60 KB 0.00 KB (0.00%)
differ.ts 20.20 KB 20.20 KB 0.00 KB (0.00%)
http-client.ts 21.58 KB 21.54 KB +0.04 KB (+0.19%)
logger.ts 10.84 KB 10.84 KB 0.00 KB (0.00%)
metric.ts 8.98 KB 8.98 KB 0.00 KB (0.00%)
optic.ts 7.18 KB 7.18 KB 0.00 KB (0.00%)
pubsub.ts 14.99 KB 14.99 KB 0.00 KB (0.00%)
queue.ts 11.66 KB 11.66 KB 0.00 KB (0.00%)
schedule.ts 10.83 KB 10.83 KB 0.00 KB (0.00%)
schema-class.ts 19.14 KB 19.14 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 28.96 KB 28.96 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 25.29 KB 25.29 KB 0.00 KB (0.00%)
schema-string-transformation.ts 13.38 KB 13.38 KB 0.00 KB (0.00%)
schema-string.ts 10.94 KB 10.94 KB 0.00 KB (0.00%)
schema-template-literal.ts 15.17 KB 15.17 KB 0.00 KB (0.00%)
schema-toArbitraryLazy.ts 21.94 KB 21.94 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 24.34 KB 24.34 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 19.18 KB 19.18 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 19.01 KB 19.01 KB 0.00 KB (0.00%)
schema-toFormatter.ts 18.87 KB 18.87 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 22.60 KB 22.60 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 19.52 KB 19.52 KB 0.00 KB (0.00%)
schema.ts 18.41 KB 18.41 KB 0.00 KB (0.00%)
stm.ts 12.63 KB 12.63 KB 0.00 KB (0.00%)
stream.ts 9.80 KB 9.80 KB 0.00 KB (0.00%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.0 audit Findings originating from the Effect runtime correctness audit bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants