fix(cli): treat only verifying sslmodes as a local TLS demand (CLI-2366) - #6664
Merged
Merged
Conversation
Honoring an explicit `--db-url` TLS request against a loopback target keyed off any populated `sslmode`, which is not the same as the DSN asking for TLS. `prefer` and `allow` name a fallback libpq performs and `sslConfigsFor` does not, and `sslmode` is also filled from `PGSSLMODE` and libpq service files when the DSN omits it. A developer with `PGSSLMODE=prefer` exported, or a DSN carrying `?sslmode=prefer`, therefore lost the local plaintext exemption and failed the handshake against a plaintext Postgres — on the shared connection seam, so `db query`, dump and pull were affected as well as `gen types`. Only `require`, `verify-ca`, `verify-full` or a supplied root cert now count as a demand. A TLS tunnel on loopback keeps working, and a local target that names nothing, `prefer`, `allow` or `disable` connects in plaintext as before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4 tasks
Contributor
There was a problem hiding this comment.
🤖 AI Review
Both independent reviews completed. The core fix addresses ambient PGSSLMODE=prefer, but its provenance-blind mode check causes a major regression for explicitly configured local prefer/allow connections and leaves the analogous ambient PGSSLROOTCERT problem. Six findings are confirmed; the import-order nit is refuted because no trusted convention requires that ordering.
Findings
| Severity | Location | Category | Sources | Claim |
|---|---|---|---|---|
| 🟠 MAJOR | apps/cli/src/command-internal/db-connection.sql-pg.layer.ts:415 |
tls-semantics |
claude+codex | Treating local sslmode=prefer and sslmode=allow as non-TLS-demanding makes explicitly configured local targets plaintext-only, breaking TLS-only loopback endpoints and suppressing allow's implemented plaintext-then-TLS fallback. |
| 🟡 MINOR | apps/cli/src/command-internal/db-connection.sql-pg.layer.ts:416 |
correctness |
claude | An ambient PGSSLROOTCERT still makes a bare local connection demand TLS, despite sslrootcert having the same environment/service provenance ambiguity used to justify discounting ambient sslmode. |
| ⚪ NIT | apps/cli/src/command-internal/db-connection.sql-pg.integration.test.ts:913 |
test-quality |
claude | The new allow integration test cannot validate the PR's changed allow classification because the same plaintext-server assertion passes before and after the change, and its title incorrectly says sslConfigsFor does not implement allow's fallback. |
| ⚪ NIT | apps/cli/src/command-internal/db-connection.sql-pg.unit.test.ts:283 |
comments |
claude+codex | The new test title/comments falsely state that sslConfigsFor never performs allow's fallback, and the comments add narration and ticket-provenance language contrary to trusted repository guidance. |
| ⚪ NIT | apps/cli/src/command-internal/db-connection.sql-pg.unit.test.ts:308 |
test-quality |
claude | The verify-full environment test dereferences the optional parser result without first asserting successful parsing, so parser failures produce an unhelpful runtime error. |
| ⚪ NIT | apps/cli/src/command-internal/db-connection.sql-pg.layer.ts:468 |
documentation |
claude | The sslConfigsFor documentation still says every explicitly set sslmode removes the local TLS exemption, which is no longer true for prefer, allow, or disable. |
Findings outside the diff
- ⚪ NIT
apps/cli/src/command-internal/db-connection.sql-pg.layer.ts:468— The sslConfigsFor documentation still says every explicitly set sslmode removes the local TLS exemption, which is no longer true for prefer, allow, or disable.
Refuted findings (kept for transparency, not posted as review comments)
apps/cli/src/command-internal/db-connection.sql-pg.unit.test.ts:28(style): The new relative import violates the repository's alphabetical import ordering convention.
Refuted: Neither trusted/CLAUDE.md nor trusted/apps/cli/CLAUDE.md requires alphabetical import paths, and the trusted baseline of this same file already places db-connection.sql-pg.layer.ts before db-connection.service.ts, which is itself non-alphabetical. The cited ordering therefore is not an established repository convention.
Stats
Claude findings: 7 · Codex findings: 2 · Confirmed: 6 · Refuted: 1 · Uncertain: 0
Models: claude-opus-5 + gpt-5.6-sol · Trigger: auto · Workflow run
This review runs once per PR. A maintainer can request another with a /ai-review comment.
avallete
approved these changes
Sep 17, 2026
…rget (CLI-2366) Review follow-up on #6664: narrowing tlsExplicitlyRequested to drop ambient sslmode=allow/prefer as a TLS demand also silently dropped allow's own plaintext-then-TLS fallback for local-classified targets, since sslConfigsFor's isLocal short-circuit ran before the allow branch. allow's fallback is safe regardless of isLocal — its first attempt is already plaintext — so it now bypasses that exemption instead of being collapsed to plaintext-only. Also corrects test titles/comments that claimed sslConfigsFor never implements allow's fallback, and adds a missing parse-success assertion before a non-null dereference. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Summary
Follow-up to #6652, addressing @avallete's post-merge review
(review).
#6652 stopped
sslConfigsForfrom silently downgrading an explicitsslmode=require/verify-fullto plaintext on a target classified local. The predicate it introduced was too broad:it treated any populated
sslmodeas a TLS demand.That is not the same as the DSN asking for TLS:
preferandallowname a TLS/plaintext fallback that libpq performs andsslConfigsFordeliberately does not — it maps
preferand unset to TLS-only. Local classification used to forceplaintext before that mapping ran, so reading
preferas a demand turns a plaintext-capabletarget into a handshake failure.
sslmodeis also filled fromPGSSLMODEand libpq service files when the DSN omits it, so amerely present value can come from the environment rather than the connection string.
The result was a regression on the shared
DbConnectionseam: a developer withPGSSLMODE=preferexported, or a DSN carrying
?sslmode=prefer, could no longer reach a local plaintext Postgres —affecting
db query --db-url, dump and pull as well asgen types.Only
require,verify-ca,verify-full, or a suppliedsslrootcert/ inline CA now count as ademand.
Verified against a plaintext Postgres on the local-classified port
developPGSSLMODE=preferPGSSLMODE=allow?sslmode=prefer?sslmode=disable?sslmode=requirePGSSLMODE=verify-fullThe TLS-tunnel behaviour #6652 set out to fix is unchanged: an explicit demand still puts an
SSLRequest on the wire against a loopback target, and a supplied root cert still opens the CA gate.
Coverage is behavioural rather than shape-only — the integration tests assert whether an SSLRequest
actually reaches a fake Postgres server, and a unit test composes the real DSN parser with the
predicate so the
PGSSLMODE-filled case is covered end to end rather than assumed.Linked issue
Follow-up to CLI-2366 (no GitHub issue).
open-for-contributionlabel (or I'm a Supabase maintainer).Checklist
fix(cli): …).pnpm check:allpasses; relevant package tests pass for every touched workspace, andpnpm types:checkpasses for each touched TypeScript workspace (or workspace declaring it).🤖 Generated with Claude Code