"""CER-P5-010: env validation policy — fail-fast per mandatory, soft per optional. Usage al boot di ogni mcp `__main__.py`: from option_mcp_common.env_validation import require_env, optional_env, summarize creds_file = require_env("CREDENTIALS_FILE", "deribit credentials JSON path") host = optional_env("HOST", default="0.0.0.0") summarize(["CREDENTIALS_FILE", "HOST", "PORT"]) """ from __future__ import annotations import logging import os import sys logger = logging.getLogger(__name__) class MissingEnvError(RuntimeError): """Mandatory env var absent or empty.""" def require_env(name: str, description: str = "") -> str: """Fail-fast: raise MissingEnvError se name non presente o vuoto. Uscita dal processo con codice 2 se chiamato dal main(). Comporta logging chiaro del missing var prima dell'exit. """ val = (os.environ.get(name) or "").strip() if not val: msg = f"missing mandatory env var: {name}" if description: msg += f" ({description})" logger.error(msg) raise MissingEnvError(msg) return val def optional_env(name: str, *, default: str = "") -> str: """Soft: ritorna env o default. Log INFO se default usato.""" val = (os.environ.get(name) or "").strip() if not val: if default: logger.info("env %s not set, using default=%r", name, default) return default return val def summarize(names: list[str]) -> None: """Log INFO di tutti gli env rilevanti con presenza (mask se SECRET/KEY/TOKEN).""" sensitive_tokens = ("SECRET", "KEY", "TOKEN", "PASSWORD", "CREDENTIAL", "WALLET") for n in names: val = os.environ.get(n) if val is None: logger.info("env[%s]: ", n) continue if any(t in n.upper() for t in sensitive_tokens): logger.info("env[%s]: ", n, len(val)) else: logger.info("env[%s]: %s", n, val) def fail_fast_if_missing(names: list[str]) -> None: """Verifica lista di nomi mandatory al boot. Exit 2 se uno solo manca. Uso preferito: early call in main() per bloccare boot se config incompleta. """ missing: list[str] = [] for n in names: if not (os.environ.get(n) or "").strip(): missing.append(n) if missing: logger.error("boot aborted: missing mandatory env vars: %s", missing) print( f"FATAL: missing mandatory env vars: {missing}", file=sys.stderr, ) sys.exit(2)