""" web/config.py ------------- Environment-based configuration for the web app. All values come from .env or environment variables. """ import os import subprocess from dotenv import load_dotenv load_dotenv() def _project_root() -> str: return os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) def _detect_build_id(default: str) -> str: env_build = os.getenv("APP_BUILD_ID", "").strip() if env_build: return env_build try: result = subprocess.run( ["git", "rev-parse", "--short", "HEAD"], cwd=_project_root(), check=True, capture_output=True, text=True, ) build_id = result.stdout.strip() return build_id or default except Exception: return default class Settings: # Adobe Sign OAuth adobe_client_id: str = os.getenv("ADOBE_CLIENT_ID", "") adobe_client_secret: str = os.getenv("ADOBE_CLIENT_SECRET", "") adobe_redirect_uri: str = os.getenv("ADOBE_REDIRECT_URI", "http://localhost:8000/api/auth/adobe/callback") adobe_sign_base_url: str = os.getenv("ADOBE_SIGN_BASE_URL", "https://api.eu2.adobesign.com/api/rest/v6") # DocuSign OAuth docusign_client_id: str = os.getenv("DOCUSIGN_CLIENT_ID", "") docusign_client_secret: str = os.getenv("DOCUSIGN_CLIENT_SECRET", "") docusign_redirect_uri: str = os.getenv("DOCUSIGN_REDIRECT_URI", "http://localhost:8000/api/auth/docusign/callback") docusign_account_id: str = os.getenv("DOCUSIGN_ACCOUNT_ID", "") docusign_base_url: str = os.getenv("DOCUSIGN_BASE_URL", "https://demo.docusign.net/restapi") docusign_auth_server: str = os.getenv("DOCUSIGN_AUTH_SERVER", "account-d.docusign.com") # Session session_secret_key: str = os.getenv("SESSION_SECRET_KEY", "dev-secret-change-in-production") session_store_dir: str = os.getenv( "SESSION_STORE_DIR", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".session-store")), ) audit_log_file: str = os.getenv( "AUDIT_LOG_FILE", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".audit-log.jsonl")), ) admin_emails_raw: str = os.getenv("ADMIN_EMAILS", "") # App version: str = "2.0" build_id: str = _detect_build_id("dev") asset_version: str = os.getenv("ASSET_VERSION", build_id) downloads_dir: str = os.getenv("DOWNLOADS_DIR", os.path.abspath(os.path.join(_project_root(), "downloads"))) @property def admin_emails(self) -> set[str]: return { email.strip().lower() for email in self.admin_emails_raw.split(",") if email.strip() } settings = Settings()