From 4f0b84272982b80fcd615fe9bdae12d528ed277a Mon Sep 17 00:00:00 2001 From: Gajus Date: Fri, 3 Jan 2025 11:31:40 -0600 Subject: [PATCH] test: add framework for testing ssl --- .../slonik/src/integration.test/ssl.test.ts | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 packages/slonik/src/integration.test/ssl.test.ts diff --git a/packages/slonik/src/integration.test/ssl.test.ts b/packages/slonik/src/integration.test/ssl.test.ts new file mode 100644 index 00000000..07801d9c --- /dev/null +++ b/packages/slonik/src/integration.test/ssl.test.ts @@ -0,0 +1,113 @@ +/* eslint-disable no-console */ + +import { createPool, sql } from '..'; +import test from 'ava'; +import getPort from 'get-port'; +import { execSync, spawn } from 'node:child_process'; +import { randomUUID } from 'node:crypto'; +import { setTimeout } from 'node:timers/promises'; + +export const startTestContainer = async () => { + const dockerContainerName = `slonik-test-${randomUUID()}`; + + const servicePort = await getPort(); + + const dockerArgs = [ + 'run', + '--name', + dockerContainerName, + '--rm', + '-e', + 'POSTGRES_HOST_AUTH_METHOD=trust', + '-p', + servicePort + ':5432', + // see packages/test-ssls/README.md + 'slonik-ssl-test', + '-N 1000', + ]; + + const dockerProcess = spawn('docker', dockerArgs); + + dockerProcess.on('error', (error) => { + console.error(error); + }); + + dockerProcess.stdout.on('data', (data) => { + console.log(data.toString()); + }); + + dockerProcess.stderr.on('data', (data) => { + console.error(data.toString()); + }); + + dockerProcess.on('exit', (code) => { + console.log(`Docker process exited with code ${code}`); + }); + + await new Promise((resolve) => { + dockerProcess.stdout.on('data', (data) => { + if ( + data + .toString() + .includes('database system is ready to accept connections') + ) { + resolve(undefined); + } + }); + }); + + await setTimeout(1_000); + + const terminate = () => { + execSync(`docker kill ${dockerContainerName}`); + }; + + return { + servicePort, + terminate, + }; +}; + +test('makes a connection using SSL', async (t) => { + const { servicePort, terminate } = await startTestContainer(); + + try { + const searchParameters = new URLSearchParams(); + + // TODO figure out how to test sslmode=require + // We are now getting an error: SELF_SIGNED_CERT_IN_CHAIN + searchParameters.set('sslmode', 'no-verify'); + + searchParameters.set( + 'sslrootcert', + require.resolve('@slonik/test-ssls/root.crt'), + ); + searchParameters.set( + 'sslcert', + require.resolve('@slonik/test-ssls/slonik.crt'), + ); + searchParameters.set( + 'sslkey', + require.resolve('@slonik/test-ssls/slonik.key'), + ); + + const pool = await createPool( + `postgresql://postgres@localhost:${servicePort}/postgres?${searchParameters}`, + ); + + const result = await pool.one(sql.unsafe` + SELECT ssl + FROM pg_stat_ssl + JOIN pg_stat_activity + ON pg_stat_ssl.pid = pg_stat_activity.pid; + `); + + t.deepEqual(result, { + ssl: true, + }); + + await pool.end(); + } finally { + terminate(); + } +});