Spaces:
Sleeping
Sleeping
| """Application configuration helpers.""" | |
| from __future__ import annotations | |
| from functools import lru_cache | |
| import os | |
| from pathlib import Path | |
| from typing import Optional | |
| from pydantic import BaseModel, ConfigDict, Field, field_validator | |
| PROJECT_ROOT = Path(__file__).resolve().parents[3] | |
| DEFAULT_VAULT_BASE = PROJECT_ROOT / "data" / "vaults" | |
| class AppConfig(BaseModel): | |
| """Runtime configuration loaded from environment variables.""" | |
| model_config = ConfigDict(frozen=True) | |
| jwt_secret_key: Optional[str] = Field( | |
| default=None, | |
| description="HMAC secret for JWT signing (required for JWT/HTTP auth)", | |
| ) | |
| enable_local_mode: bool = Field( | |
| default=True, | |
| description="Allow local-dev token bypass when running locally", | |
| ) | |
| local_dev_token: Optional[str] = Field( | |
| default="local-dev-token", | |
| description="Static token accepted in local mode for development", | |
| ) | |
| vault_base_path: Path = Field(..., description="Base directory for per-user vaults") | |
| hf_oauth_client_id: Optional[str] = Field( | |
| None, description="Hugging Face OAuth client ID (optional)" | |
| ) | |
| hf_oauth_client_secret: Optional[str] = Field( | |
| None, description="Hugging Face OAuth client secret (optional)" | |
| ) | |
| hf_space_url: str = Field( | |
| default="http://localhost:5173", | |
| description="Base URL of the HF Space or local dev server" | |
| ) | |
| def _normalize_vault_path(cls, value: str | Path | None) -> Path: | |
| if value is None or value == "": | |
| raise ValueError("VAULT_BASE_PATH is required") | |
| if isinstance(value, Path): | |
| path = value | |
| else: | |
| path = Path(value) | |
| # Resolve relative vault paths from the project root so data/ is placed | |
| # alongside backend rather than inside it. | |
| path = path.expanduser() | |
| if not path.is_absolute(): | |
| path = PROJECT_ROOT / path | |
| return path.resolve() | |
| def _ensure_secret(cls, value: Optional[str]) -> Optional[str]: | |
| if value is None: | |
| return None | |
| cleaned = value.strip() | |
| if not cleaned: | |
| raise ValueError( | |
| "JWT_SECRET_KEY cannot be empty; unset the variable to disable JWT auth in local mode" | |
| ) | |
| if len(cleaned) < 16: | |
| raise ValueError("JWT_SECRET_KEY must be at least 16 characters") | |
| return cleaned | |
| def _read_env(key: str, default: Optional[str] = None) -> Optional[str]: | |
| return os.getenv(key, default) | |
| def get_config() -> AppConfig: | |
| """Load and cache application configuration.""" | |
| jwt_secret = _read_env("JWT_SECRET_KEY") | |
| vault_base = _read_env("VAULT_BASE_PATH", str(DEFAULT_VAULT_BASE)) | |
| hf_client_id = _read_env("HF_OAUTH_CLIENT_ID") | |
| hf_client_secret = _read_env("HF_OAUTH_CLIENT_SECRET") | |
| hf_space_url = _read_env("HF_SPACE_URL", "http://localhost:5173") | |
| enable_local_mode = _read_env("ENABLE_LOCAL_MODE", "true").lower() not in { | |
| "0", | |
| "false", | |
| "no", | |
| } | |
| local_dev_token = _read_env("LOCAL_DEV_TOKEN", "local-dev-token") | |
| config = AppConfig( | |
| jwt_secret_key=jwt_secret, | |
| enable_local_mode=enable_local_mode, | |
| local_dev_token=local_dev_token, | |
| vault_base_path=vault_base, | |
| hf_oauth_client_id=hf_client_id, | |
| hf_oauth_client_secret=hf_client_secret, | |
| hf_space_url=hf_space_url, | |
| ) | |
| # Ensure vault base directory exists for downstream services. | |
| config.vault_base_path.mkdir(parents=True, exist_ok=True) | |
| return config | |
| def reload_config() -> AppConfig: | |
| """Clear cached config (useful for tests) and reload.""" | |
| get_config.cache_clear() | |
| return get_config() | |
| __all__ = ["AppConfig", "get_config", "reload_config", "PROJECT_ROOT", "DEFAULT_VAULT_BASE"] | |