179 lines
4.3 KiB
TypeScript
179 lines
4.3 KiB
TypeScript
#!/usr/bin/env ts-node
|
|
/**
|
|
* Environment Variables Validation Script
|
|
*
|
|
* Validates that all required environment variables are set
|
|
* before deployment to production.
|
|
*
|
|
* Usage:
|
|
* ts-node scripts/validate-env.ts
|
|
* or
|
|
* npm run validate:env
|
|
*/
|
|
|
|
// Load environment variables from .env file
|
|
const dotenv = require('dotenv');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
// Try to load .env file
|
|
const envPath = path.resolve(process.cwd(), '.env');
|
|
if (fs.existsSync(envPath)) {
|
|
dotenv.config({ path: envPath });
|
|
console.log(`✅ Loaded environment variables from ${envPath}\n`);
|
|
} else {
|
|
console.warn(`⚠️ Warning: .env file not found at ${envPath}`);
|
|
console.warn(' Trying to load from process.env only...\n');
|
|
// Still try to load from current directory
|
|
dotenv.config();
|
|
}
|
|
|
|
const requiredVars = [
|
|
// Core
|
|
'DATABASE_URL',
|
|
'NEXTAUTH_URL',
|
|
'NEXTAUTH_SECRET',
|
|
|
|
// Keycloak
|
|
'KEYCLOAK_BASE_URL',
|
|
'KEYCLOAK_REALM',
|
|
'KEYCLOAK_CLIENT_ID',
|
|
'KEYCLOAK_CLIENT_SECRET',
|
|
'KEYCLOAK_ISSUER',
|
|
'NEXT_PUBLIC_KEYCLOAK_ISSUER',
|
|
];
|
|
|
|
const optionalButRecommended = [
|
|
// Redis
|
|
'REDIS_HOST',
|
|
'REDIS_PORT',
|
|
'REDIS_PASSWORD',
|
|
|
|
// External Services
|
|
'N8N_API_KEY',
|
|
'N8N_WEBHOOK_URL',
|
|
'LEANTIME_API_URL',
|
|
'LEANTIME_TOKEN',
|
|
'ROCKET_CHAT_TOKEN',
|
|
'ROCKET_CHAT_USER_ID',
|
|
];
|
|
|
|
interface ValidationResult {
|
|
valid: boolean;
|
|
missing: string[];
|
|
warnings: string[];
|
|
errors: string[];
|
|
}
|
|
|
|
function validateEnvironment(): ValidationResult {
|
|
const result: ValidationResult = {
|
|
valid: true,
|
|
missing: [],
|
|
warnings: [],
|
|
errors: [],
|
|
};
|
|
|
|
// Check required variables
|
|
for (const varName of requiredVars) {
|
|
const value = process.env[varName];
|
|
if (!value || value.trim() === '') {
|
|
result.missing.push(varName);
|
|
result.valid = false;
|
|
}
|
|
}
|
|
|
|
// Check optional but recommended
|
|
for (const varName of optionalButRecommended) {
|
|
const value = process.env[varName];
|
|
if (!value || value.trim() === '') {
|
|
result.warnings.push(varName);
|
|
}
|
|
}
|
|
|
|
// Validate DATABASE_URL format
|
|
const dbUrl = process.env.DATABASE_URL;
|
|
if (dbUrl) {
|
|
if (!dbUrl.startsWith('postgresql://') && !dbUrl.startsWith('postgres://')) {
|
|
result.errors.push('DATABASE_URL must start with postgresql:// or postgres://');
|
|
result.valid = false;
|
|
}
|
|
|
|
// Check for connection pool parameters
|
|
if (!dbUrl.includes('connection_limit')) {
|
|
result.warnings.push(
|
|
'DATABASE_URL should include connection_limit parameter (e.g., ?connection_limit=10&pool_timeout=20)'
|
|
);
|
|
}
|
|
}
|
|
|
|
// Validate NEXTAUTH_SECRET strength
|
|
const nextAuthSecret = process.env.NEXTAUTH_SECRET;
|
|
if (nextAuthSecret && nextAuthSecret.length < 32) {
|
|
result.warnings.push('NEXTAUTH_SECRET should be at least 32 characters long');
|
|
}
|
|
|
|
// Validate URLs
|
|
const urlVars = ['NEXTAUTH_URL', 'KEYCLOAK_BASE_URL', 'NEXT_PUBLIC_KEYCLOAK_ISSUER'];
|
|
for (const varName of urlVars) {
|
|
const value = process.env[varName];
|
|
if (value) {
|
|
try {
|
|
new URL(value);
|
|
} catch {
|
|
result.errors.push(`${varName} is not a valid URL: ${value}`);
|
|
result.valid = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function main() {
|
|
console.log('🔍 Validating environment variables...\n');
|
|
|
|
const result = validateEnvironment();
|
|
|
|
if (result.missing.length > 0) {
|
|
console.error('❌ Missing required environment variables:');
|
|
result.missing.forEach((varName) => {
|
|
console.error(` - ${varName}`);
|
|
});
|
|
console.error('');
|
|
}
|
|
|
|
if (result.errors.length > 0) {
|
|
console.error('❌ Validation errors:');
|
|
result.errors.forEach((error) => {
|
|
console.error(` - ${error}`);
|
|
});
|
|
console.error('');
|
|
}
|
|
|
|
if (result.warnings.length > 0) {
|
|
console.warn('⚠️ Warnings:');
|
|
result.warnings.forEach((warning) => {
|
|
console.warn(` - ${warning}`);
|
|
});
|
|
console.warn('');
|
|
}
|
|
|
|
if (result.valid) {
|
|
console.log('✅ All required environment variables are set!\n');
|
|
if (result.warnings.length > 0) {
|
|
console.log('⚠️ Some optional variables are missing, but deployment can proceed.\n');
|
|
}
|
|
process.exit(0);
|
|
} else {
|
|
console.error('❌ Environment validation failed!\n');
|
|
console.error('Please set all required variables before deploying.\n');
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (require.main === module) {
|
|
main();
|
|
}
|
|
|
|
export { validateEnvironment };
|