Fix config status and missing historical filter imports

1) Added _get_active_jail_names import in jail_config_service 2) Added _get_active_jail_names and _parse_jails_sync imports in filter_config_service and resolved constants/exceptions 3) Added bangui_version=__version__ in config_service.get_service_status and tests
This commit is contained in:
2026-03-22 20:54:44 +01:00
parent 8e1b4fa978
commit ed184f1c84
4 changed files with 82 additions and 12 deletions

View File

@@ -15,7 +15,6 @@ from __future__ import annotations
import asyncio import asyncio
import contextlib import contextlib
import re import re
from collections.abc import Awaitable, Callable
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, TypeVar, cast from typing import TYPE_CHECKING, TypeVar, cast
@@ -24,8 +23,12 @@ import structlog
from app.utils.fail2ban_client import Fail2BanCommand, Fail2BanResponse, Fail2BanToken from app.utils.fail2ban_client import Fail2BanCommand, Fail2BanResponse, Fail2BanToken
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Awaitable, Callable
import aiosqlite import aiosqlite
from app import __version__
from app.exceptions import ConfigOperationError, ConfigValidationError, JailNotFoundError
from app.models.config import ( from app.models.config import (
AddLogPathRequest, AddLogPathRequest,
BantimeEscalation, BantimeEscalation,
@@ -44,11 +47,13 @@ from app.models.config import (
RegexTestResponse, RegexTestResponse,
ServiceStatusResponse, ServiceStatusResponse,
) )
from app.exceptions import ConfigOperationError, ConfigValidationError, JailNotFoundError
from app.utils.fail2ban_client import Fail2BanClient from app.utils.fail2ban_client import Fail2BanClient
from app.utils.log_utils import preview_log as util_preview_log, test_regex as util_test_regex from app.utils.log_utils import preview_log as util_preview_log
from app.utils.log_utils import test_regex as util_test_regex
from app.utils.setup_utils import ( from app.utils.setup_utils import (
get_map_color_thresholds as util_get_map_color_thresholds, get_map_color_thresholds as util_get_map_color_thresholds,
)
from app.utils.setup_utils import (
set_map_color_thresholds as util_set_map_color_thresholds, set_map_color_thresholds as util_set_map_color_thresholds,
) )
@@ -815,6 +820,7 @@ async def get_service_status(
return ServiceStatusResponse( return ServiceStatusResponse(
online=server_status.online, online=server_status.online,
version=server_status.version, version=server_status.version,
bangui_version=__version__,
jail_count=server_status.active_jails, jail_count=server_status.active_jails,
total_bans=server_status.total_bans, total_bans=server_status.total_bans,
total_failures=server_status.total_failures, total_failures=server_status.total_failures,

View File

@@ -17,16 +17,21 @@ from pathlib import Path
import structlog import structlog
from app.exceptions import FilterInvalidRegexError
from app.models.config import ( from app.models.config import (
AssignFilterRequest,
FilterConfig, FilterConfig,
FilterConfigUpdate, FilterConfigUpdate,
FilterCreateRequest, FilterCreateRequest,
FilterListResponse, FilterListResponse,
FilterUpdateRequest, FilterUpdateRequest,
AssignFilterRequest,
) )
from app.exceptions import FilterInvalidRegexError, JailNotFoundError from app.services.config_file_service import _TRUE_VALUES, ConfigWriteError, JailNotFoundInConfigError
from app.utils import conffile_parser from app.utils import conffile_parser
from app.utils.config_file_utils import (
_get_active_jail_names,
_parse_jails_sync,
)
from app.utils.jail_utils import reload_jails from app.utils.jail_utils import reload_jails
log: structlog.stdlib.BoundLogger = structlog.get_logger() log: structlog.stdlib.BoundLogger = structlog.get_logger()
@@ -90,6 +95,7 @@ class JailNameError(Exception):
"""Raised when a jail name contains invalid characters.""" """Raised when a jail name contains invalid characters."""
_SAFE_FILTER_NAME_RE: re.Pattern[str] = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$")
_SAFE_JAIL_NAME_RE: re.Pattern[str] = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$") _SAFE_JAIL_NAME_RE: re.Pattern[str] = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$")

View File

@@ -26,22 +26,17 @@ from app.models.config import (
InactiveJail, InactiveJail,
InactiveJailListResponse, InactiveJailListResponse,
JailActivationResponse, JailActivationResponse,
JailValidationIssue,
JailValidationResult, JailValidationResult,
RollbackResponse, RollbackResponse,
) )
from app.utils.config_file_utils import ( from app.utils.config_file_utils import (
_build_inactive_jail, _build_inactive_jail,
_ordered_config_files, _get_active_jail_names,
_parse_jails_sync, _parse_jails_sync,
_validate_jail_config_sync, _validate_jail_config_sync,
) )
from app.utils.fail2ban_client import Fail2BanClient
from app.utils.jail_utils import reload_jails from app.utils.jail_utils import reload_jails
from app.utils.fail2ban_client import (
Fail2BanClient,
Fail2BanConnectionError,
Fail2BanResponse,
)
log: structlog.stdlib.BoundLogger = structlog.get_logger() log: structlog.stdlib.BoundLogger = structlog.get_logger()

View File

@@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
from typing import Any from typing import Any
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
@@ -748,8 +749,11 @@ class TestGetServiceStatus:
probe_fn=AsyncMock(return_value=online_status), probe_fn=AsyncMock(return_value=online_status),
) )
from app import __version__
assert result.online is True assert result.online is True
assert result.version == "1.0.0" assert result.version == "1.0.0"
assert result.bangui_version == __version__
assert result.jail_count == 2 assert result.jail_count == 2
assert result.total_bans == 5 assert result.total_bans == 5
assert result.total_failures == 3 assert result.total_failures == 3
@@ -771,3 +775,62 @@ class TestGetServiceStatus:
assert result.jail_count == 0 assert result.jail_count == 0
assert result.log_level == "UNKNOWN" assert result.log_level == "UNKNOWN"
assert result.log_target == "UNKNOWN" assert result.log_target == "UNKNOWN"
@pytest.mark.asyncio
class TestConfigModuleIntegration:
async def test_jail_config_service_list_inactive_jails_uses_imports(self, tmp_path: Any) -> None:
from app.services.jail_config_service import list_inactive_jails
# Arrange: fake parse_jails output with one active and one inactive
def fake_parse_jails_sync(path: Path) -> tuple[dict[str, dict[str, str]], dict[str, str]]:
return (
{
"sshd": {
"enabled": "true",
"filter": "sshd",
"logpath": "/var/log/auth.log",
},
"apache-auth": {
"enabled": "false",
"filter": "apache-auth",
"logpath": "/var/log/apache2/error.log",
},
},
{
"sshd": str(path / "jail.conf"),
"apache-auth": str(path / "jail.conf"),
},
)
with patch(
"app.services.jail_config_service._parse_jails_sync",
new=fake_parse_jails_sync,
), patch(
"app.services.jail_config_service._get_active_jail_names",
new=AsyncMock(return_value={"sshd"}),
):
result = await list_inactive_jails(str(tmp_path), "/fake.sock")
names = {j.name for j in result.jails}
assert "apache-auth" in names
assert "sshd" not in names
async def test_filter_config_service_list_filters_uses_imports(self, tmp_path: Any) -> None:
from app.services.filter_config_service import list_filters
# Arrange minimal filter and jail config files
filter_d = tmp_path / "filter.d"
filter_d.mkdir(parents=True)
(filter_d / "sshd.conf").write_text("[Definition]\nfailregex = ^%(__prefix_line)s.*$\n")
(tmp_path / "jail.conf").write_text("[sshd]\nfilter = sshd\nenabled = true\n")
with patch(
"app.services.filter_config_service._get_active_jail_names",
new=AsyncMock(return_value={"sshd"}),
):
result = await list_filters(str(tmp_path), "/fake.sock")
assert result.total == 1
assert result.filters[0].name == "sshd"
assert result.filters[0].active is True