"""Config domain models. Internal domain-focused models used by config_service. These represent the business domain layer and are independent of HTTP response shapes. Response models are defined in `app.models.config` and mappers convert domain models to response models at the router boundary. """ from __future__ import annotations from dataclasses import dataclass from typing import Literal DNSMode = Literal["yes", "warn", "no", "raw"] LogEncoding = Literal["auto", "ascii", "utf-8", "UTF-8", "latin-1"] BackendType = Literal["auto", "polling", "pyinotify", "systemd", "gamin"] LogLevel = Literal["CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"] @dataclass(frozen=True) class DomainBantimeEscalation: """Incremental ban-time escalation configuration (domain model).""" increment: bool = False factor: float | None = None formula: str | None = None multipliers: str | None = None max_time: int | None = None rnd_time: int | None = None overall_jails: bool = False @dataclass(frozen=True) class DomainJailConfig: """Configuration snapshot of a single jail (domain model).""" name: str ban_time: int max_retry: int find_time: int fail_regex: list[str] ignore_regex: list[str] log_paths: list[str] actions: list[str] date_pattern: str | None = None log_encoding: LogEncoding = "UTF-8" backend: BackendType = "polling" use_dns: DNSMode = "warn" prefregex: str = "" bantime_escalation: DomainBantimeEscalation | None = None @dataclass(frozen=True) class DomainJailConfigList: """List of jail configurations (domain model).""" items: list[DomainJailConfig] total: int @dataclass(frozen=True) class DomainGlobalConfig: """Global fail2ban settings (domain model).""" log_level: LogLevel log_target: str db_purge_age: int db_max_matches: int @dataclass(frozen=True) class DomainServiceStatus: """Fail2ban service health status (domain model).""" online: bool version: str | None = None jail_count: int = 0 total_bans: int = 0 total_failures: int = 0 log_level: str | None = None log_target: str | None = None @dataclass(frozen=True) class DomainMapColorThresholds: """Map color threshold configuration (domain model).""" threshold_high: int threshold_medium: int threshold_low: int @dataclass(frozen=True) class DomainRegexTest: """Result of a regex test (domain model).""" matched: bool groups: list[str] error: str | None = None @dataclass(frozen=True) class DomainFilterConfig: """Structured representation of a filter.d/*.conf file (domain model).""" name: str filename: str before: str | None = None after: str | None = None variables: dict[str, str] | None = None prefregex: str | None = None failregex: list[str] | None = None ignoreregex: list[str] | None = None maxlines: int | None = None datepattern: str | None = None journalmatch: str | None = None active: bool = False used_by_jails: list[str] | None = None source_file: str = "" has_local_override: bool = False @dataclass(frozen=True) class DomainFilterList: """List of filter configurations (domain model).""" items: list[DomainFilterConfig] total: int