diff --git a/src/router/worker-env.ts b/src/router/worker-env.ts index 6422c240..c17d2fdc 100644 --- a/src/router/worker-env.ts +++ b/src/router/worker-env.ts @@ -50,6 +50,30 @@ export async function buildWorkerEnv(job: Job): Promise { return buildWorkerEnvWithProjectId(job, projectId); } +/** + * Append optional infrastructure env vars that are conditionally forwarded to workers. + * Extracted to keep buildWorkerEnvWithProjectId within complexity limits. + */ +function appendOptionalEnvVars(env: string[]): void { + // Forward DB SSL config so workers use the same TLS settings as the router. + if (process.env.DATABASE_SSL) env.push(`DATABASE_SSL=${process.env.DATABASE_SSL}`); + if (process.env.DATABASE_CA_CERT) env.push(`DATABASE_CA_CERT=${process.env.DATABASE_CA_CERT}`); + + // CLAUDE_CODE_OAUTH_TOKEN is for the Claude Code backend (subscription auth). + if (process.env.CLAUDE_CODE_OAUTH_TOKEN) + env.push(`CLAUDE_CODE_OAUTH_TOKEN=${process.env.CLAUDE_CODE_OAUTH_TOKEN}`); + + // Forward Sentry env vars so worker containers report to the same project. + if (process.env.SENTRY_DSN) env.push(`SENTRY_DSN=${process.env.SENTRY_DSN}`); + if (process.env.SENTRY_ENVIRONMENT) + env.push(`SENTRY_ENVIRONMENT=${process.env.SENTRY_ENVIRONMENT}`); + if (process.env.SENTRY_RELEASE) env.push(`SENTRY_RELEASE=${process.env.SENTRY_RELEASE}`); + + // Forward dashboard URL so worker progress comments can include run links. + if (process.env.CASCADE_DASHBOARD_URL) + env.push(`CASCADE_DASHBOARD_URL=${process.env.CASCADE_DASHBOARD_URL}`); +} + /** * Build environment variables for a worker container with a pre-resolved projectId. * @internal Used by container-manager.ts to avoid resolving projectId twice. @@ -95,19 +119,7 @@ export async function buildWorkerEnvWithProjectId( } } - // CLAUDE_CODE_OAUTH_TOKEN is for the Claude Code backend (subscription auth). - if (process.env.CLAUDE_CODE_OAUTH_TOKEN) - env.push(`CLAUDE_CODE_OAUTH_TOKEN=${process.env.CLAUDE_CODE_OAUTH_TOKEN}`); - - // Forward Sentry env vars so worker containers report to the same project. - if (process.env.SENTRY_DSN) env.push(`SENTRY_DSN=${process.env.SENTRY_DSN}`); - if (process.env.SENTRY_ENVIRONMENT) - env.push(`SENTRY_ENVIRONMENT=${process.env.SENTRY_ENVIRONMENT}`); - if (process.env.SENTRY_RELEASE) env.push(`SENTRY_RELEASE=${process.env.SENTRY_RELEASE}`); - - // Forward dashboard URL so worker progress comments can include run links. - if (process.env.CASCADE_DASHBOARD_URL) - env.push(`CASCADE_DASHBOARD_URL=${process.env.CASCADE_DASHBOARD_URL}`); + appendOptionalEnvVars(env); return env; } diff --git a/tests/unit/router/worker-env.test.ts b/tests/unit/router/worker-env.test.ts index 8adb5a91..ce02f462 100644 --- a/tests/unit/router/worker-env.test.ts +++ b/tests/unit/router/worker-env.test.ts @@ -168,6 +168,32 @@ describe('buildWorkerEnv', () => { const env = await buildWorkerEnv(makeJob() as never); expect(env).toContain('REDIS_URL=redis://localhost:6379'); }); + + it('forwards DATABASE_SSL when set', async () => { + process.env.DATABASE_SSL = 'false'; + try { + const env = await buildWorkerEnv(makeJob() as never); + expect(env).toContain('DATABASE_SSL=false'); + } finally { + Reflect.deleteProperty(process.env, 'DATABASE_SSL'); + } + }); + + it('omits DATABASE_SSL when not set', async () => { + Reflect.deleteProperty(process.env, 'DATABASE_SSL'); + const env = await buildWorkerEnv(makeJob() as never); + expect(env.some((e) => e.startsWith('DATABASE_SSL='))).toBe(false); + }); + + it('forwards DATABASE_CA_CERT when set', async () => { + process.env.DATABASE_CA_CERT = '/etc/ssl/certs/rds-ca.pem'; + try { + const env = await buildWorkerEnv(makeJob() as never); + expect(env).toContain('DATABASE_CA_CERT=/etc/ssl/certs/rds-ca.pem'); + } finally { + Reflect.deleteProperty(process.env, 'DATABASE_CA_CERT'); + } + }); }); // ---------------------------------------------------------------------------