Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/utils/validateEnvVars.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,27 @@ const envVarsSchema = Joi.object({
CLUSTER_SHUTDOWN_TIMEOUT_MS: Joi.number().integer().min(1).optional(),
REDIS_URL: Joi.string().pattern(/^rediss?:\/\//).optional(),

// TLS certs are required in production
// Mirrors config/index.js: any value other than 'false' enables TLS.
TLS_ENABLED: Joi.string().valid('true', 'false').optional(),

// TLS certs are required in production unless TLS terminates at the platform
// edge (TLS_ENABLED=false), where startApplicationRuntime never loads them.
TLS_KEY: Joi.string().when('NODE_ENV', {
is: 'production',
then: Joi.required(),
then: Joi.when('TLS_ENABLED', {
is: 'false',
then: Joi.optional(),
otherwise: Joi.required(),
}),
otherwise: Joi.optional(),
}),
TLS_CERT: Joi.string().when('NODE_ENV', {
is: 'production',
then: Joi.required(),
then: Joi.when('TLS_ENABLED', {
is: 'false',
then: Joi.optional(),
otherwise: Joi.required(),
}),
otherwise: Joi.optional(),
}),
OUTBOUND_CA_BUNDLE_FILE: Joi.string().optional(),
Expand Down
80 changes: 80 additions & 0 deletions tests/unit/utils/validateEnvVars.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,92 @@ describe('Unit | Utils | Validate Env Vars', () => {
NODE_ENV: 'production',
REPLICATE_API_TOKEN: 'test-token',
},
remove: ['TLS_KEY', 'TLS_CERT', 'TLS_ENABLED'],
});

expect(() => validateEnvVars()).toThrow(/TLS_KEY/);
});

it('does not require production TLS credentials when TLS_ENABLED=false', () => {
const validateEnvVars = loadValidator({
overrides: {
NODE_ENV: 'production',
TLS_ENABLED: 'false',
REPLICATE_API_TOKEN: 'test-token',
},
remove: ['TLS_KEY', 'TLS_CERT'],
});

expect(() => validateEnvVars()).not.toThrow();
});

it('requires production TLS credentials when TLS_ENABLED=true', () => {
const validateEnvVars = loadValidator({
overrides: {
NODE_ENV: 'production',
TLS_ENABLED: 'true',
REPLICATE_API_TOKEN: 'test-token',
},
remove: ['TLS_KEY', 'TLS_CERT'],
});

expect(() => validateEnvVars()).toThrow(/TLS_KEY/);
});

it('requires TLS_CERT in production when only TLS_KEY is supplied', () => {
const validateEnvVars = loadValidator({
overrides: {
NODE_ENV: 'production',
REPLICATE_API_TOKEN: 'test-token',
TLS_KEY: 'tls-key',
},
remove: ['TLS_CERT', 'TLS_ENABLED'],
});

expect(() => validateEnvVars()).toThrow(/TLS_CERT/);
});

it('accepts TLS_ENABLED=false in production alongside unused TLS credentials', () => {
const validateEnvVars = loadValidator({
overrides: {
NODE_ENV: 'production',
TLS_ENABLED: 'false',
REPLICATE_API_TOKEN: 'test-token',
TLS_KEY: 'tls-key',
TLS_CERT: 'tls-cert',
},
});

expect(() => validateEnvVars()).not.toThrow();
});

it('rejects a TLS_ENABLED value other than true or false', () => {
const validateEnvVars = loadValidator({
overrides: {
NODE_ENV: 'production',
TLS_ENABLED: 'disabled',
REPLICATE_API_TOKEN: 'test-token',
TLS_KEY: 'tls-key',
TLS_CERT: 'tls-cert',
},
});

expect(() => validateEnvVars()).toThrow(/TLS_ENABLED/);
});

it('leaves TLS credentials optional outside production when TLS_ENABLED=true', () => {
const validateEnvVars = loadValidator({
overrides: {
NODE_ENV: 'development',
TLS_ENABLED: 'true',
REPLICATE_API_TOKEN: 'test-token',
},
remove: ['TLS_KEY', 'TLS_CERT'],
});

expect(() => validateEnvVars()).not.toThrow();
});

it('accepts a non-negative TRUST_PROXY_HOPS override', () => {
const validateEnvVars = loadValidator({
overrides: {
Expand Down
Loading