Add deployment-safe backend config and production-safe CORS defaults

This commit is contained in:
2026-04-06 20:47:31 +02:00
parent 1a7096b276
commit c2982116a8
4 changed files with 52 additions and 9 deletions

View File

@@ -4,9 +4,15 @@ Follows pydantic-settings patterns: all values are prefixed with BANGUI_
and validated at startup via the Settings singleton.
"""
from pydantic import Field
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
from app.utils.constants import (
DEFAULT_DATABASE_PATH,
DEFAULT_FAIL2BAN_SOCKET,
DEFAULT_SESSION_DURATION_MINUTES,
)
class Settings(BaseSettings):
"""BanGUI runtime configuration.
@@ -18,11 +24,11 @@ class Settings(BaseSettings):
"""
database_path: str = Field(
default="bangui.db",
default=DEFAULT_DATABASE_PATH,
description="Filesystem path to the BanGUI SQLite application database.",
)
fail2ban_socket: str = Field(
default="/var/run/fail2ban/fail2ban.sock",
default=DEFAULT_FAIL2BAN_SOCKET,
description="Path to the fail2ban Unix domain socket.",
)
session_secret: str = Field(
@@ -33,7 +39,7 @@ class Settings(BaseSettings):
),
)
session_duration_minutes: int = Field(
default=60,
default=DEFAULT_SESSION_DURATION_MINUTES,
ge=1,
description="Number of minutes a session token remains valid after creation.",
)
@@ -41,14 +47,24 @@ class Settings(BaseSettings):
default="UTC",
description="IANA timezone name used when displaying timestamps in the UI.",
)
cors_allowed_origins: list[str] = Field(
default_factory=lambda: ["http://localhost:5173"],
cors_allowed_origins: str | list[str] = Field(
default_factory=list,
description=(
"Comma-separated list of allowed CORS origins when the frontend is "
"served from a different origin than the backend. "
"Leave empty to disable cross-origin requests in production."
),
)
@field_validator("cors_allowed_origins", mode="before")
@classmethod
def _normalize_cors_origins(cls, value: str | list[str] | None) -> list[str]:
if value is None:
return []
if isinstance(value, str):
return [origin.strip() for origin in value.split(",") if origin.strip()]
return value
log_level: str = Field(
default="info",
description="Application log level: debug | info | warning | error | critical.",
@@ -72,8 +88,8 @@ class Settings(BaseSettings):
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. "
"recovery rollback. Split by whitespace to build the argument list — "
"no shell interpretation is performed. "
"Example: 'systemctl start fail2ban' or 'fail2ban-client start'."
),
)