Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Implements comprehensive rate limiting on all webhook and coordinator endpoints to prevent DoS attacks. Follows TDD protocol with 14 passing tests. Implementation: - Added @nestjs/throttler package for rate limiting - Created ThrottlerApiKeyGuard for per-API-key rate limiting - Created ThrottlerValkeyStorageService for distributed rate limiting via Redis - Configured rate limits on stitcher endpoints (60 req/min) - Configured rate limits on coordinator endpoints (100 req/min) - Higher limits for health endpoints (300 req/min for monitoring) - Added environment variables for rate limit configuration - Rate limiting logs violations for security monitoring Rate Limits: - Stitcher webhooks: 60 requests/minute per API key - Coordinator endpoints: 100 requests/minute per API key - Health endpoints: 300 requests/minute (higher for monitoring) Storage: - Uses Valkey (Redis) for distributed rate limiting across API instances - Falls back to in-memory storage if Redis unavailable Testing: - 14 comprehensive rate limiting tests (all passing) - Tests verify: rate limit enforcement, Retry-After headers, per-API-key isolation - TDD approach: RED (failing tests) → GREEN (implementation) → REFACTOR Additional improvements: - Type safety improvements in websocket gateway - Array type notation standardization in coordinator service Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
import { Controller, Post, Body, UseGuards } from "@nestjs/common";
|
|
import { Throttle } from "@nestjs/throttler";
|
|
import { StitcherService } from "./stitcher.service";
|
|
import { WebhookPayloadDto, DispatchJobDto } from "./dto";
|
|
import type { JobDispatchResult, JobDispatchContext } from "./interfaces";
|
|
import { ApiKeyGuard } from "../common/guards";
|
|
|
|
/**
|
|
* StitcherController - Webhook and job dispatch endpoints
|
|
*
|
|
* SECURITY:
|
|
* - All endpoints require API key authentication via X-API-Key header
|
|
* - Rate limiting: 60 requests per minute per IP/API key
|
|
*
|
|
* Handles incoming webhooks from @mosaic bot and provides
|
|
* endpoints for manual job dispatch
|
|
*/
|
|
@Controller("stitcher")
|
|
@UseGuards(ApiKeyGuard)
|
|
@Throttle({ default: { ttl: 60000, limit: 60 } }) // 60 requests per minute
|
|
export class StitcherController {
|
|
constructor(private readonly stitcherService: StitcherService) {}
|
|
|
|
/**
|
|
* Webhook endpoint for @mosaic bot
|
|
*
|
|
* Rate limit: 60 requests per minute per IP/API key
|
|
*/
|
|
@Post("webhook")
|
|
@Throttle({ default: { ttl: 60000, limit: 60 } })
|
|
async webhook(@Body() payload: WebhookPayloadDto): Promise<JobDispatchResult> {
|
|
return this.stitcherService.handleWebhook(payload);
|
|
}
|
|
|
|
/**
|
|
* Manual job dispatch endpoint
|
|
*
|
|
* Rate limit: 60 requests per minute per IP/API key
|
|
*/
|
|
@Post("dispatch")
|
|
@Throttle({ default: { ttl: 60000, limit: 60 } })
|
|
async dispatch(@Body() dto: DispatchJobDto): Promise<JobDispatchResult> {
|
|
const context: JobDispatchContext = {
|
|
workspaceId: dto.workspaceId,
|
|
type: dto.type,
|
|
...(dto.context !== undefined && { metadata: dto.context }),
|
|
};
|
|
|
|
return this.stitcherService.dispatchJob(context);
|
|
}
|
|
}
|