From 0e7c7e2017e2bbf29697f7e9d685d70d4860ef86 Mon Sep 17 00:00:00 2001 From: Aljaz Ceru Date: Tue, 9 Sep 2025 08:16:04 +0200 Subject: [PATCH] fixing variables loading --- .env.example | 94 +++++++++++++++++++++++++------ backend/app/core/config.py | 112 ++++++++++++++++++------------------- docker-compose.yml | 22 -------- 3 files changed, 134 insertions(+), 94 deletions(-) diff --git a/.env.example b/.env.example index 3c1146b..cf6d8f1 100644 --- a/.env.example +++ b/.env.example @@ -20,6 +20,29 @@ PRIVATEMODE_API_KEY=your-privatemode-api-key-here ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=admin123 +# =================================== +# ADDITIONAL SECURITY SETTINGS (Optional but recommended) +# =================================== +# JWT Algorithm (default: HS256) +# JWT_ALGORITHM=HS256 + +# Token expiration times (in minutes) +# ACCESS_TOKEN_EXPIRE_MINUTES=30 +# REFRESH_TOKEN_EXPIRE_MINUTES=10080 +# SESSION_EXPIRE_MINUTES=1440 + +# API Key prefix (default: en_) +# API_KEY_PREFIX=en_ + +# Security thresholds (0.0-1.0) +# API_SECURITY_RISK_THRESHOLD=0.8 +# API_SECURITY_WARNING_THRESHOLD=0.6 +# API_SECURITY_ANOMALY_THRESHOLD=0.7 + +# IP security (comma-separated for multiple IPs) +# API_BLOCKED_IPS= +# API_ALLOWED_IPS= + # =================================== # APPLICATION BASE URL (Required - derives all URLs and CORS) # =================================== @@ -49,23 +72,62 @@ QDRANT_URL=http://enclava-qdrant:6333 # PRIVATEMODE_CACHE_SALT= # Optional: defaults to empty # =================================== -# MOVED TO APP SETTINGS (Optional - have defaults) +# OPTIONAL CONFIGURATION (All have sensible defaults) # =================================== -# The following were moved to have sane defaults and/or be user-configurable: -# - APP_NAME (default: "Enclava") -# - APP_DEBUG (default: false) -# - APP_LOG_LEVEL (default: INFO) -# - API timeout/retry settings (have defaults) -# - Rate limiting settings (default enabled) -# - Module default URLs (user configurable) -# - API_KEY_PREFIX (default: "ce_") -# - Monitoring settings (default enabled) + +# Application Settings +# APP_NAME=Enclava +# APP_DEBUG=false +# APP_LOG_LEVEL=INFO +# APP_HOST=0.0.0.0 +# APP_PORT=8000 + +# Security Features +# API_SECURITY_ENABLED=true +# API_THREAT_DETECTION_ENABLED=true +# API_IP_REPUTATION_ENABLED=true +# API_ANOMALY_DETECTION_ENABLED=true +# API_RATE_LIMITING_ENABLED=true +# API_SECURITY_HEADERS_ENABLED=true + +# Content Security Policy +# API_CSP_HEADER=default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' + +# Rate Limiting (requests per minute/hour) +# API_RATE_LIMIT_AUTHENTICATED_PER_MINUTE=300 +# API_RATE_LIMIT_AUTHENTICATED_PER_HOUR=5000 +# API_RATE_LIMIT_API_KEY_PER_MINUTE=1000 +# API_RATE_LIMIT_API_KEY_PER_HOUR=20000 +# API_RATE_LIMIT_PREMIUM_PER_MINUTE=5000 +# API_RATE_LIMIT_PREMIUM_PER_HOUR=100000 + +# Request Size Limits (in bytes) +# API_MAX_REQUEST_BODY_SIZE=10485760 # 10MB +# API_MAX_REQUEST_BODY_SIZE_PREMIUM=52428800 # 50MB +# MAX_UPLOAD_SIZE=10485760 # 10MB + +# Monitoring +# PROMETHEUS_ENABLED=true +# PROMETHEUS_PORT=9090 + +# Logging +# LOG_FORMAT=json +# LOG_LEVEL=INFO +# LOG_LLM_PROMPTS=false + +# Module Configuration +# MODULES_CONFIG_PATH=config/modules.yaml + +# Plugin Configuration +# PLUGINS_DIR=/plugins +# PLUGINS_CONFIG_PATH=config/plugins.yaml +# PLUGIN_REPOSITORY_URL=https://plugins.enclava.com +# PLUGIN_ENCRYPTION_KEY= # =================================== -# TOTAL: 8 essential variables vs 25+ in original -# (Consolidated 3 URL settings into 1 base URL) -# (Consolidated 6 Docker networking settings into 2 ports) -# (CORS_ORIGINS now derived from base URL) -# (Added PRIVATEMODE_API_KEY as required) -# (68% reduction in required configuration!) +# SUMMARY +# =================================== +# Required: DATABASE_URL, REDIS_URL, JWT_SECRET, ADMIN_EMAIL, ADMIN_PASSWORD, BASE_URL +# Recommended: PRIVATEMODE_API_KEY, QDRANT_HOST, QDRANT_PORT +# Optional: All other settings have secure defaults # =================================== \ No newline at end of file diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 3b429e3..c5cb8c3 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -12,35 +12,35 @@ class Settings(BaseSettings): """Application settings""" # Application - APP_NAME: str = "Enclava" - APP_DEBUG: bool = False - APP_LOG_LEVEL: str = "INFO" - APP_HOST: str = "0.0.0.0" - APP_PORT: int = 8000 + APP_NAME: str = os.getenv("APP_NAME", "Enclava") + APP_DEBUG: bool = os.getenv("APP_DEBUG", "False").lower() == "true" + APP_LOG_LEVEL: str = os.getenv("APP_LOG_LEVEL", "INFO") + APP_HOST: str = os.getenv("APP_HOST", "0.0.0.0") + APP_PORT: int = int(os.getenv("APP_PORT", "8000")) # Detailed logging for LLM interactions - LOG_LLM_PROMPTS: bool = False # Set to True to log prompts and context sent to LLM + LOG_LLM_PROMPTS: bool = os.getenv("LOG_LLM_PROMPTS", "False").lower() == "true" # Set to True to log prompts and context sent to LLM # Database - DATABASE_URL: str = "postgresql://empire_user:empire_pass@localhost:5432/empire_db" + DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql://empire_user:empire_pass@localhost:5432/empire_db") # Redis - REDIS_URL: str = "redis://localhost:6379" + REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379") # Security - JWT_SECRET: str = "your-super-secret-jwt-key-here" - JWT_ALGORITHM: str = "HS256" - ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 - REFRESH_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7 # 7 days - SESSION_EXPIRE_MINUTES: int = 60 * 24 # 24 hours - API_KEY_PREFIX: str = "en_" + JWT_SECRET: str = os.getenv("JWT_SECRET", "your-super-secret-jwt-key-here") + JWT_ALGORITHM: str = os.getenv("JWT_ALGORITHM", "HS256") + ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "30")) + REFRESH_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("REFRESH_TOKEN_EXPIRE_MINUTES", "10080")) # 7 days + SESSION_EXPIRE_MINUTES: int = int(os.getenv("SESSION_EXPIRE_MINUTES", "1440")) # 24 hours + API_KEY_PREFIX: str = os.getenv("API_KEY_PREFIX", "en_") # Admin user provisioning (used only on first startup) - ADMIN_EMAIL: str = "admin@example.com" - ADMIN_PASSWORD: str = "admin123" + ADMIN_EMAIL: str = os.getenv("ADMIN_EMAIL", "admin@example.com") + ADMIN_PASSWORD: str = os.getenv("ADMIN_PASSWORD", "admin123") # Base URL for deriving CORS origins - BASE_URL: str = "localhost" + BASE_URL: str = os.getenv("BASE_URL", "localhost") @field_validator('CORS_ORIGINS', mode='before') @classmethod @@ -60,77 +60,77 @@ class Settings(BaseSettings): # LLM Service Security (removed encryption - credentials handled by proxy) # Plugin System Security - PLUGIN_ENCRYPTION_KEY: Optional[str] = None # Key for encrypting plugin secrets and configurations + PLUGIN_ENCRYPTION_KEY: Optional[str] = os.getenv("PLUGIN_ENCRYPTION_KEY") # Key for encrypting plugin secrets and configurations # API Keys for LLM providers - OPENAI_API_KEY: Optional[str] = None - ANTHROPIC_API_KEY: Optional[str] = None - GOOGLE_API_KEY: Optional[str] = None - PRIVATEMODE_API_KEY: Optional[str] = None - PRIVATEMODE_PROXY_URL: str = "http://privatemode-proxy:8080/v1" + OPENAI_API_KEY: Optional[str] = os.getenv("OPENAI_API_KEY") + ANTHROPIC_API_KEY: Optional[str] = os.getenv("ANTHROPIC_API_KEY") + GOOGLE_API_KEY: Optional[str] = os.getenv("GOOGLE_API_KEY") + PRIVATEMODE_API_KEY: Optional[str] = os.getenv("PRIVATEMODE_API_KEY") + PRIVATEMODE_PROXY_URL: str = os.getenv("PRIVATEMODE_PROXY_URL", "http://privatemode-proxy:8080/v1") # Qdrant - QDRANT_HOST: str = "localhost" - QDRANT_PORT: int = 6333 - QDRANT_API_KEY: Optional[str] = None + QDRANT_HOST: str = os.getenv("QDRANT_HOST", "localhost") + QDRANT_PORT: int = int(os.getenv("QDRANT_PORT", "6333")) + QDRANT_API_KEY: Optional[str] = os.getenv("QDRANT_API_KEY") # API & Security Settings - API_SECURITY_ENABLED: bool = True - API_THREAT_DETECTION_ENABLED: bool = True - API_IP_REPUTATION_ENABLED: bool = True - API_ANOMALY_DETECTION_ENABLED: bool = True + API_SECURITY_ENABLED: bool = os.getenv("API_SECURITY_ENABLED", "True").lower() == "true" + API_THREAT_DETECTION_ENABLED: bool = os.getenv("API_THREAT_DETECTION_ENABLED", "True").lower() == "true" + API_IP_REPUTATION_ENABLED: bool = os.getenv("API_IP_REPUTATION_ENABLED", "True").lower() == "true" + API_ANOMALY_DETECTION_ENABLED: bool = os.getenv("API_ANOMALY_DETECTION_ENABLED", "True").lower() == "true" # Rate Limiting Configuration - API_RATE_LIMITING_ENABLED: bool = True + API_RATE_LIMITING_ENABLED: bool = os.getenv("API_RATE_LIMITING_ENABLED", "True").lower() == "true" # Authenticated users (JWT token) - API_RATE_LIMIT_AUTHENTICATED_PER_MINUTE: int = 300 - API_RATE_LIMIT_AUTHENTICATED_PER_HOUR: int = 5000 + API_RATE_LIMIT_AUTHENTICATED_PER_MINUTE: int = int(os.getenv("API_RATE_LIMIT_AUTHENTICATED_PER_MINUTE", "300")) + API_RATE_LIMIT_AUTHENTICATED_PER_HOUR: int = int(os.getenv("API_RATE_LIMIT_AUTHENTICATED_PER_HOUR", "5000")) # API key users (programmatic access) - API_RATE_LIMIT_API_KEY_PER_MINUTE: int = 1000 - API_RATE_LIMIT_API_KEY_PER_HOUR: int = 20000 + API_RATE_LIMIT_API_KEY_PER_MINUTE: int = int(os.getenv("API_RATE_LIMIT_API_KEY_PER_MINUTE", "1000")) + API_RATE_LIMIT_API_KEY_PER_HOUR: int = int(os.getenv("API_RATE_LIMIT_API_KEY_PER_HOUR", "20000")) # Premium/Enterprise API keys - API_RATE_LIMIT_PREMIUM_PER_MINUTE: int = 5000 - API_RATE_LIMIT_PREMIUM_PER_HOUR: int = 100000 + API_RATE_LIMIT_PREMIUM_PER_MINUTE: int = int(os.getenv("API_RATE_LIMIT_PREMIUM_PER_MINUTE", "5000")) + API_RATE_LIMIT_PREMIUM_PER_HOUR: int = int(os.getenv("API_RATE_LIMIT_PREMIUM_PER_HOUR", "100000")) # Security Thresholds - API_SECURITY_RISK_THRESHOLD: float = 0.8 # Block requests above this risk score - API_SECURITY_WARNING_THRESHOLD: float = 0.6 # Log warnings above this threshold - API_SECURITY_ANOMALY_THRESHOLD: float = 0.7 # Flag anomalies above this threshold + API_SECURITY_RISK_THRESHOLD: float = float(os.getenv("API_SECURITY_RISK_THRESHOLD", "0.8")) # Block requests above this risk score + API_SECURITY_WARNING_THRESHOLD: float = float(os.getenv("API_SECURITY_WARNING_THRESHOLD", "0.6")) # Log warnings above this threshold + API_SECURITY_ANOMALY_THRESHOLD: float = float(os.getenv("API_SECURITY_ANOMALY_THRESHOLD", "0.7")) # Flag anomalies above this threshold # Request Size Limits - API_MAX_REQUEST_BODY_SIZE: int = 10 * 1024 * 1024 # 10MB - API_MAX_REQUEST_BODY_SIZE_PREMIUM: int = 50 * 1024 * 1024 # 50MB for premium + API_MAX_REQUEST_BODY_SIZE: int = int(os.getenv("API_MAX_REQUEST_BODY_SIZE", "10485760")) # 10MB + API_MAX_REQUEST_BODY_SIZE_PREMIUM: int = int(os.getenv("API_MAX_REQUEST_BODY_SIZE_PREMIUM", "52428800")) # 50MB for premium # IP Security - API_BLOCKED_IPS: List[str] = [] # IPs to always block - API_ALLOWED_IPS: List[str] = [] # IPs to always allow (empty = allow all) - API_IP_REPUTATION_CACHE_TTL: int = 3600 # 1 hour + API_BLOCKED_IPS: List[str] = os.getenv("API_BLOCKED_IPS", "").split(",") if os.getenv("API_BLOCKED_IPS") else [] + API_ALLOWED_IPS: List[str] = os.getenv("API_ALLOWED_IPS", "").split(",") if os.getenv("API_ALLOWED_IPS") else [] + API_IP_REPUTATION_CACHE_TTL: int = int(os.getenv("API_IP_REPUTATION_CACHE_TTL", "3600")) # 1 hour # Security Headers - API_SECURITY_HEADERS_ENABLED: bool = True - API_CSP_HEADER: str = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" + API_SECURITY_HEADERS_ENABLED: bool = os.getenv("API_SECURITY_HEADERS_ENABLED", "True").lower() == "true" + API_CSP_HEADER: str = os.getenv("API_CSP_HEADER", "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'") # Monitoring - PROMETHEUS_ENABLED: bool = True - PROMETHEUS_PORT: int = 9090 + PROMETHEUS_ENABLED: bool = os.getenv("PROMETHEUS_ENABLED", "True").lower() == "true" + PROMETHEUS_PORT: int = int(os.getenv("PROMETHEUS_PORT", "9090")) # File uploads - MAX_UPLOAD_SIZE: int = 10 * 1024 * 1024 # 10MB + MAX_UPLOAD_SIZE: int = int(os.getenv("MAX_UPLOAD_SIZE", "10485760")) # 10MB # Module configuration - MODULES_CONFIG_PATH: str = "config/modules.yaml" + MODULES_CONFIG_PATH: str = os.getenv("MODULES_CONFIG_PATH", "config/modules.yaml") # Plugin configuration - PLUGINS_DIR: str = "/plugins" - PLUGINS_CONFIG_PATH: str = "config/plugins.yaml" - PLUGIN_REPOSITORY_URL: str = "https://plugins.enclava.com" + PLUGINS_DIR: str = os.getenv("PLUGINS_DIR", "/plugins") + PLUGINS_CONFIG_PATH: str = os.getenv("PLUGINS_CONFIG_PATH", "config/plugins.yaml") + PLUGIN_REPOSITORY_URL: str = os.getenv("PLUGIN_REPOSITORY_URL", "https://plugins.enclava.com") # Logging - LOG_FORMAT: str = "json" - LOG_LEVEL: str = "INFO" + LOG_FORMAT: str = os.getenv("LOG_FORMAT", "json") + LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO") model_config = { diff --git a/docker-compose.yml b/docker-compose.yml index 9f434a6..ed8b930 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -113,28 +113,6 @@ services: - enclava-net restart: unless-stopped - # Ollama Free Model Proxy - #enclava-ollama-proxy: - # build: - # context: /home/lio/cloud/code/ollama-free-model-proxy - # dockerfile: Dockerfile - # environment: - # - OPENAI_API_KEY=${SOME_API_KEY} - # - FREE_MODE=true - # - TOOL_USE_ONLY=false - # volumes: - # - enclava-ollama-data:/data - # working_dir: /data - # networks: - # - enclava-net - # restart: unless-stopped - #healthcheck: - # test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:11434/"] - # interval: 30s - # timeout: 10s - # retries: 3 - # start_period: 40s - # Qdrant vector database enclava-qdrant: image: qdrant/qdrant:latest