"""Environment configuration validation for portable deployments.""" from dataclasses import dataclass import os from pathlib import Path class ConfigError(ValueError): """Raised when deployment configuration is unsafe or malformed.""" @dataclass(frozen=True) class Config: app_env: str data_dir: Path session_secret: str outreach_enabled: bool log_level: str def _env(values, key, default=""): return str(values.get(key, default) or "").strip() def load_config(values=None): values = os.environ if values is None else values app_env = _env(values, "APP_ENV", "development").lower() if app_env not in {"development", "test", "staging", "production"}: raise ConfigError("APP_ENV must be development, test, staging, or production") data_dir = Path(_env(values, "DATA_DIR", ".") or ".").expanduser() if not data_dir.is_absolute(): data_dir = (Path.cwd() / data_dir).resolve() if data_dir.exists() and not data_dir.is_dir(): raise ConfigError("DATA_DIR must be a directory") secret = _env(values, "SESSION_SECRET") if app_env == "production" and (len(secret) < 32 or secret.lower() in {"change-me", "development", "dev"}): raise ConfigError("SESSION_SECRET must be at least 32 characters in production") outreach = _env(values, "AUTOMATED_OUTREACH_ENABLED", "false").lower() if outreach not in {"", "0", "false", "no", "off"}: raise ConfigError("automated outreach is disabled in this release") log_level = _env(values, "LOG_LEVEL", "INFO").upper() if log_level not in {"QUIET", "ERROR", "WARNING", "INFO", "DEBUG"}: raise ConfigError("LOG_LEVEL is invalid") return Config(app_env, data_dir, secret, False, log_level)