Cybersecurity-Projects/PROJECTS/advanced/ai-threat-detection/backend/app/config.py

95 lines
2.7 KiB
Python

"""
©AngelaMos | 2026
config.py
Pydantic-settings application configuration loaded from
environment variables and .env file
Defines the Settings model with defaults for: server
(host 0.0.0.0, port 8000, debug, log_level), database
(postgresql+asyncpg URL), Redis URL, GeoIP MaxMind
database path, nginx log path, pipeline queue sizes
(raw 1000, parsed 500, feature 200, alert 100), batch
settings (size 32, timeout 50ms), and ML configuration
(model_dir, detection_mode, ensemble weights for
autoencoder/random-forest/isolation-forest at 0.40/0.40
/0.20 with model_validator enforcing sum-to-1.0,
ae_threshold_percentile 99.5, MLflow tracking URI).
Exports a module-level singleton settings instance
Connects to:
factory.py - consumed in lifespan and create_app
__main__.py - server host/port/reload
core/ingestion/ - queue sizes, log path
core/detection/ - model_dir, ensemble weights
core/enrichment/ - geoip_db_path
"""
from typing import Self
from pydantic import model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""
Application configuration loaded from environment variables.
"""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
)
app_name: str = "AngelusVigil"
env: str = "development"
debug: bool = False
host: str = "0.0.0.0"
port: int = 8000
api_key: str = ""
log_level: str = "INFO"
database_url: str = "postgresql+asyncpg://vigil:changeme@localhost:5432/angelusvigil"
redis_url: str = "redis://localhost:6379"
geoip_db_path: str = "/usr/share/GeoIP/GeoLite2-City.mmdb"
nginx_log_path: str = "/var/log/nginx/access.log"
raw_queue_size: int = 1000
parsed_queue_size: int = 500
feature_queue_size: int = 200
alert_queue_size: int = 100
batch_size: int = 32
batch_timeout_ms: int = 50
model_dir: str = "data/models"
detection_mode: str = "rules"
ensemble_weight_ae: float = 0.40
ensemble_weight_rf: float = 0.40
ensemble_weight_if: float = 0.20
ae_threshold_percentile: float = 99.5
mlflow_tracking_uri: str = "file:./mlruns"
@model_validator(mode="after")
def _check_ensemble_weights(self) -> Self:
"""
Validate that ensemble weights sum to 1.0
"""
total = (
self.ensemble_weight_ae
+ self.ensemble_weight_rf
+ self.ensemble_weight_if
)
if abs(total - 1.0) > 1e-6:
raise ValueError(
f"Ensemble weights must sum to 1.0, got {total:.6f}"
)
return self
settings = Settings()