from __future__ import annotations from pathlib import Path from typing import Literal from pydantic import BaseModel, Field class ConfSource(BaseModel): key: str source_type: Literal["url", "file", "inline", "base64"] = "url" value: str enabled: bool = True cache_ttl: int | None = None options: dict[str, str] = Field(default_factory=dict) line_no: int class ConfSelector(BaseModel): key: str regex: str line_no: int class ConfGroup(BaseModel): name: str group_type: str tokens: list[str] = Field(default_factory=list) raw: str line_no: int class ConfModule(BaseModel): key: str path: str policy: str order: int enabled: bool = True line_no: int def resolved_path(self, config_dir: Path) -> Path: return (config_dir / self.path).resolve() class ConfBuiltin(BaseModel): key: str builtin_type: Literal["GEOIP", "FINAL"] value: str = "" policy: str order: int enabled: bool = True line_no: int class ConfBaseConfig(BaseModel): listen: str | None = None output_dir: str | None = None cache_dir: str | None = None mode: str | None = None allow_lan: bool | None = None log_level: str | None = None ipv6: bool | None = None append_userinfo_header: bool | None = None userinfo_source_policy: str | None = None sources: list[ConfSource] = Field(default_factory=list) selectors: list[ConfSelector] = Field(default_factory=list) groups: list[ConfGroup] = Field(default_factory=list) modules: list[ConfModule] = Field(default_factory=list) builtins: list[ConfBuiltin] = Field(default_factory=list) class ConfPolicyOverride(BaseModel): module_key: str policy: str line_no: int class ConfInlineRule(BaseModel): value: str line_no: int class ConfProfileConfig(BaseModel): name: str | None = None enabled: bool = True sources: list[str] = Field(default_factory=list) include_modules: list[str] = Field(default_factory=list) exclude_modules: list[str] = Field(default_factory=list) include_builtins: list[str] = Field(default_factory=list) override_policies: list[ConfPolicyOverride] = Field(default_factory=list) prepend_rules: list[ConfInlineRule] = Field(default_factory=list) append_rules: list[ConfInlineRule] = Field(default_factory=list) class ConfResolvedSource(BaseModel): key: str display_name: str source_type: str value: str enabled: bool = True cache_ttl: int | None = None options: dict[str, str] = Field(default_factory=dict) class ConfResolvedModule(BaseModel): key: str path: str policy: str order: int enabled: bool = True class ConfResolvedBuiltin(BaseModel): key: str rule_line: str policy: str order: int enabled: bool = True class ConfResolvedGroup(BaseModel): name: str group_type: str members: list[str] = Field(default_factory=list) selector_key: str | None = None url: str | None = None interval: int | None = None tolerance: int | None = None raw: str class ConfRuntimePlan(BaseModel): profile_key: str profile_name: str | None = None selected_sources: list[ConfResolvedSource] = Field(default_factory=list) selected_modules: list[ConfResolvedModule] = Field(default_factory=list) selected_builtins: list[ConfResolvedBuiltin] = Field(default_factory=list) selectors: dict[str, str] = Field(default_factory=dict) groups: list[ConfResolvedGroup] = Field(default_factory=list) prepend_rules: list[str] = Field(default_factory=list) append_rules: list[str] = Field(default_factory=list) mode: str | None = None allow_lan: bool | None = None log_level: str | None = None ipv6: bool | None = None append_userinfo_header: bool | None = None userinfo_source_policy: str | None = None