Skip to content

fix(sql): TypeError tls must be a boolean or an object + fix SSL/TLS behaviour to match postgres.js standard - #26503

Open
S4N-T0S wants to merge 16 commits into
oven-sh:mainfrom
S4N-T0S:main
Open

S4N-T0S wants to merge 16 commits into
oven-sh:mainfrom
S4N-T0S:main

Conversation

@S4N-T0S

@S4N-T0S S4N-T0S commented Jan 27, 2026 •

Copy link
Copy Markdown

What does this PR do?

This PR fixes several inconsistencies and bugs regarding SSL/TLS configuration in Bun.SQL. It changes the default SSL mode from disable to prefer (aligning with standard Postgres clients and existing code comments), ensures that verify-ca and verify-full are correctly implemented in the native code for both Postgres and MySQL, and fixes option parsing bugs in shared.ts.

Specifically, it:

  • Sets the default ssl mode to prefer (tries SSL, falls back to plaintext).
  • Fixes a TypeError that occurred when setting ssl: 'disable' without a tls object.
  • tls: false behavior:
    • If no ssl mode is provided, tls: false overrides the default prefer to disable.
    • If an explicit ssl mode is provided (e.g. require), passing tls: false throws a validation error to prevent accidental security downgrades.
  • Updates PostgresSQLConnection.zig and JSMySQLConnection.zig to distinguish between verify-ca (cert chain check only) and verify-full (cert chain + hostname check).
  • Updates documentation to reflect the correct defaults and configuration options.

What is the issue?
There were multiple issues with the previous SSL implementation:

  1. Incorrect Default: Although code comments (postgres.ts line 511) stated that prefer was the default, the code actually defaulted to plaintext (disable).
  2. Option Parsing Bug: Setting { ssl: 'disable' } caused a TypeError: tls must be a boolean or an object because the string value was incorrectly being assigned to the tls configuration.
  3. TLS Boolean Logic: Setting tls: false did not consistently disable SSL if other defaults were at play.
  4. Verification Logic: The native implementation needed to explicitly separate verify-ca and verify-full logic to ensure strict verification modes behaved as expected (e.g., verify-ca shouldn't enforce hostname validation, but verify-full must).

How did you verify your code works?
I included test scripts and tested all connection modes for Postgresql.

  1. ssl-postgres-behavior-verification.test.ts - Tests with docker image if our "rejectUnauthorized" logic works like it does in postgres.js (accepts unsigned certs by default, rejects if rejectUnauthorized is set to true or in verify-ca/verify-full ssl mode)
  2. ssl-postgres-handshake.test.ts - Tests with a mock server if handshake logic matches what we expect. (the mock server does not accept ssl so it should attempt ssl, then fallback or error correctly)
1. test\js\sql\ssl-postgres-behavior-verification.test.ts:
✓ PostgreSQL TLS Compatibility > prepared: true > ssl: 'prefer' connects successfully with snakeoil cert [192.01ms]
✓ PostgreSQL TLS Compatibility > prepared: true > ssl: 'require' connects successfully with snakeoil cert (loose default) [47.00ms]
✓ PostgreSQL TLS Compatibility > prepared: true > ssl: 'require' with rejectUnauthorized: false connects successfully [44.00ms]
✓ PostgreSQL TLS Compatibility > prepared: true > ssl: 'require' with rejectUnauthorized: true throws on snakeoil cert [37.00ms]
✓ PostgreSQL TLS Compatibility > prepared: true > ssl: 'verify-ca' throws without CA provided [36.00ms]
✓ PostgreSQL TLS Compatibility > prepared: true > ssl: 'verify-full' throws on host mismatch/untrusted cert [35.00ms]
✓ PostgreSQL TLS Compatibility > prepared: true > tls: true alias works like ssl: 'require' (loose) [43.00ms]
✓ PostgreSQL TLS Compatibility > prepared: false > ssl: 'prefer' connects successfully with snakeoil cert [30.00ms]
✓ PostgreSQL TLS Compatibility > prepared: false > ssl: 'require' connects successfully with snakeoil cert (loose default) [32.00ms]
✓ PostgreSQL TLS Compatibility > prepared: false > ssl: 'require' with rejectUnauthorized: false connects successfully [35.00ms]
✓ PostgreSQL TLS Compatibility > prepared: false > ssl: 'require' with rejectUnauthorized: true throws on snakeoil cert [31.00ms]
✓ PostgreSQL TLS Compatibility > prepared: false > ssl: 'verify-ca' throws without CA provided [27.00ms]
✓ PostgreSQL TLS Compatibility > prepared: false > ssl: 'verify-full' throws on host mismatch/untrusted cert [27.00ms]
✓ PostgreSQL TLS Compatibility > prepared: false > tls: true alias works like ssl: 'require' (loose) [29.00ms]

2. test\js\sql\ssl-postgres-handshake.test.ts:
✓ PostgreSQL SSL Handshake (Mock Server) > Default (No Options) -> Prefer (SSLRequest -> Fallback -> Startup) [109.00ms]
✓ PostgreSQL SSL Handshake (Mock Server) > SSL: disable -> Only StartupMessage
✓ PostgreSQL SSL Handshake (Mock Server) > TLS: false -> Only StartupMessage [16.00ms]
✓ PostgreSQL SSL Handshake (Mock Server) > SSL: disable, TLS: true -> Only StartupMessage (SSL takes precedence)
✓ PostgreSQL SSL Handshake (Mock Server) > SSL: prefer -> SSLRequest -> StartupMessage [15.00ms]
✓ PostgreSQL SSL Handshake (Mock Server) > SSL: require -> Fails on 'N' response [16.00ms]
✓ PostgreSQL SSL Handshake (Mock Server) > TLS: true -> Acts as Prefer (Defaults)
✓ PostgreSQL SSL Handshake (Mock Server) > SSL: require, TLS: false -> Fails config validation
✓ PostgreSQL SSL Handshake (Mock Server) > SSL: verify-ca (No CA) -> Fails before handshake [16.00ms]

@coderabbitai

coderabbitai Bot commented Jan 27, 2026 •

Copy link
Copy Markdown
Contributor

Walkthrough

Default SSL mode changed to "prefer". Option parsing now maps ssl strings/booleans/objects to explicit SSL modes and derives tls when appropriate. TLS/handshake flows were adjusted across JS and Zig: mode-driven decisions, hostname verification, buffering, re-entrancy guards, added logging, updated types, docs, and tests.

Changes

Cohort / File(s) Summary
Option parsing & TLS defaults (JS)
src/js/internal/sql/shared.ts
Default sslMode set to prefer. options.ssl accepts mode strings, booleans, or TLS objects and maps to SSL modes; legacy ssl object can populate tls; enforces rejectUnauthorized for verify-ca/verify-full; injects serverName for SNI when appropriate; removed legacy unconditional TLS merge.
JS TLS comments/annotations
src/js/internal/sql/mysql.ts, src/js/internal/sql/postgres.ts
Clarified docs/comments: tls: false explicitly disables TLS; notes that defaulting to "prefer" is handled in parseOptions and that falsy 0 is allowed to disable TLS. No runtime/signature changes.
Zig: Postgres TLS flow
src/sql/postgres/PostgresSQLConnection.zig
Refactored TLS upgrade/handshake: added logs, handle server 'S'/'N' responses, buffer data during TLS handshake, add re-entrancy guards, implement verify_ca/verify_full checks (including servername verification), and removed implicit start after upgrade.
Zig: MySQL TLS, buffering & guards
src/sql/mysql/MySQLConnection.zig
Added public accessors getSSLMode, bufferData, hasBufferedData. Handshake outcome now follows SSL-mode rules with verify-ca/verify-full checks and hostname verification. Improved read remainder handling, processing guards, and buffering to avoid re-entrancy.
JS↔Zig MySQL bridge updates
src/sql/mysql/js/JSMySQLConnection.zig
SocketHandler(comptime ssl: bool) onHandshake_ param renamed to s: SocketType; handshake handling now delegates to connection verification, performs verify_full hostname checks, buffers post-handshake data, and guards onData to buffer concurrent data.
Docs
docs/runtime/sql.mdx
Updated narrative and examples to prefer ssl mode strings ("disable","prefer","require","verify-ca","verify-full"), state default "prefer", clarify tls: false semantics and precedence between tls and ssl.
Types
packages/bun-types/sql.d.ts
Expanded ssl union in PostgresOrMySQLOptions to include mode literals `"disable"
Tests (unit & integration)
test/js/sql/ssl-postgres-handshake.test.ts, test/js/sql/ssl-postgres-behavior-verification.test.ts
Added unit mock-server tests for Postgres SSL handshake signaling and a Docker-backed integration suite exercising ssl-mode permutations, CA/hostname verification, and expected success/failure cases.
Misc TLS guards & logging
src/sql/mysql/js/..., src/js/internal/sql/postgres.ts
Added logging, handshake outcome classification, buffering/restart logic around TLS transitions, and processing guards to avoid data loss and race conditions during upgrades.
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly identifies the two main issues being fixed: a TypeError related to TLS configuration and SSL/TLS behavior corrections to match postgres.js standards.
Description check ✅ Passed The PR description fully addresses both template sections with detailed explanation of what the PR does, specific changes made, the underlying issues, and comprehensive test verification with test output.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@alii

alii commented Jan 27, 2026

Copy link
Copy Markdown
Member

Thank you, this seems correct. I've unblocked the CI.

@S4N-T0S
S4N-T0S marked this pull request as draft January 28, 2026 09:17
@S4N-T0S
S4N-T0S marked this pull request as ready for review January 28, 2026 10:29

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/sql/mysql/js/JSMySQLConnection.zig (1)

336-360: Allow null/undefined TLS objects to use default empty TLS config.

When a user sets ssl_mode but omits the tls option, the JS layer passes null (via the tls ?? null coalescing at postgres.ts:516, mysql.ts equivalent). The comments in postgres.ts:338 and mysql.ts:112 explicitly document that "boolean false or null => nothing" (i.e., use default TLS config), yet the current Zig code throws "tls must be a boolean or an object" on line 354.

The fix should check tls_object.isEmptyOrUndefinedOrNull() first and treat it the same as an explicit boolean true, consistent with the documented behavior:

Suggested fix
    if (ssl_mode != .disable) {
        tls_config = if (tls_object.isEmptyOrUndefinedOrNull() or (tls_object.isBoolean() and tls_object.toBoolean()))
            .{}
        else if (tls_object.isObject())
            (jsc.API.ServerConfig.SSLConfig.fromJS(vm, globalObject, tls_object) catch return .zero) orelse .{}
        else {
            return globalObject.throwInvalidArguments("tls must be a boolean or an object", .{});
        };
src/sql/postgres/PostgresSQLConnection.zig (1)

594-618: Allow null/undefined tls when ssl_mode is enabled to support graceful SSL fallback.

Lines 613–615 throw an error if tls is not a boolean or object. However, when tls is omitted but ssl_mode is set (e.g., .require or .prefer), the JavaScript side may pass undefined or null for arguments[6], causing an unnecessary error. Per the MySQL connector behavior, .require and .prefer should gracefully degrade when SSL is unavailable; only .verify_ca and .verify_full should reject non-SSL connections.

Update the condition to accept null/undefined as a default (empty) TLS config:

🔧 Suggested fix
-    tls_config = if (tls_object.isBoolean() and tls_object.toBoolean())
+    tls_config = if (tls_object.isEmptyOrUndefinedOrNull())
+        .{}
+    else if (tls_object.isBoolean() and tls_object.toBoolean())
         .{}
     else if (tls_object.isObject())
         (jsc.API.ServerConfig.SSLConfig.fromJS(vm, globalObject, tls_object) catch return .zero) orelse .{}
     else {
         return globalObject.throwInvalidArguments("tls must be a boolean or an object", .{});
     };

Apply the same fix to the MySQL connector at src/sql/mysql/js/JSMySQLConnection.zig lines 354–360.

@S4N-T0S S4N-T0S changed the title fix(bun:sql): fix TypeError when tls is false in Postgres fix(sql/mysql): TypeError tls must be a boolean or an object Jan 28, 2026
@S4N-T0S
S4N-T0S marked this pull request as draft January 28, 2026 17:48
@S4N-T0S S4N-T0S closed this Jan 28, 2026
@S4N-T0S

S4N-T0S commented Jan 28, 2026

Copy link
Copy Markdown
Author

I apologise for the mess here, I have edited the main PR to reflect what has been changed. I was at first expecting this to be a straightforward fix but then I just found more and more inconsistencies and issues as I dug deeper.

@S4N-T0S S4N-T0S reopened this Jan 28, 2026
@S4N-T0S S4N-T0S changed the title fix(sql/mysql): TypeError tls must be a boolean or an object fix(sql): TypeError tls must be a boolean or an object + more Jan 28, 2026
@S4N-T0S
S4N-T0S marked this pull request as ready for review January 28, 2026 23:21
@coderabbitai

coderabbitai Bot commented Jan 28, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/sql/mysql/js/JSMySQLConnection.zig`:
- Around line 236-275: In onHandshake_ for JSMySQLConnection, when handling
.verify_full mode and calling bun.BoringSSL.c.SSL_get_servername, add a failure
path if SSL_get_servername returns null so hostname verification does not get
silently skipped; if servername is unavailable, call this.failWithJSValue with
an appropriate JS error (e.g., create an error like ssl_error.toJS or a new
error indicating missing server name) and return. Update the same logic in
MySQLConnection.zig's onHandshake_ as well (referencing .verify_full,
SSL_get_servername, checkServerIdentity, and failWithJSValue) so verify_full
consistently rejects connections when server name cannot be obtained.

In `@src/sql/postgres/PostgresSQLConnection.zig`:
- Around line 424-447: In PostgresSQLConnection.zig update the .verify_full
branch to explicitly fail when the servername is missing and when
BoringSSL.checkServerIdentity returns false instead of skipping or reporting
ssl_error: detect when BoringSSL.c.SSL_get_servername returns null and call
this.failWithJSValue with a clear hostname-verification JS error (not
ssl_error), and when checkServerIdentity returns false similarly construct and
pass a descriptive JS error indicating hostname mismatch; use the existing
this.failWithJSValue and this.globalObject helpers to produce these dedicated
errors so verify_full never silently downgrades or emits the generic ssl_error.

Comment thread src/sql/mysql/js/JSMySQLConnection.zig Outdated
Comment thread src/sql/postgres/PostgresSQLConnection.zig
Comment thread src/sql/mysql/js/JSMySQLConnection.zig Outdated
Comment thread src/sql/postgres/PostgresSQLConnection.zig

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/js/internal/sql/shared.ts`:
- Around line 671-679: The current enforcement of rejectUnauthorized for sslMode
values SSLMode.verify_ca and SSLMode.verify_full runs before the code that may
convert a boolean tls into an object when injecting serverName, which can drop
rejectUnauthorized; update the logic in the module that handles tls/serverName
(references: sslMode, SSLMode.verify_ca, SSLMode.verify_full, tls, and the
serverName injection code) so that rejectUnauthorized = true is applied after
any conversion from boolean-to-object (or re-applied when you create the new tls
object), ensuring the final tls object always contains rejectUnauthorized: true.

Comment thread src/js/internal/sql/shared.ts

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/sql/mysql/js/JSMySQLConnection.zig`:
- Around line 242-278: The TLS verification in JSMySQLConnection.onHandshake_
duplicates logic already present in MySQLConnection.doHandshake; pick one place
to own verification to avoid redundancy — remove the duplicate verification
block from MySQLConnection.doHandshake and keep the full verification in
JSMySQLConnection.onHandshake_ (or vice versa if you prefer the core to own it),
but before removing confirm there are no other callers of
MySQLConnection.doHandshake that expect verification; update/remove any
now-unused helper functions/branches in MySQLConnection.doHandshake and run
related tests to ensure behavior remains the same.

In `@src/sql/mysql/MySQLConnection.zig`:
- Around line 237-238: The comment above the switch on this.#ssl_mode
incorrectly references the postgres library; update it to point to the correct
MySQL/TLS documentation (or a generic TLS mode reference) to avoid confusion.
Find the ssl mode handling in MySQLConnection (the switch on this.#ssl_mode) and
replace the postgres link with a link to MySQL's TLS/SSL docs (or an
RFC/OWASP/TLS-mode spec) and adjust the comment text to describe that the switch
implements MySQL client TLS modes.

Comment thread src/sql/mysql/js/JSMySQLConnection.zig Outdated
Comment thread src/sql/mysql/MySQLConnection.zig

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/sql/mysql/js/JSMySQLConnection.zig`:
- Around line 236-266: When onHandshake_ sees doHandshake return false with
ssl_error.error_no == 0 in verify_full mode and checkServerIdentity returns
true, add an explicit fallback error before falling through to failWithJSValue
to avoid an ambiguous message; locate the onHandshake_ function and after the
checkServerIdentity success path (the block using
bun.BoringSSL.checkServerIdentity) return a clear failFmt or fail call (e.g.,
using error.SslConnectionError) describing the inconsistent state (doHandshake
failed despite successful server identity verification) so that failWithJSValue
is not relied on to report an unclear zero-error SSL object.

Comment thread src/sql/mysql/js/JSMySQLConnection.zig
…that it executes before the Enforce rejectUnauthorized block.

Add fallthrough for edgecase in MySQL tls/ssl connection.

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@test/js/sql/ssl-postgres-handshake.test.ts`:
- Around line 9-21: Replace the hardcoded/random PORT usage with an OS-assigned
port by setting Bun.listen's port to 0 in the test setup (the beforeAll block
that initializes server), then read the actual assigned port from the server
(e.g., server.port or server.address().port) and use that value wherever PORT is
referenced to build the connection URL; update any other occurrences (including
the later block around the other test) to stop using the PORT constant and
instead use the runtime-assigned port variable so tests are not flaky in CI.

Comment thread test/js/sql/ssl-postgres-handshake.test.ts

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@test/js/sql/ssl-postgres-handshake.test.ts`:
- Around line 21-102: The data(socket, data) handler is assuming each chunk is a
full frame, causing flaky parsing; fix it by implementing per-socket buffering
inside data(socket, data): append incoming chunk to a buffer, then loop parsing
as long as the buffer contains a full message; for messages that start with 0
(Startup/SSL) use the 4-byte length at offset 0 to know total size and read the
code at offset 4 (refer to SSL_REQUEST_CODE and PROTOCOL_V3_CODE handling in
data), for normal typed messages (e.g. 'P' (80), 'Q' (81), 'C', 'Z', 'X' etc.)
require at least 5 bytes to read the 4-byte length at offset 1 and wait until
buffer has that many bytes before consuming and responding, and only then slice
consumed bytes from the buffer and continue the loop; ensure the same response
construction logic (parseComplete, bindComplete, cmdComplete, ready, etc.) is
used when a full message is available.

Comment thread test/js/sql/ssl-postgres-handshake.test.ts Outdated

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@test/js/sql/ssl-postgres-behavior-verification.test.ts`:
- Line 86: Fix the typo in the test comment: replace "TSL" with "TLS" in the
comment that reads "// Depending on where the error is caught (TSL layer or
Postgres layer)," in ssl-postgres-behavior-verification.test.ts so it correctly
references the TLS layer.
- Around line 129-145: Add two tests to
ssl-postgres-behavior-verification.test.ts that cover the missing scenarios: one
that constructs a new SQL({...getBaseOptions(), ssl: "disable"}) and runs a
simple query to assert it connects without TLS (expecting SELECT 1 to return 1),
and another that constructs new SQL({...getBaseOptions(), tls: false}) and runs
the same simple query to assert TLS is explicitly disabled; place them alongside
the existing tls/ssl tests and use the same container.ready and using sql
patterns so they exercise the same connection lifecycle and prevent regressions
for the TypeError and prefer-default behavior fixes.
- Around line 92-127: The tests "ssl: 'verify-ca' throws without CA provided"
and "ssl: 'verify-full' throws on host mismatch/untrusted cert" only assert that
an error exists; update each test (the SQL client created with new SQL({...
getBaseOptions(), ssl: "verify-ca" }) and ssl: "verify-full") to assert the
error is a TLS verification error rather than a generic failure by checking
error.message or error.code for TLS-related indicators (e.g., message contains
"certificate", "self signed", "host", or codes like DEPTH_ZERO_SELF_SIGNED_CERT
or CERT_HAS_EXPIRED), so replace the loose expect(error).toBeDefined() with a
targeted assertion (e.g., expect(error.message).toMatch(/certificate|self
signed|host/i) or expect(error.code).toBeDefined() with the expected TLS code)
while keeping a fallback loose assertion if platform messages differ.

Comment thread test/js/sql/ssl-postgres-behavior-verification.test.ts Outdated
Comment thread test/js/sql/ssl-postgres-behavior-verification.test.ts
Comment thread test/js/sql/ssl-postgres-behavior-verification.test.ts
@coderabbitai

coderabbitai Bot commented Jan 31, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@S4N-T0S
S4N-T0S requested a review from cirospaciari January 31, 2026 19:17
@S4N-T0S S4N-T0S changed the title fix(sql): TypeError tls must be a boolean or an object + more fix(sql): TypeError tls must be a boolean or an object + fix SSL/TLS behaviour to match postgres.js standard Jan 31, 2026

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/js/internal/sql/shared.ts`:
- Around line 660-668: The code currently overrides an explicit options.tls ===
false when sslMode is derived from URL/env; change the logic so that an explicit
options.tls === false is honored (or surfaces a conflict) before the defaulting
that sets tls = true: detect options.tls === false and either (a) set tls =
false and skip the later sslMode !== SSLMode.disable && !tls block, or (b) if
sslMode requires TLS (e.g., SSLMode.require), throw a clear error about the
conflicting settings; update the branches around sslMode, options.tls, and tls
(the variables named sslMode, options.tls, and tls) so explicit user TLS choice
wins or surfaces a conflict immediately.

Comment thread src/js/internal/sql/shared.ts Outdated
@S4N-T0S
S4N-T0S requested a review from alii as a code owner January 31, 2026 19:59

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/bun-types/sql.d.ts (1)

326-336: ⚠️ Potential issue | 🟡 Minor

JSDoc defaults for tls/ssl are now misleading.

Runtime defaults now favor sslMode: "prefer" with TLS enabled when unspecified; the @default false and “alias for tls” wording no longer matches behavior or the new mode strings.

📝 Suggested doc update
-      /**
-       * Whether to use TLS/SSL for the connection
-       * `@default` false
-       */
+      /**
+       * TLS options or boolean toggle. If omitted, TLS is enabled by default
+       * when sslMode defaults to "prefer".
+       */
       tls?: Bun.BunFile | TLSOptions | boolean | undefined;

-      /**
-       * Whether to use TLS/SSL for the connection (alias for tls)
-       * `@deprecated` Prefer {`@link` tls}
-       * `@default` false
-       */
+      /**
+       * SSL mode string or TLS options. Supports "disable" | "prefer" | "require" | "verify-ca" | "verify-full".
+       * `@deprecated` Prefer {`@link` tls} for TLS options; use {`@link` ssl} for mode selection.
+       * `@default` "prefer"
+       */
       ssl?: Bun.BunFile | TLSOptions | boolean | "disable" | "prefer" | "require" | "verify-ca" | "verify-full" | undefined;
🤖 Fix all issues with AI agents
In `@src/js/internal/sql/shared.ts`:
- Around line 640-646: The guard `if (options.ssl)` ignores a boolean false and
so doesn't apply the override; change the presence check to test for undefined
(e.g. `if (options.ssl !== undefined)` or `if ("ssl" in options)`) so
`options.ssl === false` is handled, then keep the existing branches that call
`normalizeSSLMode(options.ssl)` for string and set `sslMode = options.ssl ?
SSLMode.prefer : SSLMode.disable` for boolean to ensure false disables TLS;
update the block around the `options.ssl` check that surrounds normalizeSSLMode,
SSLMode.prefer and SSLMode.disable accordingly.

Comment thread src/js/internal/sql/shared.ts

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/js/internal/sql/shared.ts`:
- Around line 660-668: When options.tls === false, don't unconditionally set
sslMode = SSLMode.disable; instead detect if an explicit ssl mode was provided
(i.e., options.ssl / sslMode was set to a non-default value like "require",
"verify-ca", "verify-full") and throw an argument conflict error referencing
"tls" vs "ssl"/sslMode; only downgrade sslMode to disable and set tls = false
when sslMode is still the default (e.g., SSLMode.prefer or undefined). Update
the logic around options.tls, options.ssl, and the sslMode variable to enforce
this conflict handling.

Comment thread src/js/internal/sql/shared.ts Outdated
…, throw error. Update comments, docs and test. +Ran the auto-formatter.

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/js/internal/sql/shared.ts`:
- Around line 682-690: The hostname-to-SNI injection currently skips IP literals
(require("node:net").isIP(hostname)), which breaks verify_full because later
verification (SSL_get_servername/verify_full) expects a serverName; either allow
injection when sslMode === SSLMode.verify_full or change the verification path
to fall back to the original hostname when SSL_get_servername is missing. Update
the injection block around sslMode/SSLMode.disable and tls to set tls.serverName
= hostname even for IPs when sslMode === SSLMode.verify_full (or alternatively
modify the verification routine to use the provided hostname when
SSL_get_servername returns null), referencing the sslMode/SSLMode.disable check,
tls variable, hostname, require("node:net").isIP, and the
verify_full/SSL_get_servername flow.

In `@src/sql/mysql/js/JSMySQLConnection.zig`:
- Around line 294-295: The onData handler (JSMySQLConnection.onData) currently
drops data when this.#connection.isProcessingData() is true; instead, append
incoming chunks to an internal buffer/queue and defer processing until current
work completes: add a per-connection buffer or queue (e.g., this.#pending_reads
or reuse this.#read_buffer) to store data in onData whenever isProcessingData()
is true, and when readAndProcessData() or the processing routine finishes, drain
that queue into readAndProcessData() (or invoke the normal processing path) so
no bytes are lost; reference JSMySQLConnection.onData,
JSMySQLConnection.readAndProcessData(), this.#read_buffer, and
this.#connection.isProcessingData() when implementing the buffering and drain
logic.

Comment thread src/js/internal/sql/shared.ts Outdated
Comment thread src/sql/mysql/js/JSMySQLConnection.zig Outdated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/js/internal/sql/shared.ts`:
- Around line 682-693: There's an extra closing brace causing a syntax error in
the SSL SNI/hostname injection block that uses sslMode, SSLMode, tls and
hostname; remove the stray `}` following that if-block so the braces balance
(ensure the conditional starting with `if (sslMode !== SSLMode.disable &&
!tls?.serverName && hostname) {` is closed exactly once and no additional `}`
remains).

Comment thread src/js/internal/sql/shared.ts Outdated
@coderabbitai

coderabbitai Bot commented Jan 31, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/sql/mysql/MySQLConnection.zig`:
- Around line 239-242: The current defer unconditionally resets
this.#flags.is_processing_data and can clear it when doHandshake runs nested;
modify the handshake entry to save the previous value (e.g., const prev =
this.#flags.is_processing_data), set this.#flags.is_processing_data = true only
if not already true, and in the defer restore it to prev (or only clear it if
prev was false). Apply this change around doHandshake and the surrounding write
block so re-entrant onData remains disabled unless the outer scope originally
left it enabled.

In `@test/js/sql/ssl-postgres-handshake.test.ts`:
- Around line 207-212: The test "Default (No Options) -> Prefer (SSLRequest ->
Fallback -> Startup)" contains a debug console.error(error) that pollutes CI
output; remove that call (or gate it behind a debug flag) inside the test so the
connect({}) result is still asserted but errors are not unconditionally logged.
Locate the test function and the connect invocation and either delete the
console.error(error) line or wrap it in a conditional debug check (e.g., if
(process.env.DEBUG) ...) around the console.error call.

Comment thread src/sql/mysql/MySQLConnection.zig
Comment thread test/js/sql/ssl-postgres-handshake.test.ts

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/sql/postgres/PostgresSQLConnection.zig`:
- Around line 413-435: The code redundantly resets flags.is_processing_data and
re-checks read_buffer.remaining() after calling startTLS and start, which
duplicates the outer defer logic; remove the explicit resets and onData calls
that follow this.startTLS(socket) and this.start() so the single defer (which
clears is_processing_data and invokes onData when needed) handles cleanup and
buffered-data processing; ensure you keep the early return after
this.startTLS(socket) but do not reset flags.is_processing_data or call
this.onData("") there—let the defer perform those actions for consistency with
the initial re-entrancy protection.

In `@test/js/sql/ssl-postgres-handshake.test.ts`:
- Around line 244-248: The test "TLS: true -> Acts as Prefer (Defaults)" lacks
an inline comment explaining why tls: true is expected to behave like SSL mode
"prefer"; add a short clarifying comment above the test or inside it stating
that when tls is set to true without an explicit sslMode the client defaults to
"prefer" behavior, so connect({ tls: true }) should emit ["SSLRequest",
"StartupMessage", "Query"] — reference the test block name, the connect function
call (connect({ tls: true })), and the events assertion
(expect(events).toEqual([...])) so readers understand the expected handshake
sequence.

Comment thread src/sql/postgres/PostgresSQLConnection.zig Outdated
Comment thread test/js/sql/ssl-postgres-handshake.test.ts
Comment thread src/js/internal/sql/shared.ts

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/js/internal/sql/shared.ts`:
- Around line 681-690: The serverName injection currently runs before hostname
defaults are applied, so when hostname falls back to a default (e.g.,
"localhost") serverName can remain unset and SSLMode.verify_full fails; move the
block that sets tls.serverName (the logic referencing sslMode,
SSLMode.verify_full, tls, and hostname) to after the code that resolves/defaults
hostname (or call the same injection logic again immediately after hostname is
resolved) so serverName is always populated when sslMode !== SSLMode.disable and
tls lacks serverName.

In `@src/sql/mysql/js/JSMySQLConnection.zig`:
- Around line 246-270: The code path handling a failed handshake in
JSMySQLConnection checks handshakeWasSuccessful and ultimately calls
this.failWithJSValue(ssl_error.toJS(...)) but does not return, allowing
subsequent processing on a closed/failed socket; update the logic in the
handshake failure block (the branch using ssl_error and calling
this.failWithJSValue) to return immediately after the this.failWithJSValue(...)
call to stop further post-failure processing and avoid using a failed
connection.

Comment thread src/js/internal/sql/shared.ts Outdated
Comment thread src/sql/mysql/js/JSMySQLConnection.zig
@coderabbitai

coderabbitai Bot commented Feb 1, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@S4N-T0S

S4N-T0S commented Mar 20, 2026

Copy link
Copy Markdown
Author

@alii @cirospaciari Please let me know what to do with this pull request, Bun without this pull request or other changes uses plaintext by default on communications with databases which is unheard of.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants