From 8a7e17cc43a8f03400a98c69a438dc377a54c743 Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:47:07 +0800 Subject: [PATCH] fix: inherit postgres sslmode from project db url (#2191) --- internal/db/runtime-store.test.ts | 18 ++++++++++++++++++ internal/db/runtime-store.ts | 15 +++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/internal/db/runtime-store.test.ts b/internal/db/runtime-store.test.ts index 535cbc93..429f6762 100644 --- a/internal/db/runtime-store.test.ts +++ b/internal/db/runtime-store.test.ts @@ -223,6 +223,24 @@ test("postgres pool config makes HWLAB_CLOUD_DB_SSL_MODE authoritative over URL assert.equal(new URL(required.connectionString).searchParams.get("uselibpqcompat"), "true"); }); +test("postgres pool config inherits URL sslmode when env override is absent", () => { + const disabled = buildPostgresPoolConfig({ + dbUrl: "postgres://hwlab_user:fixture-pass@db.example.test:5432/hwlab?sslmode=disable&application_name=hwlab" + }); + + assert.equal(disabled.ssl, false); + const disabledUrl = new URL(disabled.connectionString); + assert.equal(disabledUrl.searchParams.get("sslmode"), null); + assert.equal(disabledUrl.searchParams.get("application_name"), "hwlab"); + + const required = buildPostgresPoolConfig({ + dbUrl: "postgres://hwlab_user:fixture-pass@db.example.test:5432/hwlab?sslmode=require" + }); + + assert.deepEqual(required.ssl, { rejectUnauthorized: false }); + assert.equal(new URL(required.connectionString).searchParams.get("sslmode"), "require"); +}); + test("configured postgres runtime passes normalized pool config to pg", async () => { const pools = []; const store = createConfiguredCloudRuntimeStore({ diff --git a/internal/db/runtime-store.ts b/internal/db/runtime-store.ts index 3ec4048d..88eaf41a 100644 --- a/internal/db/runtime-store.ts +++ b/internal/db/runtime-store.ts @@ -120,8 +120,8 @@ export function createConfiguredCloudRuntimeStore(options = {}) { return createCloudRuntimeStore(options); } -export function buildPostgresPoolConfig({ dbUrl, sslMode = "require", timeoutMs, poolMax, queryTimeoutMs } = {}) { - const normalizedSslMode = normalizePostgresSslMode(sslMode); +export function buildPostgresPoolConfig({ dbUrl, sslMode, timeoutMs, poolMax, queryTimeoutMs } = {}) { + const normalizedSslMode = normalizePostgresSslMode(sslMode ?? postgresSslModeFromConnectionString(dbUrl)); const normalizedPoolMax = normalizeRuntimePoolMax(poolMax); const normalizedQueryTimeoutMs = queryTimeoutMs === undefined || queryTimeoutMs === null || String(queryTimeoutMs).trim() === "" ? null @@ -2999,6 +2999,17 @@ function normalizePostgresSslMode(value) { return "require"; } +function postgresSslModeFromConnectionString(dbUrl) { + if (typeof dbUrl !== "string" || dbUrl.trim() === "") return undefined; + try { + const url = new URL(dbUrl); + if (!["postgres:", "postgresql:"].includes(url.protocol)) return undefined; + return url.searchParams.get("sslmode") ?? url.searchParams.get("ssl") ?? undefined; + } catch { + return undefined; + } +} + function postgresSslOption(sslMode) { return sslMode === "disable" ? false : { rejectUnauthorized: false }; }