Files
stack/.env.example
Jason Woltje 41d56dadf0
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
fix(#199): implement rate limiting on webhook endpoints
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>
2026-02-02 13:07:16 -06:00

217 lines
7.4 KiB
Plaintext

# ==============================================
# Mosaic Stack Environment Configuration
# ==============================================
# Copy this file to .env and customize for your environment
# ======================
# Application Ports
# ======================
API_PORT=3001
API_HOST=0.0.0.0
WEB_PORT=3000
# ======================
# Web Configuration
# ======================
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:3001
# ======================
# PostgreSQL Database
# ======================
# SECURITY: Change POSTGRES_PASSWORD to a strong random password in production
DATABASE_URL=postgresql://mosaic:REPLACE_WITH_SECURE_PASSWORD@localhost:5432/mosaic
POSTGRES_USER=mosaic
POSTGRES_PASSWORD=REPLACE_WITH_SECURE_PASSWORD
POSTGRES_DB=mosaic
POSTGRES_PORT=5432
# PostgreSQL Performance Tuning (Optional)
POSTGRES_SHARED_BUFFERS=256MB
POSTGRES_EFFECTIVE_CACHE_SIZE=1GB
POSTGRES_MAX_CONNECTIONS=100
# ======================
# Valkey Cache (Redis-compatible)
# ======================
VALKEY_URL=redis://localhost:6379
VALKEY_PORT=6379
VALKEY_MAXMEMORY=256mb
# Knowledge Module Cache Configuration
# Set KNOWLEDGE_CACHE_ENABLED=false to disable caching (useful for development)
KNOWLEDGE_CACHE_ENABLED=true
# Cache TTL in seconds (default: 300 = 5 minutes)
KNOWLEDGE_CACHE_TTL=300
# ======================
# Authentication (Authentik OIDC)
# ======================
# Authentik Server URLs
OIDC_ISSUER=https://auth.example.com/application/o/mosaic-stack/
OIDC_CLIENT_ID=your-client-id-here
OIDC_CLIENT_SECRET=your-client-secret-here
# Redirect URI must match what's configured in Authentik
# Development: http://localhost:3001/auth/callback/authentik
# Production: https://api.mosaicstack.dev/auth/callback/authentik
OIDC_REDIRECT_URI=http://localhost:3001/auth/callback/authentik
# Authentik PostgreSQL Database
AUTHENTIK_POSTGRES_USER=authentik
AUTHENTIK_POSTGRES_PASSWORD=REPLACE_WITH_SECURE_PASSWORD
AUTHENTIK_POSTGRES_DB=authentik
# Authentik Configuration
# CRITICAL: Generate a random secret key with at least 50 characters
# Example: openssl rand -base64 50
AUTHENTIK_SECRET_KEY=REPLACE_WITH_RANDOM_SECRET_MINIMUM_50_CHARS
AUTHENTIK_ERROR_REPORTING=false
# SECURITY: Change bootstrap password immediately after first login
AUTHENTIK_BOOTSTRAP_PASSWORD=REPLACE_WITH_SECURE_PASSWORD
AUTHENTIK_BOOTSTRAP_EMAIL=admin@localhost
AUTHENTIK_COOKIE_DOMAIN=.localhost
# Authentik Ports
AUTHENTIK_PORT_HTTP=9000
AUTHENTIK_PORT_HTTPS=9443
# ======================
# JWT Configuration
# ======================
# CRITICAL: Generate a random secret key with at least 32 characters
# Example: openssl rand -base64 32
JWT_SECRET=REPLACE_WITH_RANDOM_SECRET_MINIMUM_32_CHARS
JWT_EXPIRATION=24h
# ======================
# Ollama (Optional AI Service)
# ======================
# Set OLLAMA_ENDPOINT to use local or remote Ollama
# For bundled Docker service: http://ollama:11434
# For external service: http://your-ollama-server:11434
OLLAMA_ENDPOINT=http://ollama:11434
OLLAMA_PORT=11434
# ======================
# OpenAI API (For Semantic Search)
# ======================
# OPTIONAL: Semantic search requires an OpenAI API key
# Get your API key from: https://platform.openai.com/api-keys
# If not configured, semantic search endpoints will return an error
# OPENAI_API_KEY=sk-...
# ======================
# Application Environment
# ======================
NODE_ENV=development
# ======================
# Docker Compose Profiles
# ======================
# Uncomment to enable optional services:
# COMPOSE_PROFILES=authentik,ollama # Enable both Authentik and Ollama
# COMPOSE_PROFILES=full # Enable all optional services
# COMPOSE_PROFILES=authentik # Enable only Authentik
# COMPOSE_PROFILES=ollama # Enable only Ollama
# COMPOSE_PROFILES=traefik-bundled # Enable bundled Traefik reverse proxy
# ======================
# Traefik Reverse Proxy
# ======================
# TRAEFIK_MODE options:
# - bundled: Use bundled Traefik (requires traefik-bundled profile)
# - upstream: Connect to external Traefik instance
# - none: Direct port exposure without reverse proxy (default)
TRAEFIK_MODE=none
# Domain configuration for Traefik routing
MOSAIC_API_DOMAIN=api.mosaic.local
MOSAIC_WEB_DOMAIN=mosaic.local
MOSAIC_AUTH_DOMAIN=auth.mosaic.local
# External Traefik network name (for upstream mode)
# Must match the network name of your existing Traefik instance
TRAEFIK_NETWORK=traefik-public
# TLS/SSL Configuration
TRAEFIK_TLS_ENABLED=true
# For Let's Encrypt (production):
TRAEFIK_ACME_EMAIL=admin@example.com
# For self-signed certificates (development), leave TRAEFIK_ACME_EMAIL empty
# Traefik Dashboard (bundled mode only)
TRAEFIK_DASHBOARD_ENABLED=true
TRAEFIK_DASHBOARD_PORT=8080
# ======================
# Gitea Integration (Coordinator)
# ======================
# Gitea instance URL
GITEA_URL=https://git.mosaicstack.dev
# Coordinator bot credentials (see docs/1-getting-started/3-configuration/4-gitea-coordinator.md)
# SECURITY: Store GITEA_BOT_TOKEN in secrets vault, not in version control
GITEA_BOT_USERNAME=mosaic
GITEA_BOT_TOKEN=REPLACE_WITH_COORDINATOR_BOT_API_TOKEN
GITEA_BOT_PASSWORD=REPLACE_WITH_COORDINATOR_BOT_PASSWORD
# Repository configuration
GITEA_REPO_OWNER=mosaic
GITEA_REPO_NAME=stack
# Webhook secret for coordinator (HMAC SHA256 signature verification)
# SECURITY: Generate random secret with: openssl rand -hex 32
# Configure in Gitea: Repository Settings → Webhooks → Add Webhook
GITEA_WEBHOOK_SECRET=REPLACE_WITH_RANDOM_WEBHOOK_SECRET
# Coordinator API Key (service-to-service authentication)
# CRITICAL: Generate a random API key with at least 32 characters
# Example: openssl rand -base64 32
# The coordinator service uses this key to authenticate with the API
COORDINATOR_API_KEY=REPLACE_WITH_RANDOM_API_KEY_MINIMUM_32_CHARS
# ======================
# Rate Limiting
# ======================
# Rate limiting prevents DoS attacks on webhook and API endpoints
# TTL is in seconds, limits are per TTL window
# Global rate limit (applies to all endpoints unless overridden)
RATE_LIMIT_TTL=60 # Time window in seconds
RATE_LIMIT_GLOBAL_LIMIT=100 # Requests per window
# Webhook endpoints (/stitcher/webhook, /stitcher/dispatch)
RATE_LIMIT_WEBHOOK_LIMIT=60 # Requests per minute
# Coordinator endpoints (/coordinator/*)
RATE_LIMIT_COORDINATOR_LIMIT=100 # Requests per minute
# Health check endpoints (/coordinator/health)
RATE_LIMIT_HEALTH_LIMIT=300 # Requests per minute (higher for monitoring)
# Storage backend for rate limiting (redis or memory)
# redis: Uses Valkey for distributed rate limiting (recommended for production)
# memory: Uses in-memory storage (single instance only, for development)
RATE_LIMIT_STORAGE=redis
# ======================
# Discord Bridge (Optional)
# ======================
# Discord bot integration for chat-based control
# Get bot token from: https://discord.com/developers/applications
# DISCORD_BOT_TOKEN=your-discord-bot-token-here
# DISCORD_GUILD_ID=your-discord-server-id
# DISCORD_CONTROL_CHANNEL_ID=channel-id-for-commands
# DISCORD_WORKSPACE_ID=your-workspace-uuid
#
# SECURITY: DISCORD_WORKSPACE_ID must be a valid workspace UUID from your database.
# All Discord commands will execute within this workspace context for proper
# multi-tenant isolation. Each Discord bot instance should be configured for
# a single workspace.
# ======================
# Logging & Debugging
# ======================
LOG_LEVEL=info
DEBUG=false