import { readFileSync } from "fs";
import {
PsqlSSLEnvConfig,
SSLConfig,
sslConfigFromCoCalcEnv,
sslConfigToPsqlEnv,
} from "./data";
enum TestString {
SSL="tRuE",
SSL_CA_FILE="test_ca_path",
SSL_CLIENT_CERT_FILE="test_client_cert",
SSL_CLIENT_KEY_FILE="test_client_key",
SSL_CLIENT_KEY_PASSPHRASE="test_client_key_passphrase",
}
const mockFileContents = {
[TestString.SSL_CA_FILE]: "ca-file-stuff",
[TestString.SSL_CLIENT_CERT_FILE]: "client-cert-file-stuff",
[TestString.SSL_CLIENT_KEY_FILE]: "client-key-file-stuff",
}
jest.mock("fs");
const mockReadFileSync = jest.mocked(readFileSync);
describe("#sslConfigFromCoCalcEnv", () => {
beforeEach(() => {
mockReadFileSync.mockImplementation((fileName) => mockFileContents[fileName as TestString]);
});
afterEach(() => {
mockReadFileSync.mockClear();
});
it("returns false when provided empty configuration", async () => {
const expected = false;
const pgssl = sslConfigFromCoCalcEnv();
expect(pgssl).toEqual<SSLConfig>(expected);
});
it("returns true when SMC_DB_SSL field is not true (case insensitive)", async () => {
const expected = true;
const pgssl = sslConfigFromCoCalcEnv({
SMC_DB_SSL: TestString.SSL,
});
expect(pgssl).toEqual<SSLConfig>(expected);
});
it("returns false when SMC_DB_SSL field is not 'true' and no other configuration is provided", () => {
const expected = false;
const pgssl = sslConfigFromCoCalcEnv({
SMC_DB_SSL: `!${TestString.SSL}`,
});
expect(pgssl).toEqual<SSLConfig>(expected);
});
it("sets SSL config fields when provided", async () => {
const expected = {
caFile: TestString.SSL_CA_FILE,
ca: mockFileContents[TestString.SSL_CA_FILE],
clientCertFile: TestString.SSL_CLIENT_CERT_FILE,
cert: mockFileContents[TestString.SSL_CLIENT_CERT_FILE],
clientKeyFile: TestString.SSL_CLIENT_KEY_FILE,
key: mockFileContents[TestString.SSL_CLIENT_KEY_FILE],
passphrase: TestString.SSL_CLIENT_KEY_PASSPHRASE,
};
const pgssl = sslConfigFromCoCalcEnv({
SMC_DB_SSL_CA_FILE: TestString.SSL_CA_FILE,
SMC_DB_SSL_CLIENT_CERT_FILE: TestString.SSL_CLIENT_CERT_FILE,
SMC_DB_SSL_CLIENT_KEY_FILE: TestString.SSL_CLIENT_KEY_FILE,
SMC_DB_SSL_CLIENT_KEY_PASSPHRASE: TestString.SSL_CLIENT_KEY_PASSPHRASE,
})
expect(pgssl).toEqual<SSLConfig>(expected);
});
it("ignores 'enabled' config field when other params are provided", async () => {
const expected = {
caFile: TestString.SSL_CA_FILE,
ca: mockFileContents[TestString.SSL_CA_FILE],
};
const pgssl = sslConfigFromCoCalcEnv({
SMC_DB_SSL: `!${TestString.SSL}`,
SMC_DB_SSL_CA_FILE: TestString.SSL_CA_FILE,
});
expect(pgssl).toEqual<SSLConfig>(expected);
});
it("reads SSL config fields from process.env by default", async () => {
const expected = {
caFile: TestString.SSL_CA_FILE,
ca: mockFileContents[TestString.SSL_CA_FILE],
clientCertFile: TestString.SSL_CLIENT_CERT_FILE,
cert: mockFileContents[TestString.SSL_CLIENT_CERT_FILE],
clientKeyFile: TestString.SSL_CLIENT_KEY_FILE,
key: mockFileContents[TestString.SSL_CLIENT_KEY_FILE],
passphrase: TestString.SSL_CLIENT_KEY_PASSPHRASE,
};
process.env = {
SMC_DB_SSL_CA_FILE: TestString.SSL_CA_FILE,
SMC_DB_SSL_CLIENT_CERT_FILE: TestString.SSL_CLIENT_CERT_FILE,
SMC_DB_SSL_CLIENT_KEY_FILE: TestString.SSL_CLIENT_KEY_FILE,
SMC_DB_SSL_CLIENT_KEY_PASSPHRASE: TestString.SSL_CLIENT_KEY_PASSPHRASE,
}
const pgssl = sslConfigFromCoCalcEnv();
expect(pgssl).toEqual<SSLConfig>(expected);
});
it("throws error when CA cert file cannot be read", async () => {
const readError = new Error("dude where's my ca file");
mockReadFileSync.mockImplementation(() => {
throw readError;
});
expect(() => sslConfigFromCoCalcEnv({
SMC_DB_SSL_CA_FILE: TestString.SSL_CA_FILE,
})).toThrow(readError);
});
it("throws error when client cert file cannot be read", async () => {
const readError = new Error("dude where's my cert file");
mockReadFileSync.mockImplementation(() => {
throw readError;
});
expect(() => sslConfigFromCoCalcEnv({
SMC_DB_SSL_CLIENT_CERT_FILE: TestString.SSL_CLIENT_CERT_FILE,
})).toThrow(readError);
});
it("throws error when client key file cannot be read", async () => {
const readError = new Error("dude where's my key file");
mockReadFileSync.mockImplementation(() => {
throw readError;
});
expect(() => sslConfigFromCoCalcEnv({
SMC_DB_SSL_CLIENT_KEY_FILE: TestString.SSL_CLIENT_KEY_FILE,
})).toThrow(readError);
});
});
describe("#sslConfigToPsqlEnv", () => {
it("returns empty object when provided config is undefined", async () => {
const expected: PsqlSSLEnvConfig = {};
const env = sslConfigToPsqlEnv(undefined);
expect(env).toEqual<PsqlSSLEnvConfig>(expected);
});
it("returns empty object when provided config is false", async () => {
const expected: PsqlSSLEnvConfig = {};
const env = sslConfigToPsqlEnv(false);
expect(env).toEqual<PsqlSSLEnvConfig>(expected);
});
it("configures SSL mode to require when provided config is true", async () => {
const expected: PsqlSSLEnvConfig = {
PGSSLMODE: "require",
};
const env = sslConfigToPsqlEnv(true);
expect(env).toEqual<PsqlSSLEnvConfig>(expected);
});
it("validates against the system cert store when provided empty configuration", async () => {
const expected: PsqlSSLEnvConfig = {
PGSSLMODE: "verify-full",
PGSSLROOTCERT: "system",
};
const env = sslConfigToPsqlEnv({});
expect(env).toEqual<PsqlSSLEnvConfig>(expected);
});
it("validates against a custom certificate authority when provided", async () => {
const expected: PsqlSSLEnvConfig = {
PGSSLMODE: "verify-full",
PGSSLROOTCERT: TestString.SSL_CA_FILE,
};
const env = sslConfigToPsqlEnv({
caFile: TestString.SSL_CA_FILE,
});
expect(env).toEqual<PsqlSSLEnvConfig>(expected);
});
it("uses a client cert when provided", async () => {
const expected: PsqlSSLEnvConfig = {
PGSSLMODE: "verify-full",
PGSSLROOTCERT: "system",
PGSSLCERT: TestString.SSL_CLIENT_CERT_FILE,
};
const env = sslConfigToPsqlEnv({
clientCertFile: TestString.SSL_CLIENT_CERT_FILE,
});
expect(env).toEqual<PsqlSSLEnvConfig>(expected);
});
it("uses a client key when provided", async () => {
const expected: PsqlSSLEnvConfig = {
PGSSLMODE: "verify-full",
PGSSLROOTCERT: "system",
PGSSLKEY: TestString.SSL_CLIENT_KEY_FILE,
};
const env = sslConfigToPsqlEnv({
clientKeyFile: TestString.SSL_CLIENT_KEY_FILE,
});
expect(env).toEqual<PsqlSSLEnvConfig>(expected);
});
});