82 lines
2.3 KiB
Python
82 lines
2.3 KiB
Python
"""Centralized settings loaded once at startup via pydantic-settings.
|
|
|
|
Reads environment variables once and exposes a cached Settings() instance.
|
|
Replaces scattered os.environ.get() calls throughout the codebase.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from functools import lru_cache
|
|
|
|
from pydantic import Field
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
"""Application settings pulled from environment variables."""
|
|
|
|
model_config = SettingsConfigDict(
|
|
env_file=".env",
|
|
env_file_encoding="utf-8",
|
|
case_sensitive=False,
|
|
extra="ignore",
|
|
)
|
|
|
|
# Redis
|
|
redis_url: str = Field(
|
|
default="redis://redis:6379/0", description="Redis connection URL"
|
|
)
|
|
|
|
# Auth
|
|
admin_username: str = Field(default="admin", description="Admin username")
|
|
admin_password_hash: str | None = Field(
|
|
default=None,
|
|
description="Argon2 password hash. If unset, first-run setup is required.",
|
|
)
|
|
session_secret: str | None = Field(
|
|
default=None,
|
|
description="Signing secret for session cookies (required in prod).",
|
|
)
|
|
session_max_age_seconds: int = Field(
|
|
default=14 * 24 * 3600, description="Session cookie max age"
|
|
)
|
|
trust_proxy: bool = Field(
|
|
default=False,
|
|
description="Set true when behind HTTPS reverse proxy (enables Secure cookie + HSTS)",
|
|
)
|
|
|
|
# SMTP
|
|
smtp_password: str | None = Field(
|
|
default=None, description="SMTP password (not stored in Redis)"
|
|
)
|
|
|
|
# Network validation
|
|
allow_private_ips: bool = Field(
|
|
default=True,
|
|
description="Allow private/RFC1918 hosts in UPSConfig.host. Default true for homelab.",
|
|
)
|
|
|
|
# Legacy / migration
|
|
ups_config_path: str = Field(
|
|
default="/config/ups.yaml",
|
|
description="Legacy YAML path (migration-only).",
|
|
)
|
|
|
|
# Logging
|
|
log_level: str = Field(default="INFO", description="Python log level")
|
|
|
|
# Timezone
|
|
tz: str = Field(default="UTC", description="Server timezone")
|
|
|
|
# Rate limit toggle (disable in tests)
|
|
rate_limit_enabled: bool = Field(
|
|
default=True, description="Enable slowapi rate limiting"
|
|
)
|
|
|
|
|
|
@lru_cache(maxsize=1)
|
|
def get_settings() -> Settings:
|
|
return Settings()
|
|
|
|
|
|
settings = get_settings()
|