Fix stale activation record on failed jail activation
Record activation only after a successful jail activate request and add regression coverage to prevent stale last_activation state.
This commit is contained in:
@@ -839,6 +839,24 @@ class TestActivateJail:
|
||||
|
||||
assert resp.status_code == 409
|
||||
|
||||
async def test_failed_activation_does_not_set_last_activation(
|
||||
self, config_client: AsyncClient
|
||||
) -> None:
|
||||
"""A failed activation must not leave a stale last_activation record."""
|
||||
from app.exceptions import Fail2BanConnectionError
|
||||
|
||||
config_client._transport.app.state.last_activation = None
|
||||
with patch(
|
||||
"app.routers.jail_config.jail_config_service.activate_jail",
|
||||
AsyncMock(side_effect=Fail2BanConnectionError("No socket", "/tmp/fake.sock")),
|
||||
):
|
||||
resp = await config_client.post(
|
||||
"/api/config/jails/sshd/activate", json={}
|
||||
)
|
||||
|
||||
assert resp.status_code == 502
|
||||
assert config_client._transport.app.state.last_activation is None
|
||||
|
||||
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
|
||||
"""POST /api/config/jails/ with bad name returns 400."""
|
||||
from app.exceptions import JailNameError
|
||||
@@ -1903,7 +1921,7 @@ class TestGetFail2BanLog:
|
||||
async def test_200_returns_log_response(self, config_client: AsyncClient) -> None:
|
||||
"""GET /api/config/fail2ban-log returns 200 with Fail2BanLogResponse."""
|
||||
with patch(
|
||||
"app.routers.config_misc.config_service.read_fail2ban_log",
|
||||
"app.routers.config_misc.log_service.read_fail2ban_log",
|
||||
AsyncMock(return_value=self._mock_log_response()),
|
||||
):
|
||||
resp = await config_client.get("/api/config/fail2ban-log")
|
||||
@@ -1918,7 +1936,7 @@ class TestGetFail2BanLog:
|
||||
async def test_200_passes_lines_query_param(self, config_client: AsyncClient) -> None:
|
||||
"""GET /api/config/fail2ban-log passes the lines query param to the service."""
|
||||
with patch(
|
||||
"app.routers.config_misc.config_service.read_fail2ban_log",
|
||||
"app.routers.config_misc.log_service.read_fail2ban_log",
|
||||
AsyncMock(return_value=self._mock_log_response()),
|
||||
) as mock_fn:
|
||||
resp = await config_client.get("/api/config/fail2ban-log?lines=500")
|
||||
@@ -1930,7 +1948,7 @@ class TestGetFail2BanLog:
|
||||
async def test_200_passes_filter_query_param(self, config_client: AsyncClient) -> None:
|
||||
"""GET /api/config/fail2ban-log passes the filter query param to the service."""
|
||||
with patch(
|
||||
"app.routers.config_misc.config_service.read_fail2ban_log",
|
||||
"app.routers.config_misc.log_service.read_fail2ban_log",
|
||||
AsyncMock(return_value=self._mock_log_response()),
|
||||
) as mock_fn:
|
||||
resp = await config_client.get("/api/config/fail2ban-log?filter=ERROR")
|
||||
@@ -1944,7 +1962,7 @@ class TestGetFail2BanLog:
|
||||
from app.services.config_service import ConfigOperationError
|
||||
|
||||
with patch(
|
||||
"app.routers.config_misc.config_service.read_fail2ban_log",
|
||||
"app.routers.config_misc.log_service.read_fail2ban_log",
|
||||
AsyncMock(side_effect=ConfigOperationError("fail2ban is logging to 'STDOUT'")),
|
||||
):
|
||||
resp = await config_client.get("/api/config/fail2ban-log")
|
||||
@@ -1956,7 +1974,7 @@ class TestGetFail2BanLog:
|
||||
from app.services.config_service import ConfigOperationError
|
||||
|
||||
with patch(
|
||||
"app.routers.config_misc.config_service.read_fail2ban_log",
|
||||
"app.routers.config_misc.log_service.read_fail2ban_log",
|
||||
AsyncMock(side_effect=ConfigOperationError("outside the allowed directory")),
|
||||
):
|
||||
resp = await config_client.get("/api/config/fail2ban-log")
|
||||
@@ -1968,7 +1986,7 @@ class TestGetFail2BanLog:
|
||||
from app.exceptions import Fail2BanConnectionError
|
||||
|
||||
with patch(
|
||||
"app.routers.config_misc.config_service.read_fail2ban_log",
|
||||
"app.routers.config_misc.log_service.read_fail2ban_log",
|
||||
AsyncMock(side_effect=Fail2BanConnectionError("socket error", "/tmp/f.sock")),
|
||||
):
|
||||
resp = await config_client.get("/api/config/fail2ban-log")
|
||||
@@ -2011,7 +2029,7 @@ class TestGetServiceStatus:
|
||||
async def test_200_when_online(self, config_client: AsyncClient) -> None:
|
||||
"""GET /api/config/service-status returns 200 with full status when online."""
|
||||
with patch(
|
||||
"app.routers.config_misc.config_service.get_service_status",
|
||||
"app.routers.config_misc.health_service.get_service_status",
|
||||
AsyncMock(return_value=self._mock_status(online=True)),
|
||||
):
|
||||
resp = await config_client.get("/api/config/service-status")
|
||||
@@ -2026,7 +2044,7 @@ class TestGetServiceStatus:
|
||||
async def test_200_when_offline(self, config_client: AsyncClient) -> None:
|
||||
"""GET /api/config/service-status returns 200 with offline=False when daemon is down."""
|
||||
with patch(
|
||||
"app.routers.config_misc.config_service.get_service_status",
|
||||
"app.routers.config_misc.health_service.get_service_status",
|
||||
AsyncMock(return_value=self._mock_status(online=False)),
|
||||
):
|
||||
resp = await config_client.get("/api/config/service-status")
|
||||
|
||||
Reference in New Issue
Block a user