|
|
|
|
@@ -101,7 +101,7 @@ class TestGetJailConfigs:
|
|
|
|
|
jails=[_make_jail_config("sshd")], total=1
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.list_jail_configs",
|
|
|
|
|
"app.routers.jail_config.config_service.list_jail_configs",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/jails")
|
|
|
|
|
@@ -124,7 +124,7 @@ class TestGetJailConfigs:
|
|
|
|
|
from app.utils.fail2ban_client import Fail2BanConnectionError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.list_jail_configs",
|
|
|
|
|
"app.routers.jail_config.config_service.list_jail_configs",
|
|
|
|
|
AsyncMock(side_effect=Fail2BanConnectionError("down", "/tmp/fake.sock")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/jails")
|
|
|
|
|
@@ -144,7 +144,7 @@ class TestGetJailConfig:
|
|
|
|
|
"""GET /api/config/jails/sshd returns 200 with JailConfigResponse."""
|
|
|
|
|
mock_response = JailConfigResponse(jail=_make_jail_config("sshd"))
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.get_jail_config",
|
|
|
|
|
"app.routers.jail_config.config_service.get_jail_config",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/jails/sshd")
|
|
|
|
|
@@ -158,7 +158,7 @@ class TestGetJailConfig:
|
|
|
|
|
from app.services.config_service import JailNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.get_jail_config",
|
|
|
|
|
"app.routers.jail_config.config_service.get_jail_config",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/jails/missing")
|
|
|
|
|
@@ -185,7 +185,7 @@ class TestUpdateJailConfig:
|
|
|
|
|
async def test_204_on_success(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""PUT /api/config/jails/sshd returns 204 on success."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.update_jail_config",
|
|
|
|
|
"app.routers.jail_config.config_service.update_jail_config",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -200,7 +200,7 @@ class TestUpdateJailConfig:
|
|
|
|
|
from app.services.config_service import JailNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.update_jail_config",
|
|
|
|
|
"app.routers.jail_config.config_service.update_jail_config",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -215,7 +215,7 @@ class TestUpdateJailConfig:
|
|
|
|
|
from app.services.config_service import ConfigValidationError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.update_jail_config",
|
|
|
|
|
"app.routers.jail_config.config_service.update_jail_config",
|
|
|
|
|
AsyncMock(side_effect=ConfigValidationError("bad regex")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -230,7 +230,7 @@ class TestUpdateJailConfig:
|
|
|
|
|
from app.services.config_service import ConfigOperationError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.update_jail_config",
|
|
|
|
|
"app.routers.jail_config.config_service.update_jail_config",
|
|
|
|
|
AsyncMock(side_effect=ConfigOperationError("set failed")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -243,7 +243,7 @@ class TestUpdateJailConfig:
|
|
|
|
|
async def test_204_with_dns_mode(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""PUT /api/config/jails/sshd accepts dns_mode field."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.update_jail_config",
|
|
|
|
|
"app.routers.jail_config.config_service.update_jail_config",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -256,7 +256,7 @@ class TestUpdateJailConfig:
|
|
|
|
|
async def test_204_with_prefregex(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""PUT /api/config/jails/sshd accepts prefregex field."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.update_jail_config",
|
|
|
|
|
"app.routers.jail_config.config_service.update_jail_config",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -269,7 +269,7 @@ class TestUpdateJailConfig:
|
|
|
|
|
async def test_204_with_date_pattern(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""PUT /api/config/jails/sshd accepts date_pattern field."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.update_jail_config",
|
|
|
|
|
"app.routers.jail_config.config_service.update_jail_config",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -297,7 +297,7 @@ class TestGetGlobalConfig:
|
|
|
|
|
db_max_matches=10,
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.get_global_config",
|
|
|
|
|
"app.routers.config_misc.config_service.get_global_config",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/global")
|
|
|
|
|
@@ -327,7 +327,7 @@ class TestUpdateGlobalConfig:
|
|
|
|
|
async def test_204_on_success(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""PUT /api/config/global returns 204 on success."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.update_global_config",
|
|
|
|
|
"app.routers.config_misc.config_service.update_global_config",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -342,7 +342,7 @@ class TestUpdateGlobalConfig:
|
|
|
|
|
from app.services.config_service import ConfigOperationError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.update_global_config",
|
|
|
|
|
"app.routers.config_misc.config_service.update_global_config",
|
|
|
|
|
AsyncMock(side_effect=ConfigOperationError("set failed")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -364,7 +364,7 @@ class TestReloadFail2ban:
|
|
|
|
|
async def test_204_on_success(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/reload returns 204 on success."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_service.reload_all",
|
|
|
|
|
"app.routers.config_misc.jail_service.reload_all",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/reload")
|
|
|
|
|
@@ -376,7 +376,7 @@ class TestReloadFail2ban:
|
|
|
|
|
from app.utils.fail2ban_client import Fail2BanConnectionError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_service.reload_all",
|
|
|
|
|
"app.routers.config_misc.jail_service.reload_all",
|
|
|
|
|
AsyncMock(side_effect=Fail2BanConnectionError("no socket", "/fake.sock")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/reload")
|
|
|
|
|
@@ -388,7 +388,7 @@ class TestReloadFail2ban:
|
|
|
|
|
from app.services.jail_service import JailOperationError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_service.reload_all",
|
|
|
|
|
"app.routers.config_misc.jail_service.reload_all",
|
|
|
|
|
AsyncMock(side_effect=JailOperationError("reload rejected")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/reload")
|
|
|
|
|
@@ -408,15 +408,15 @@ class TestRestartFail2ban:
|
|
|
|
|
"""POST /api/config/restart returns 204 when fail2ban restarts cleanly."""
|
|
|
|
|
with (
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.jail_service.restart",
|
|
|
|
|
"app.routers.config_misc.jail_service.restart",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
),
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.config_file_service.start_daemon",
|
|
|
|
|
"app.routers.config_misc.config_file_service.start_daemon",
|
|
|
|
|
AsyncMock(return_value=True),
|
|
|
|
|
),
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.config_file_service.wait_for_fail2ban",
|
|
|
|
|
"app.routers.config_misc.config_file_service.wait_for_fail2ban",
|
|
|
|
|
AsyncMock(return_value=True),
|
|
|
|
|
),
|
|
|
|
|
):
|
|
|
|
|
@@ -428,15 +428,15 @@ class TestRestartFail2ban:
|
|
|
|
|
"""POST /api/config/restart returns 503 when fail2ban does not come back online."""
|
|
|
|
|
with (
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.jail_service.restart",
|
|
|
|
|
"app.routers.config_misc.jail_service.restart",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
),
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.config_file_service.start_daemon",
|
|
|
|
|
"app.routers.config_misc.config_file_service.start_daemon",
|
|
|
|
|
AsyncMock(return_value=True),
|
|
|
|
|
),
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.config_file_service.wait_for_fail2ban",
|
|
|
|
|
"app.routers.config_misc.config_file_service.wait_for_fail2ban",
|
|
|
|
|
AsyncMock(return_value=False),
|
|
|
|
|
),
|
|
|
|
|
):
|
|
|
|
|
@@ -449,7 +449,7 @@ class TestRestartFail2ban:
|
|
|
|
|
from app.services.jail_service import JailOperationError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_service.restart",
|
|
|
|
|
"app.routers.config_misc.jail_service.restart",
|
|
|
|
|
AsyncMock(side_effect=JailOperationError("stop failed")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/restart")
|
|
|
|
|
@@ -461,7 +461,7 @@ class TestRestartFail2ban:
|
|
|
|
|
from app.utils.fail2ban_client import Fail2BanConnectionError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_service.restart",
|
|
|
|
|
"app.routers.config_misc.jail_service.restart",
|
|
|
|
|
AsyncMock(side_effect=Fail2BanConnectionError("no socket", "/fake.sock")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/restart")
|
|
|
|
|
@@ -473,15 +473,15 @@ class TestRestartFail2ban:
|
|
|
|
|
mock_start = AsyncMock(return_value=True)
|
|
|
|
|
with (
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.jail_service.restart",
|
|
|
|
|
"app.routers.config_misc.jail_service.restart",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
),
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.config_file_service.start_daemon",
|
|
|
|
|
"app.routers.config_misc.config_file_service.start_daemon",
|
|
|
|
|
mock_start,
|
|
|
|
|
),
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.config_file_service.wait_for_fail2ban",
|
|
|
|
|
"app.routers.config_misc.config_file_service.wait_for_fail2ban",
|
|
|
|
|
AsyncMock(return_value=True),
|
|
|
|
|
),
|
|
|
|
|
):
|
|
|
|
|
@@ -502,7 +502,7 @@ class TestRegexTest:
|
|
|
|
|
"""POST /api/config/regex-test returns matched=true for a valid match."""
|
|
|
|
|
mock_response = RegexTestResponse(matched=True, groups=["1.2.3.4"], error=None)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.log_service.test_regex",
|
|
|
|
|
"app.routers.config_misc.log_service.test_regex",
|
|
|
|
|
return_value=mock_response,
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -520,7 +520,7 @@ class TestRegexTest:
|
|
|
|
|
"""POST /api/config/regex-test returns matched=false for no match."""
|
|
|
|
|
mock_response = RegexTestResponse(matched=False, groups=[], error=None)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.log_service.test_regex",
|
|
|
|
|
"app.routers.config_misc.log_service.test_regex",
|
|
|
|
|
return_value=mock_response,
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -554,7 +554,7 @@ class TestAddLogPath:
|
|
|
|
|
async def test_204_on_success(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/sshd/logpath returns 204 on success."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.add_log_path",
|
|
|
|
|
"app.routers.jail_config.config_service.add_log_path",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -569,7 +569,7 @@ class TestAddLogPath:
|
|
|
|
|
from app.services.config_service import JailNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.add_log_path",
|
|
|
|
|
"app.routers.jail_config.config_service.add_log_path",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -598,7 +598,7 @@ class TestPreviewLog:
|
|
|
|
|
matched_count=1,
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.log_service.preview_log",
|
|
|
|
|
"app.routers.config_misc.log_service.preview_log",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -726,7 +726,7 @@ class TestGetInactiveJails:
|
|
|
|
|
mock_response = InactiveJailListResponse(jails=[mock_jail], total=1)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.list_inactive_jails",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.list_inactive_jails",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/jails/inactive")
|
|
|
|
|
@@ -741,7 +741,7 @@ class TestGetInactiveJails:
|
|
|
|
|
from app.models.config import InactiveJailListResponse
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.list_inactive_jails",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.list_inactive_jails",
|
|
|
|
|
AsyncMock(return_value=InactiveJailListResponse(jails=[], total=0)),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/jails/inactive")
|
|
|
|
|
@@ -777,7 +777,7 @@ class TestActivateJail:
|
|
|
|
|
message="Jail 'apache-auth' activated successfully.",
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -797,7 +797,7 @@ class TestActivateJail:
|
|
|
|
|
name="apache-auth", active=True, message="Activated."
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
) as mock_activate:
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -816,7 +816,7 @@ class TestActivateJail:
|
|
|
|
|
from app.services.jail_config_service import JailNotFoundInConfigError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -830,7 +830,7 @@ class TestActivateJail:
|
|
|
|
|
from app.services.jail_config_service import JailAlreadyActiveError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailAlreadyActiveError("sshd")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -841,10 +841,10 @@ class TestActivateJail:
|
|
|
|
|
|
|
|
|
|
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/ with bad name returns 400."""
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
from app.exceptions import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError("bad name")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -873,7 +873,7 @@ class TestActivateJail:
|
|
|
|
|
message="Jail 'airsonic-auth' cannot be activated: log file '/var/log/airsonic/airsonic.log' not found",
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(return_value=blocked_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -906,7 +906,7 @@ class TestDeactivateJail:
|
|
|
|
|
message="Jail 'sshd' deactivated successfully.",
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.deactivate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.deactivate_jail",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/sshd/deactivate")
|
|
|
|
|
@@ -921,7 +921,7 @@ class TestDeactivateJail:
|
|
|
|
|
from app.services.jail_config_service import JailNotFoundInConfigError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.deactivate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.deactivate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -935,7 +935,7 @@ class TestDeactivateJail:
|
|
|
|
|
from app.services.jail_config_service import JailAlreadyInactiveError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.deactivate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.deactivate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailAlreadyInactiveError("apache-auth")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -946,10 +946,10 @@ class TestDeactivateJail:
|
|
|
|
|
|
|
|
|
|
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/.../deactivate with bad name returns 400."""
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
from app.exceptions import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.deactivate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.deactivate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -977,7 +977,7 @@ class TestDeactivateJail:
|
|
|
|
|
)
|
|
|
|
|
with (
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.jail_config_service._deactivate_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service._deactivate_jail",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
),
|
|
|
|
|
patch(
|
|
|
|
|
@@ -1028,7 +1028,7 @@ class TestListFilters:
|
|
|
|
|
total=1,
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.list_filters",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.list_filters",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/filters")
|
|
|
|
|
@@ -1044,7 +1044,7 @@ class TestListFilters:
|
|
|
|
|
from app.models.config import FilterListResponse
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.list_filters",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.list_filters",
|
|
|
|
|
AsyncMock(return_value=FilterListResponse(filters=[], total=0)),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/filters")
|
|
|
|
|
@@ -1067,7 +1067,7 @@ class TestListFilters:
|
|
|
|
|
total=2,
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.list_filters",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.list_filters",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/filters")
|
|
|
|
|
@@ -1096,7 +1096,7 @@ class TestGetFilter:
|
|
|
|
|
async def test_200_returns_filter(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""GET /api/config/filters/sshd returns 200 with FilterConfig."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.get_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.get_filter",
|
|
|
|
|
AsyncMock(return_value=_make_filter_config("sshd")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/filters/sshd")
|
|
|
|
|
@@ -1112,7 +1112,7 @@ class TestGetFilter:
|
|
|
|
|
from app.services.filter_config_service import FilterNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.get_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.get_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/filters/missing")
|
|
|
|
|
@@ -1139,7 +1139,7 @@ class TestUpdateFilter:
|
|
|
|
|
async def test_200_returns_updated_filter(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""PUT /api/config/filters/sshd returns 200 with updated FilterConfig."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.update_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.update_filter",
|
|
|
|
|
AsyncMock(return_value=_make_filter_config("sshd")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1155,7 +1155,7 @@ class TestUpdateFilter:
|
|
|
|
|
from app.services.filter_config_service import FilterNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.update_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.update_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1170,7 +1170,7 @@ class TestUpdateFilter:
|
|
|
|
|
from app.services.filter_config_service import FilterInvalidRegexError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.update_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.update_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterInvalidRegexError("[bad", "unterminated")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1182,10 +1182,10 @@ class TestUpdateFilter:
|
|
|
|
|
|
|
|
|
|
async def test_400_for_invalid_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""PUT /api/config/filters/... with bad name returns 400."""
|
|
|
|
|
from app.services.filter_config_service import FilterNameError
|
|
|
|
|
from app.exceptions import FilterNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.update_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.update_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1198,7 +1198,7 @@ class TestUpdateFilter:
|
|
|
|
|
async def test_reload_query_param_passed(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""PUT /api/config/filters/sshd?reload=true passes do_reload=True."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.update_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.update_filter",
|
|
|
|
|
AsyncMock(return_value=_make_filter_config("sshd")),
|
|
|
|
|
) as mock_update:
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1229,7 +1229,7 @@ class TestCreateFilter:
|
|
|
|
|
async def test_201_creates_filter(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/filters returns 201 with FilterConfig."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.create_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.create_filter",
|
|
|
|
|
AsyncMock(return_value=_make_filter_config("my-custom")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1245,7 +1245,7 @@ class TestCreateFilter:
|
|
|
|
|
from app.services.filter_config_service import FilterAlreadyExistsError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.create_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.create_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterAlreadyExistsError("sshd")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1260,7 +1260,7 @@ class TestCreateFilter:
|
|
|
|
|
from app.services.filter_config_service import FilterInvalidRegexError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.create_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.create_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterInvalidRegexError("[bad", "unterminated")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1272,10 +1272,10 @@ class TestCreateFilter:
|
|
|
|
|
|
|
|
|
|
async def test_400_for_invalid_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/filters returns 400 for invalid filter name."""
|
|
|
|
|
from app.services.filter_config_service import FilterNameError
|
|
|
|
|
from app.exceptions import FilterNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.create_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.create_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1305,7 +1305,7 @@ class TestDeleteFilter:
|
|
|
|
|
async def test_204_deletes_filter(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""DELETE /api/config/filters/my-custom returns 204."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.delete_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.delete_filter",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/filters/my-custom")
|
|
|
|
|
@@ -1317,7 +1317,7 @@ class TestDeleteFilter:
|
|
|
|
|
from app.services.filter_config_service import FilterNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.delete_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.delete_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/filters/missing")
|
|
|
|
|
@@ -1329,7 +1329,7 @@ class TestDeleteFilter:
|
|
|
|
|
from app.services.filter_config_service import FilterReadonlyError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.delete_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.delete_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterReadonlyError("sshd")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/filters/sshd")
|
|
|
|
|
@@ -1338,10 +1338,10 @@ class TestDeleteFilter:
|
|
|
|
|
|
|
|
|
|
async def test_400_for_invalid_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""DELETE /api/config/filters/... with bad name returns 400."""
|
|
|
|
|
from app.services.filter_config_service import FilterNameError
|
|
|
|
|
from app.exceptions import FilterNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.delete_filter",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.delete_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/filters/bad")
|
|
|
|
|
@@ -1368,7 +1368,7 @@ class TestAssignFilterToJail:
|
|
|
|
|
async def test_204_assigns_filter(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/sshd/filter returns 204 on success."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1383,7 +1383,7 @@ class TestAssignFilterToJail:
|
|
|
|
|
from app.services.jail_config_service import JailNotFoundInConfigError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1398,7 +1398,7 @@ class TestAssignFilterToJail:
|
|
|
|
|
from app.services.filter_config_service import FilterNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(side_effect=FilterNotFoundError("missing-filter")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1410,10 +1410,10 @@ class TestAssignFilterToJail:
|
|
|
|
|
|
|
|
|
|
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/.../filter with bad jail name returns 400."""
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
from app.exceptions import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1425,10 +1425,10 @@ class TestAssignFilterToJail:
|
|
|
|
|
|
|
|
|
|
async def test_400_for_invalid_filter_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/sshd/filter with bad filter name returns 400."""
|
|
|
|
|
from app.services.filter_config_service import FilterNameError
|
|
|
|
|
from app.exceptions import FilterNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(side_effect=FilterNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1441,7 +1441,7 @@ class TestAssignFilterToJail:
|
|
|
|
|
async def test_reload_query_param_passed(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/sshd/filter?reload=true passes do_reload=True."""
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.filter_config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
) as mock_assign:
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1479,7 +1479,7 @@ class TestListActionsRouter:
|
|
|
|
|
mock_response = ActionListResponse(actions=[mock_action], total=1)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.list_actions",
|
|
|
|
|
"app.routers.action_config.action_config_service.list_actions",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/actions")
|
|
|
|
|
@@ -1497,7 +1497,7 @@ class TestListActionsRouter:
|
|
|
|
|
mock_response = ActionListResponse(actions=[inactive, active], total=2)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.list_actions",
|
|
|
|
|
"app.routers.action_config.action_config_service.list_actions",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/actions")
|
|
|
|
|
@@ -1525,7 +1525,7 @@ class TestGetActionRouter:
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.get_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.get_action",
|
|
|
|
|
AsyncMock(return_value=mock_action),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/actions/iptables")
|
|
|
|
|
@@ -1537,7 +1537,7 @@ class TestGetActionRouter:
|
|
|
|
|
from app.services.action_config_service import ActionNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.get_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.get_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/actions/missing")
|
|
|
|
|
@@ -1564,7 +1564,7 @@ class TestUpdateActionRouter:
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.update_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.update_action",
|
|
|
|
|
AsyncMock(return_value=updated),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1579,7 +1579,7 @@ class TestUpdateActionRouter:
|
|
|
|
|
from app.services.action_config_service import ActionNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.update_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.update_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1589,10 +1589,10 @@ class TestUpdateActionRouter:
|
|
|
|
|
assert resp.status_code == 404
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.action_config_service import ActionNameError
|
|
|
|
|
from app.exceptions import ActionNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.update_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.update_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1621,7 +1621,7 @@ class TestCreateActionRouter:
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.create_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.create_action",
|
|
|
|
|
AsyncMock(return_value=created),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1636,7 +1636,7 @@ class TestCreateActionRouter:
|
|
|
|
|
from app.services.action_config_service import ActionAlreadyExistsError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.create_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.create_action",
|
|
|
|
|
AsyncMock(side_effect=ActionAlreadyExistsError("iptables")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1647,10 +1647,10 @@ class TestCreateActionRouter:
|
|
|
|
|
assert resp.status_code == 409
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.action_config_service import ActionNameError
|
|
|
|
|
from app.exceptions import ActionNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.create_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.create_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1672,7 +1672,7 @@ class TestCreateActionRouter:
|
|
|
|
|
class TestDeleteActionRouter:
|
|
|
|
|
async def test_204_on_delete(self, config_client: AsyncClient) -> None:
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.delete_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.delete_action",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/actions/custom")
|
|
|
|
|
@@ -1683,7 +1683,7 @@ class TestDeleteActionRouter:
|
|
|
|
|
from app.services.action_config_service import ActionNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.delete_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.delete_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/actions/missing")
|
|
|
|
|
@@ -1694,7 +1694,7 @@ class TestDeleteActionRouter:
|
|
|
|
|
from app.services.action_config_service import ActionReadonlyError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.delete_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.delete_action",
|
|
|
|
|
AsyncMock(side_effect=ActionReadonlyError("iptables")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/actions/iptables")
|
|
|
|
|
@@ -1702,10 +1702,10 @@ class TestDeleteActionRouter:
|
|
|
|
|
assert resp.status_code == 409
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.action_config_service import ActionNameError
|
|
|
|
|
from app.exceptions import ActionNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.delete_action",
|
|
|
|
|
"app.routers.action_config.action_config_service.delete_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/actions/badname")
|
|
|
|
|
@@ -1724,7 +1724,7 @@ class TestDeleteActionRouter:
|
|
|
|
|
class TestAssignActionToJailRouter:
|
|
|
|
|
async def test_204_on_success(self, config_client: AsyncClient) -> None:
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1738,7 +1738,7 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
from app.services.jail_config_service import JailNotFoundInConfigError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1752,7 +1752,7 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
from app.services.action_config_service import ActionNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(side_effect=ActionNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1763,10 +1763,10 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
assert resp.status_code == 404
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_jail_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
from app.exceptions import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1777,10 +1777,10 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
assert resp.status_code == 400
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_action_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.action_config_service import ActionNameError
|
|
|
|
|
from app.exceptions import ActionNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(side_effect=ActionNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1792,7 +1792,7 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
|
|
|
|
|
async def test_reload_param_passed(self, config_client: AsyncClient) -> None:
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
) as mock_assign:
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1815,7 +1815,7 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
class TestRemoveActionFromJailRouter:
|
|
|
|
|
async def test_204_on_success(self, config_client: AsyncClient) -> None:
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.remove_action_from_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.remove_action_from_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete(
|
|
|
|
|
@@ -1828,7 +1828,7 @@ class TestRemoveActionFromJailRouter:
|
|
|
|
|
from app.services.jail_config_service import JailNotFoundInConfigError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.remove_action_from_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.remove_action_from_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete(
|
|
|
|
|
@@ -1838,10 +1838,10 @@ class TestRemoveActionFromJailRouter:
|
|
|
|
|
assert resp.status_code == 404
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_jail_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
from app.exceptions import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.remove_action_from_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.remove_action_from_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete(
|
|
|
|
|
@@ -1851,10 +1851,10 @@ class TestRemoveActionFromJailRouter:
|
|
|
|
|
assert resp.status_code == 400
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_action_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.action_config_service import ActionNameError
|
|
|
|
|
from app.exceptions import ActionNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.remove_action_from_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.remove_action_from_jail",
|
|
|
|
|
AsyncMock(side_effect=ActionNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete(
|
|
|
|
|
@@ -1865,7 +1865,7 @@ class TestRemoveActionFromJailRouter:
|
|
|
|
|
|
|
|
|
|
async def test_reload_param_passed(self, config_client: AsyncClient) -> None:
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.action_config_service.remove_action_from_jail",
|
|
|
|
|
"app.routers.action_config.action_config_service.remove_action_from_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
) as mock_rm:
|
|
|
|
|
resp = await config_client.delete(
|
|
|
|
|
@@ -1903,7 +1903,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.config_service.read_fail2ban_log",
|
|
|
|
|
"app.routers.config_misc.config_service.read_fail2ban_log",
|
|
|
|
|
AsyncMock(return_value=self._mock_log_response()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/fail2ban-log")
|
|
|
|
|
@@ -1918,7 +1918,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.config_service.read_fail2ban_log",
|
|
|
|
|
"app.routers.config_misc.config_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 +1930,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.config_service.read_fail2ban_log",
|
|
|
|
|
"app.routers.config_misc.config_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 +1944,7 @@ class TestGetFail2BanLog:
|
|
|
|
|
from app.services.config_service import ConfigOperationError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.read_fail2ban_log",
|
|
|
|
|
"app.routers.config_misc.config_service.read_fail2ban_log",
|
|
|
|
|
AsyncMock(side_effect=ConfigOperationError("fail2ban is logging to 'STDOUT'")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/fail2ban-log")
|
|
|
|
|
@@ -1956,7 +1956,7 @@ class TestGetFail2BanLog:
|
|
|
|
|
from app.services.config_service import ConfigOperationError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.read_fail2ban_log",
|
|
|
|
|
"app.routers.config_misc.config_service.read_fail2ban_log",
|
|
|
|
|
AsyncMock(side_effect=ConfigOperationError("outside the allowed directory")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/fail2ban-log")
|
|
|
|
|
@@ -1968,7 +1968,7 @@ class TestGetFail2BanLog:
|
|
|
|
|
from app.utils.fail2ban_client import Fail2BanConnectionError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_service.read_fail2ban_log",
|
|
|
|
|
"app.routers.config_misc.config_service.read_fail2ban_log",
|
|
|
|
|
AsyncMock(side_effect=Fail2BanConnectionError("socket error", "/tmp/f.sock")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/fail2ban-log")
|
|
|
|
|
@@ -2011,7 +2011,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.config_service.get_service_status",
|
|
|
|
|
"app.routers.config_misc.config_service.get_service_status",
|
|
|
|
|
AsyncMock(return_value=self._mock_status(online=True)),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/service-status")
|
|
|
|
|
@@ -2026,7 +2026,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.config_service.get_service_status",
|
|
|
|
|
"app.routers.config_misc.config_service.get_service_status",
|
|
|
|
|
AsyncMock(return_value=self._mock_status(online=False)),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/service-status")
|
|
|
|
|
@@ -2063,7 +2063,7 @@ class TestValidateJailEndpoint:
|
|
|
|
|
jail_name="sshd", valid=True, issues=[]
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.validate_jail_config",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.validate_jail_config",
|
|
|
|
|
AsyncMock(return_value=mock_result),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/sshd/validate")
|
|
|
|
|
@@ -2083,7 +2083,7 @@ class TestValidateJailEndpoint:
|
|
|
|
|
jail_name="sshd", valid=False, issues=[issue]
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.validate_jail_config",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.validate_jail_config",
|
|
|
|
|
AsyncMock(return_value=mock_result),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/sshd/validate")
|
|
|
|
|
@@ -2096,10 +2096,10 @@ class TestValidateJailEndpoint:
|
|
|
|
|
|
|
|
|
|
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/bad-name/validate returns 400 on JailNameError."""
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
from app.exceptions import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.validate_jail_config",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.validate_jail_config",
|
|
|
|
|
AsyncMock(side_effect=JailNameError("bad name")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/bad-name/validate")
|
|
|
|
|
@@ -2126,7 +2126,7 @@ class TestPendingRecovery:
|
|
|
|
|
app = config_client._transport.app # type: ignore[attr-defined]
|
|
|
|
|
app.state.pending_recovery = None
|
|
|
|
|
|
|
|
|
|
resp = await config_client.get("/api/config/pending-recovery")
|
|
|
|
|
resp = await config_client.get("/api/config/jails/pending-recovery")
|
|
|
|
|
|
|
|
|
|
assert resp.status_code == 200
|
|
|
|
|
assert resp.json() is None
|
|
|
|
|
@@ -2146,7 +2146,7 @@ class TestPendingRecovery:
|
|
|
|
|
app = config_client._transport.app # type: ignore[attr-defined]
|
|
|
|
|
app.state.pending_recovery = record
|
|
|
|
|
|
|
|
|
|
resp = await config_client.get("/api/config/pending-recovery")
|
|
|
|
|
resp = await config_client.get("/api/config/jails/pending-recovery")
|
|
|
|
|
|
|
|
|
|
assert resp.status_code == 200
|
|
|
|
|
data = resp.json()
|
|
|
|
|
@@ -2158,7 +2158,7 @@ class TestPendingRecovery:
|
|
|
|
|
resp = await AsyncClient(
|
|
|
|
|
transport=ASGITransport(app=config_client._transport.app), # type: ignore[attr-defined]
|
|
|
|
|
base_url="http://test",
|
|
|
|
|
).get("/api/config/pending-recovery")
|
|
|
|
|
).get("/api/config/jails/pending-recovery")
|
|
|
|
|
assert resp.status_code == 401
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2191,7 +2191,7 @@ class TestRollbackEndpoint:
|
|
|
|
|
message="Jail 'sshd' disabled and fail2ban restarted.",
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service._rollback_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service._rollback_jail",
|
|
|
|
|
AsyncMock(return_value=mock_result),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/sshd/rollback")
|
|
|
|
|
@@ -2228,7 +2228,7 @@ class TestRollbackEndpoint:
|
|
|
|
|
message="fail2ban did not come back online.",
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service._rollback_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service._rollback_jail",
|
|
|
|
|
AsyncMock(return_value=mock_result),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/sshd/rollback")
|
|
|
|
|
@@ -2241,10 +2241,10 @@ class TestRollbackEndpoint:
|
|
|
|
|
|
|
|
|
|
async def test_400_for_invalid_jail_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/bad/rollback returns 400 on JailNameError."""
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
from app.exceptions import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.jail_config_service.rollback_jail",
|
|
|
|
|
"app.routers.jail_config.jail_config_service.rollback_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/bad/rollback")
|
|
|
|
|
|