From 8caef0a09b5ecc9eb84c3b1d28bb596ce53a53a2 Mon Sep 17 00:00:00 2001 From: Sehrope Sarkuni Date: Thu, 18 Jun 2026 11:43:49 -0400 Subject: [PATCH 1/3] Remove unused os block from GHA CI matrix --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a266291d..a09a66bd3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,8 +44,6 @@ jobs: - '22' - '24' - '26' - os: - - ubuntu-latest name: Node.js ${{ matrix.node }} runs-on: ubuntu-latest env: From 7c551b9e54c7304a402a12dde244aa8a0ac6ee5d Mon Sep 17 00:00:00 2001 From: Sehrope Sarkuni Date: Thu, 18 Jun 2026 11:45:56 -0400 Subject: [PATCH 2/3] Add historical postgres versions to GHA test matrix Adds testing of historical postgres versions from 13 to 18 to the GitHub Actions CI matrix. They are each tested with the latest node version. Older node versions are only tested against the latest postgresql server version. Both the stable server version and latest node version are defined as YAML anchors to allow updating them in a single place in the future. For v18+ the container requires an explicit PGDATA directory parent path so we add that as well. This applies to older versions too but should not be an issue. --- .github/workflows/ci.yml | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a09a66bd3..6f0751c56 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,26 +25,39 @@ jobs: needs: lint services: postgres: - image: ghcr.io/railwayapp-templates/postgres-ssl + image: ghcr.io/railwayapp-templates/postgres-ssl:${{ matrix.postgres }} env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_HOST_AUTH_METHOD: 'md5' POSTGRES_DB: ci_db_test + # PostgreSQL 18's official image defaults PGDATA to a versioned + # subdirectory (/var/lib/postgresql/18/docker), but the + # railwayapp-templates/postgres-ssl entrypoint requires PGDATA to + # start with /var/lib/postgresql/data so we pin it explicitly. This is + # also the default for the older images, so it is a no-op there. + PGDATA: /var/lib/postgresql/data ports: - 5432:5432 options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 strategy: fail-fast: false matrix: - node: - - '16' - - '18' - - '20' - - '22' - - '24' - - '26' - name: Node.js ${{ matrix.node }} + include: + # Historical Node.js versions tested against a single PostgreSQL version + - { node: '16', postgres: &stable_postgres '18' } + - { node: '18', postgres: *stable_postgres } + - { node: '20', postgres: *stable_postgres } + - { node: '22', postgres: *stable_postgres } + - { node: '24', postgres: *stable_postgres } + # Latest Node.js version tested against multiple PostgreSQL versions + - { node: &latest_node '26', postgres: '13' } + - { node: *latest_node, postgres: '14' } + - { node: *latest_node, postgres: '15' } + - { node: *latest_node, postgres: '16' } + - { node: *latest_node, postgres: '17' } + - { node: *latest_node, postgres: '18' } + name: Node.js ${{ matrix.node }} x PostgreSQL ${{ matrix.postgres }} runs-on: ubuntu-latest env: PGUSER: postgres From 7edb090c9822eb66589c6a99c03d7bdd905937a5 Mon Sep 17 00:00:00 2001 From: Sehrope Sarkuni Date: Thu, 18 Jun 2026 14:41:45 -0400 Subject: [PATCH 3/3] Add direct SSL test that only runs against v17+ --- .../pg/test/integration/client/ssl-tests.js | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/packages/pg/test/integration/client/ssl-tests.js b/packages/pg/test/integration/client/ssl-tests.js index 33919cdf8..b5b32c5ba 100644 --- a/packages/pg/test/integration/client/ssl-tests.js +++ b/packages/pg/test/integration/client/ssl-tests.js @@ -22,3 +22,58 @@ suite.test('can connect with ssl', function (done) { }) ) }) + +async function getServerVersionNum() { + const client = new helper.pg.Client(helper.config) + await client.connect() + try { + const { + rows: [row], + } = await client.query('SHOW server_version_num') + return parseInt(row.server_version_num, 10) + } finally { + await client.end() + } +} + +// The native client forwards sslnegotiation=direct to libpq, whose support +// for direct SSL depends on the linked libpq version (17+) rather than on +// this library. It also does not expose the underlying TLS socket, so the +// direct-negotiation check below is impossible. So we only test the pure-JS client. +if (!helper.args.native) { + suite.test('can connect with direct SSL negotiation', async () => { + // Direct SSL negotiation (sslnegotiation=direct) is only supported by + // PostgreSQL 17 and newer servers. Probe the server version first and skip + // on older servers rather than failing the test. + const serverVersionNum = await getServerVersionNum() + if (serverVersionNum < 170000) { + console.log(`(skipped: direct SSL requires PostgreSQL 17+, server_version_num=${serverVersionNum}) `) + return + } + + const config = { + ...helper.config, + ssl: { rejectUnauthorized: false }, + sslnegotiation: 'direct', + } + const client = new helper.pg.Client(config) + await client.connect() + const { rows } = await client.query('SELECT NOW()') + assert.strictEqual(rows.length, 1) + + // Verify the connection actually used direct SSL negotiation rather than + // silently falling back to the traditional SSLRequest handshake. pg only + // sends the 'postgresql' ALPN protocol on a direct SSL handshake (see + // Connection#upgradeToSSL), and a PostgreSQL 17+ server echoes it back, so + // its presence on the negotiated TLS socket confirms direct negotiation. + const tlsSocket = client.connection.stream + assert.ok(tlsSocket.encrypted, 'expected the connection to be upgraded to a TLS socket') + assert.strictEqual( + tlsSocket.alpnProtocol, + 'postgresql', + 'expected direct SSL negotiation to select the "postgresql" ALPN protocol' + ) + + await client.end() + }) +}