All checks were successful
ci/woodpecker/push/api Pipeline was successful
Federation is optional and should not prevent the app from starting when DEFAULT_WORKSPACE_ID is not set. Changed from throwing (crash) to logging a warning. The endpoint-level validation in the controller still rejects requests when federation is unconfigured. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
108 lines
3.4 KiB
TypeScript
108 lines
3.4 KiB
TypeScript
/**
|
|
* Federation Module
|
|
*
|
|
* Provides instance identity and federation management with DoS protection via rate limiting.
|
|
* Issue #272: Rate limiting added to prevent DoS attacks on federation endpoints
|
|
* Issue #338: Validate DEFAULT_WORKSPACE_ID at startup
|
|
*/
|
|
|
|
import { Module, Logger, OnModuleInit } from "@nestjs/common";
|
|
import { ConfigModule } from "@nestjs/config";
|
|
import { HttpModule } from "@nestjs/axios";
|
|
import { ThrottlerModule } from "@nestjs/throttler";
|
|
import { FederationController } from "./federation.controller";
|
|
import { FederationAuthController } from "./federation-auth.controller";
|
|
import { FederationService } from "./federation.service";
|
|
import { CryptoService } from "./crypto.service";
|
|
import { FederationAuditService } from "./audit.service";
|
|
import { SignatureService } from "./signature.service";
|
|
import { ConnectionService } from "./connection.service";
|
|
import { OIDCService } from "./oidc.service";
|
|
import { CommandService } from "./command.service";
|
|
import { QueryService } from "./query.service";
|
|
import { FederationAgentService } from "./federation-agent.service";
|
|
import { validateFederationConfig } from "./federation.config";
|
|
import { PrismaModule } from "../prisma/prisma.module";
|
|
import { AuthModule } from "../auth/auth.module";
|
|
import { TasksModule } from "../tasks/tasks.module";
|
|
import { EventsModule } from "../events/events.module";
|
|
import { ProjectsModule } from "../projects/projects.module";
|
|
import { RedisProvider } from "../common/providers/redis.provider";
|
|
|
|
@Module({
|
|
imports: [
|
|
ConfigModule,
|
|
PrismaModule,
|
|
AuthModule,
|
|
TasksModule,
|
|
EventsModule,
|
|
ProjectsModule,
|
|
HttpModule.register({
|
|
timeout: 10000,
|
|
maxRedirects: 5,
|
|
}),
|
|
// Rate limiting for DoS protection (Issue #272)
|
|
// Uses in-memory storage by default (suitable for single-instance deployments)
|
|
// For multi-instance deployments, configure Redis storage via ThrottlerStorageRedisService
|
|
ThrottlerModule.forRoot([
|
|
{
|
|
name: "short",
|
|
ttl: 1000, // 1 second
|
|
limit: 3, // 3 requests per second (very strict for public endpoints)
|
|
},
|
|
{
|
|
name: "medium",
|
|
ttl: 60000, // 1 minute
|
|
limit: 20, // 20 requests per minute (for authenticated endpoints)
|
|
},
|
|
{
|
|
name: "long",
|
|
ttl: 3600000, // 1 hour
|
|
limit: 200, // 200 requests per hour (for read operations)
|
|
},
|
|
]),
|
|
],
|
|
controllers: [FederationController, FederationAuthController],
|
|
providers: [
|
|
RedisProvider,
|
|
FederationService,
|
|
CryptoService,
|
|
FederationAuditService,
|
|
SignatureService,
|
|
ConnectionService,
|
|
OIDCService,
|
|
CommandService,
|
|
QueryService,
|
|
FederationAgentService,
|
|
],
|
|
exports: [
|
|
FederationService,
|
|
CryptoService,
|
|
FederationAuditService,
|
|
SignatureService,
|
|
ConnectionService,
|
|
OIDCService,
|
|
CommandService,
|
|
QueryService,
|
|
FederationAgentService,
|
|
],
|
|
})
|
|
export class FederationModule implements OnModuleInit {
|
|
private readonly logger = new Logger(FederationModule.name);
|
|
|
|
/**
|
|
* Validate federation configuration at module initialization.
|
|
* Issue #338: Fail fast if DEFAULT_WORKSPACE_ID is not a valid UUID.
|
|
*/
|
|
onModuleInit(): void {
|
|
try {
|
|
validateFederationConfig();
|
|
this.logger.log("Federation configuration validated successfully");
|
|
} catch (error) {
|
|
this.logger.warn(
|
|
`Federation disabled: ${error instanceof Error ? error.message : String(error)}`
|
|
);
|
|
}
|
|
}
|
|
}
|