From ace000034982a05d33c4662d1602815abe0088ce Mon Sep 17 00:00:00 2001 From: admin-valentin Date: Fri, 31 Jul 2026 14:57:01 +0000 Subject: [PATCH] fix(security): startup env validation + CORS origin filter (SEC-012/F6) --- src/main.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index 0542ad6..0e9926c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,7 +6,26 @@ import { Logger } from 'nestjs-pino'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { AppModule } from './app.module'; +const REQUIRED_ENV_VARS = [ + 'DATABASE_URL', + 'REDIS_URL', + 'SUPABASE_URL', + 'SUPABASE_SERVICE_ROLE_KEY', +] as const; + +function validateEnv(): void { + const missing = REQUIRED_ENV_VARS.filter((key) => !process.env[key]); + if (missing.length > 0) { + throw new Error(`Missing required environment variables: ${missing.join(', ')}`); + } + if (!process.env.SUPABASE_JWT_SECRET) { + console.warn('[WARN] SUPABASE_JWT_SECRET not set — JWT verification will use GoTrue round-trip'); + } +} + async function bootstrap() { + validateEnv(); + const app = await NestFactory.create(AppModule, { bufferLogs: true }); app.useLogger(app.get(Logger)); app.use(helmet()); @@ -14,13 +33,16 @@ async function bootstrap() { app.useGlobalPipes( new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true }), ); - const allowedOrigins = (process.env.CORS_ORIGINS ?? 'http://localhost:3000').split(',').map((o) => o.trim()); + + const rawOrigins = process.env.CORS_ORIGINS ?? 'http://localhost:3000'; + const allowedOrigins = rawOrigins.split(',').map((o) => o.trim()).filter(Boolean); app.enableCors({ origin: allowedOrigins, credentials: true }); if (process.env.SWAGGER_ENABLED === 'true') { const config = new DocumentBuilder() .setTitle('CEO OS API') .setVersion('0.1.0') + .addBearerAuth() .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('docs', app, document);