Remove critical security vulnerability where Discord service used hardcoded "default-workspace" ID, bypassing Row-Level Security policies and creating potential for cross-tenant data leakage. Changes: - Add DISCORD_WORKSPACE_ID environment variable requirement - Add validation in connect() to require workspace configuration - Replace hardcoded workspace ID with configured value - Add 3 new tests for workspace configuration - Update .env.example with security documentation Security Impact: - Multi-tenant isolation now properly enforced - Each Discord bot instance must be configured for specific workspace - Service fails fast if workspace ID not configured Breaking Change: - Existing deployments must set DISCORD_WORKSPACE_ID environment variable Tests: All 21 Discord service tests passing (100%) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
186 lines
6.1 KiB
Plaintext
186 lines
6.1 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_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
|
|
|
|
# ======================
|
|
# 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
|