Fix geo_re_resolve async mocks and mark tasks complete

This commit is contained in:
2026-03-17 18:54:25 +01:00
parent 482399c9e2
commit bdcdd5d672
12 changed files with 208 additions and 136 deletions

View File

@@ -9,12 +9,17 @@ seconds by the background health-check task, not on every HTTP request.
from __future__ import annotations
from typing import Any
from typing import cast
import structlog
from app.models.server import ServerStatus
from app.utils.fail2ban_client import Fail2BanClient, Fail2BanConnectionError, Fail2BanProtocolError
from app.utils.fail2ban_client import (
Fail2BanClient,
Fail2BanConnectionError,
Fail2BanProtocolError,
Fail2BanResponse,
)
log: structlog.stdlib.BoundLogger = structlog.get_logger()
@@ -25,7 +30,7 @@ log: structlog.stdlib.BoundLogger = structlog.get_logger()
_SOCKET_TIMEOUT: float = 5.0
def _ok(response: Any) -> Any:
def _ok(response: object) -> object:
"""Extract the payload from a fail2ban ``(return_code, data)`` response.
fail2ban wraps every response in a ``(0, data)`` success tuple or
@@ -42,7 +47,7 @@ def _ok(response: Any) -> Any:
ValueError: If the response indicates an error (return code ≠ 0).
"""
try:
code, data = response
code, data = cast(Fail2BanResponse, response)
except (TypeError, ValueError) as exc:
raise ValueError(f"Unexpected fail2ban response shape: {response!r}") from exc
@@ -52,7 +57,7 @@ def _ok(response: Any) -> Any:
return data
def _to_dict(pairs: Any) -> dict[str, Any]:
def _to_dict(pairs: object) -> dict[str, object]:
"""Convert a list of ``(key, value)`` pairs to a plain dict.
fail2ban returns structured data as lists of 2-tuples rather than dicts.
@@ -66,7 +71,7 @@ def _to_dict(pairs: Any) -> dict[str, Any]:
"""
if not isinstance(pairs, (list, tuple)):
return {}
result: dict[str, Any] = {}
result: dict[str, object] = {}
for item in pairs:
try:
k, v = item
@@ -119,7 +124,7 @@ async def probe(socket_path: str, timeout: float = _SOCKET_TIMEOUT) -> ServerSta
# 3. Global status — jail count and names #
# ------------------------------------------------------------------ #
status_data = _to_dict(_ok(await client.send(["status"])))
active_jails: int = int(status_data.get("Number of jail", 0) or 0)
active_jails: int = int(str(status_data.get("Number of jail", 0) or 0))
jail_list_raw: str = str(status_data.get("Jail list", "") or "").strip()
jail_names: list[str] = (
[j.strip() for j in jail_list_raw.split(",") if j.strip()]
@@ -138,8 +143,8 @@ async def probe(socket_path: str, timeout: float = _SOCKET_TIMEOUT) -> ServerSta
jail_resp = _to_dict(_ok(await client.send(["status", jail_name])))
filter_stats = _to_dict(jail_resp.get("Filter") or [])
action_stats = _to_dict(jail_resp.get("Actions") or [])
total_failures += int(filter_stats.get("Currently failed", 0) or 0)
total_bans += int(action_stats.get("Currently banned", 0) or 0)
total_failures += int(str(filter_stats.get("Currently failed", 0) or 0))
total_bans += int(str(action_stats.get("Currently banned", 0) or 0))
except (ValueError, TypeError, KeyError) as exc:
log.warning(
"fail2ban_jail_status_parse_error",