const DEFAULT_JWT_SECRET = 'default-jwt-secret'; const DEFAULT_REFRESH_SECRET = 'default-refresh-secret'; const DEFAULT_DB_PASSWORD = 'cloudhost_secret'; export function validateProductionConfig(): void { if (process.env.NODE_ENV !== 'production') { return; } const errors: string[] = []; const jwtSecret = process.env.JWT_SECRET || DEFAULT_JWT_SECRET; const refreshSecret = process.env.JWT_REFRESH_SECRET || DEFAULT_REFRESH_SECRET; const dbPassword = process.env.DB_PASSWORD || DEFAULT_DB_PASSWORD; if (!process.env.JWT_SECRET || jwtSecret === DEFAULT_JWT_SECRET) { errors.push('JWT_SECRET must be set to a strong random value in production'); } if (!process.env.JWT_REFRESH_SECRET || refreshSecret === DEFAULT_REFRESH_SECRET) { errors.push('JWT_REFRESH_SECRET must be set to a strong random value in production'); } if (!process.env.DB_PASSWORD || dbPassword === DEFAULT_DB_PASSWORD) { errors.push('DB_PASSWORD must be changed from the default in production'); } if (!process.env.CLUSTER_KUBECONFIG_KEY?.trim()) { errors.push('CLUSTER_KUBECONFIG_KEY must be set in production to encrypt stored kubeconfigs'); } // Elastic log-stack credentials must not fall back to the well-known dev defaults. const elasticDefaults = ['CloudHost2024!Secure', 'FluentBit2024!Writer', 'Kibana2024!System']; if (!process.env.ELASTIC_PASSWORD || elasticDefaults.includes(process.env.ELASTIC_PASSWORD)) { errors.push('ELASTIC_PASSWORD must be set to a strong random value in production'); } if (process.env.FLUENTBIT_PASSWORD && elasticDefaults.includes(process.env.FLUENTBIT_PASSWORD)) { errors.push('FLUENTBIT_PASSWORD must be changed from the default in production'); } if (errors.length > 0) { throw new Error( `Production configuration validation failed:\n${errors.map((e) => ` - ${e}`).join('\n')}`, ); } }