refactoring-backend #3

Merged
lukas.pupkalipinski merged 403 commits from refactoring-backend into main 2026-05-20 20:23:46 +02:00
4 changed files with 50 additions and 13 deletions
Showing only changes of commit 5a9d226cca - Show all commits

View File

@@ -252,7 +252,7 @@ Pure helper modules with no framework dependencies.
| `config_file_utils.py` | Common file-level config utility helpers |
| `fail2ban_db_utils.py` | Fail2ban DB path discovery and ban-history parsing helpers |
| `setup_utils.py` | Setup wizard helper utilities |
| `constants.py` | Shared constants: default socket path, default database path, time-range presets, limits |
| `constants.py` | Shared constants: default socket path, default database path, time-range presets, parser truthy values, limits |
#### Configuration (`app/config.py`)

View File

@@ -264,6 +264,7 @@ The helpers layer hides import cycles rather than eliminating them and adds thre
### Task 9 — Consolidate _TRUE_VALUES into constants.py
**Status:** Completed
**Severity:** Low (part of Task 6 cleanup)
**Where:**

View File

@@ -73,6 +73,7 @@ from app.models.config import (
RollbackResponse,
)
from app.utils import conffile_parser
from app.utils.constants import FAIL2BAN_TRUTHY_VALUES
from app.utils.async_utils import run_blocking
from app.utils.fail2ban_client import (
Fail2BanClient,
@@ -82,6 +83,7 @@ from app.utils.fail2ban_client import (
log: structlog.stdlib.BoundLogger = structlog.get_logger()
# Proxy object for jail reload operations. Tests can patch
# app.services.config_file_service.jail_service.reload_all as needed.
class _JailServiceProxy:
@@ -127,9 +129,6 @@ _SAFE_JAIL_NAME_RE: re.Pattern[str] = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,
# Sections that are not jail definitions.
_META_SECTIONS: frozenset[str] = frozenset({"INCLUDES", "DEFAULT"})
# True-ish values for the ``enabled`` key.
_TRUE_VALUES: frozenset[str] = frozenset({"true", "yes", "1"})
# False-ish values for the ``enabled`` key.
_FALSE_VALUES: frozenset[str] = frozenset({"false", "no", "0"})
@@ -230,7 +229,7 @@ def _is_truthy(value: str) -> bool:
Returns:
``True`` when the value represents enabled.
"""
return value.strip().lower() in _TRUE_VALUES
return value.strip().lower() in FAIL2BAN_TRUTHY_VALUES
def _parse_int_safe(value: str) -> int | None:
@@ -1026,8 +1025,10 @@ async def list_inactive_jails(
) -> InactiveJailListResponse:
"""Delegate to the canonical jail config service."""
from app.services.jail_config_service import list_inactive_jails as _delegate
return await _delegate(config_dir, socket_path)
async def activate_jail(
config_dir: str,
socket_path: str,
@@ -1036,8 +1037,10 @@ async def activate_jail(
) -> JailActivationResponse:
"""Delegate to the canonical jail config service."""
from app.services.jail_config_service import _activate_jail as _delegate
return await _delegate(config_dir, socket_path, name, req)
async def _rollback_activation_async(
config_dir: str,
name: str,
@@ -1069,7 +1072,7 @@ async def _rollback_activation_async(
# Step 1 — restore original file (or delete it).
try:
await run_blocking( _restore_local_file_sync, local_path, original_content)
await run_blocking(_restore_local_file_sync, local_path, original_content)
log.info("jail_activation_rollback_file_restored", jail=name)
except ConfigWriteError as exc:
log.error("jail_activation_rollback_restore_failed", jail=name, error=str(exc))
@@ -1102,8 +1105,10 @@ async def deactivate_jail(
) -> JailActivationResponse:
"""Delegate to the canonical jail config service."""
from app.services.jail_config_service import _deactivate_jail as _delegate
return await _delegate(config_dir, socket_path, name)
async def delete_jail_local_override(
config_dir: str,
socket_path: str,
@@ -1111,16 +1116,20 @@ async def delete_jail_local_override(
) -> None:
"""Delegate to the canonical jail config service."""
from app.services.jail_config_service import delete_jail_local_override as _delegate
return await _delegate(config_dir, socket_path, name)
async def validate_jail_config(
config_dir: str,
name: str,
) -> JailValidationResult:
"""Delegate to the canonical jail config service."""
from app.services.jail_config_service import validate_jail_config as _delegate
return await _delegate(config_dir, name)
async def rollback_jail(
config_dir: str,
socket_path: str,
@@ -1129,8 +1138,10 @@ async def rollback_jail(
) -> RollbackResponse:
"""Delegate to the canonical jail config helper."""
from app.services.jail_config_service import _rollback_jail as _delegate
return await _delegate(config_dir, socket_path, name, start_cmd_parts)
# ---------------------------------------------------------------------------
# Filter discovery helpers (Task 2.1)
# ---------------------------------------------------------------------------
@@ -1290,8 +1301,10 @@ async def list_filters(
) -> FilterListResponse:
"""Delegate to the canonical filter config service."""
from app.services.filter_config_service import list_filters as _delegate
return await _delegate(config_dir, socket_path)
async def get_filter(
config_dir: str,
socket_path: str,
@@ -1299,8 +1312,10 @@ async def get_filter(
) -> FilterConfig:
"""Delegate to the canonical filter config service."""
from app.services.filter_config_service import get_filter as _delegate
return await _delegate(config_dir, socket_path, name)
# ---------------------------------------------------------------------------
# Public API — filter write operations (Task 2.2)
# ---------------------------------------------------------------------------
@@ -1315,8 +1330,10 @@ async def update_filter(
) -> FilterConfig:
"""Delegate to the canonical filter config service."""
from app.services.filter_config_service import update_filter as _delegate
return await _delegate(config_dir, socket_path, name, req, do_reload=do_reload)
async def create_filter(
config_dir: str,
socket_path: str,
@@ -1325,16 +1342,20 @@ async def create_filter(
) -> FilterConfig:
"""Delegate to the canonical filter config service."""
from app.services.filter_config_service import create_filter as _delegate
return await _delegate(config_dir, socket_path, req, do_reload=do_reload)
async def delete_filter(
config_dir: str,
name: str,
) -> None:
"""Delegate to the canonical filter config service."""
from app.services.filter_config_service import delete_filter as _delegate
return await _delegate(config_dir, name)
async def assign_filter_to_jail(
config_dir: str,
socket_path: str,
@@ -1344,8 +1365,10 @@ async def assign_filter_to_jail(
) -> None:
"""Delegate to the canonical filter config service."""
from app.services.filter_config_service import assign_filter_to_jail as _delegate
return await _delegate(config_dir, socket_path, jail_name, req, do_reload=do_reload)
# ---------------------------------------------------------------------------
# Action discovery helpers (Task 3.1)
# ---------------------------------------------------------------------------
@@ -1727,8 +1750,10 @@ async def list_actions(
) -> ActionListResponse:
"""Delegate to the canonical action config service."""
from app.services.action_config_service import list_actions as _delegate
return await _delegate(config_dir, socket_path)
async def get_action(
config_dir: str,
socket_path: str,
@@ -1736,8 +1761,10 @@ async def get_action(
) -> ActionConfig:
"""Delegate to the canonical action config service."""
from app.services.action_config_service import get_action as _delegate
return await _delegate(config_dir, socket_path, name)
# ---------------------------------------------------------------------------
# Public API — action write operations (Task 3.2)
# ---------------------------------------------------------------------------
@@ -1752,8 +1779,10 @@ async def update_action(
) -> ActionConfig:
"""Delegate to the canonical action config service."""
from app.services.action_config_service import update_action as _delegate
return await _delegate(config_dir, socket_path, name, req, do_reload=do_reload)
async def create_action(
config_dir: str,
socket_path: str,
@@ -1762,16 +1791,20 @@ async def create_action(
) -> ActionConfig:
"""Delegate to the canonical action config service."""
from app.services.action_config_service import create_action as _delegate
return await _delegate(config_dir, socket_path, req, do_reload=do_reload)
async def delete_action(
config_dir: str,
name: str,
) -> None:
"""Delegate to the canonical action config service."""
from app.services.action_config_service import delete_action as _delegate
return await _delegate(config_dir, name)
async def assign_action_to_jail(
config_dir: str,
socket_path: str,
@@ -1805,8 +1838,7 @@ async def assign_action_to_jail(
_safe_jail_name(jail_name)
_safe_action_name(req.action_name)
all_jails, _src = await run_blocking( _parse_jails_sync, Path(config_dir))
all_jails, _src = await run_blocking(_parse_jails_sync, Path(config_dir))
if jail_name not in all_jails:
raise JailNotFoundInConfigError(jail_name)
@@ -1819,7 +1851,7 @@ async def assign_action_to_jail(
):
raise ActionNotFoundError(req.action_name)
await run_blocking( _check_action)
await run_blocking(_check_action)
# Build the action string with optional parameters.
if req.params:
@@ -1828,7 +1860,8 @@ async def assign_action_to_jail(
else:
action_entry = req.action_name
await run_blocking(_append_jail_action_sync,
await run_blocking(
_append_jail_action_sync,
Path(config_dir),
jail_name,
action_entry,
@@ -1882,12 +1915,12 @@ async def remove_action_from_jail(
_safe_jail_name(jail_name)
_safe_action_name(action_name)
all_jails, _src = await run_blocking( _parse_jails_sync, Path(config_dir))
all_jails, _src = await run_blocking(_parse_jails_sync, Path(config_dir))
if jail_name not in all_jails:
raise JailNotFoundInConfigError(jail_name)
await run_blocking(_remove_jail_action_sync,
await run_blocking(
_remove_jail_action_sync,
Path(config_dir),
jail_name,
action_name,

View File

@@ -16,6 +16,9 @@ DEFAULT_FAIL2BAN_SOCKET: Final[str] = "/var/run/fail2ban/fail2ban.sock"
FAIL2BAN_SOCKET_TIMEOUT_SECONDS: Final[float] = 5.0
"""Maximum seconds to wait for a response from the fail2ban socket."""
FAIL2BAN_TRUTHY_VALUES: Final[frozenset[str]] = frozenset({"true", "yes", "1"})
"""String values treated as boolean true by fail2ban configuration parsers."""
# ---------------------------------------------------------------------------
# Database
# ---------------------------------------------------------------------------