- Add TYPE_CHECKING guards for runtime-expensive imports (aiohttp, aiosqlite) - Reorganize imports to follow PEP 8 conventions - Convert TypeAlias to modern PEP 695 type syntax (where appropriate) - Use Sequence/Mapping from collections.abc for type hints (covariant) - Replace string literals with cast() for improved type inference - Fix casting of Fail2BanResponse and TypedDict patterns - Add IpLookupResult TypedDict for precise return type annotation - Reformat overlong lines for readability (120 char limit) - Add asyncio_mode and filterwarnings to pytest config - Update test fixtures with improved type hints This improves mypy type checking and makes type relationships explicit.
89 lines
3.2 KiB
Python
89 lines
3.2 KiB
Python
"""Application configuration loaded from environment variables and .env file.
|
|
|
|
Follows pydantic-settings patterns: all values are prefixed with BANGUI_
|
|
and validated at startup via the Settings singleton.
|
|
"""
|
|
|
|
from pydantic import Field
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
"""BanGUI runtime configuration.
|
|
|
|
All fields are loaded from environment variables prefixed with ``BANGUI_``
|
|
or from a ``.env`` file located next to the process working directory.
|
|
The application will raise a :class:`pydantic.ValidationError` on startup
|
|
if any required field is missing or has an invalid value.
|
|
"""
|
|
|
|
database_path: str = Field(
|
|
default="bangui.db",
|
|
description="Filesystem path to the BanGUI SQLite application database.",
|
|
)
|
|
fail2ban_socket: str = Field(
|
|
default="/var/run/fail2ban/fail2ban.sock",
|
|
description="Path to the fail2ban Unix domain socket.",
|
|
)
|
|
session_secret: str = Field(
|
|
...,
|
|
description=(
|
|
"Secret key used when generating session tokens. "
|
|
"Must be unique and never committed to source control."
|
|
),
|
|
)
|
|
session_duration_minutes: int = Field(
|
|
default=60,
|
|
ge=1,
|
|
description="Number of minutes a session token remains valid after creation.",
|
|
)
|
|
timezone: str = Field(
|
|
default="UTC",
|
|
description="IANA timezone name used when displaying timestamps in the UI.",
|
|
)
|
|
log_level: str = Field(
|
|
default="info",
|
|
description="Application log level: debug | info | warning | error | critical.",
|
|
)
|
|
geoip_db_path: str | None = Field(
|
|
default=None,
|
|
description=(
|
|
"Optional path to a MaxMind GeoLite2-Country .mmdb file. "
|
|
"When set, failed ip-api.com lookups fall back to local resolution."
|
|
),
|
|
)
|
|
fail2ban_config_dir: str = Field(
|
|
default="/config/fail2ban",
|
|
description=(
|
|
"Path to the fail2ban configuration directory. "
|
|
"Must contain subdirectories jail.d/, filter.d/, and action.d/. "
|
|
"Used for listing, viewing, and editing configuration files through the web UI."
|
|
),
|
|
)
|
|
fail2ban_start_command: str = Field(
|
|
default="fail2ban-client start",
|
|
description=(
|
|
"Shell command used to start (not reload) the fail2ban daemon during "
|
|
"recovery rollback. Split by whitespace to build the argument list — "
|
|
"no shell interpretation is performed. "
|
|
"Example: 'systemctl start fail2ban' or 'fail2ban-client start'."
|
|
),
|
|
)
|
|
|
|
model_config = SettingsConfigDict(
|
|
env_prefix="BANGUI_",
|
|
env_file=".env",
|
|
env_file_encoding="utf-8",
|
|
case_sensitive=False,
|
|
)
|
|
|
|
|
|
def get_settings() -> Settings:
|
|
"""Return a fresh :class:`Settings` instance loaded from the environment.
|
|
|
|
Returns:
|
|
A validated :class:`Settings` object. Raises :class:`pydantic.ValidationError`
|
|
if required keys are absent or values fail validation.
|
|
"""
|
|
return Settings() # type: ignore[call-arg] # pydantic-settings populates required fields from env vars
|