|
|
|
|
@@ -727,7 +727,7 @@ class TestGetInactiveJails:
|
|
|
|
|
mock_response = InactiveJailListResponse(jails=[mock_jail], total=1)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.list_inactive_jails",
|
|
|
|
|
"app.routers.config.jail_config_service.list_inactive_jails",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/jails/inactive")
|
|
|
|
|
@@ -742,7 +742,7 @@ class TestGetInactiveJails:
|
|
|
|
|
from app.models.config import InactiveJailListResponse
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.list_inactive_jails",
|
|
|
|
|
"app.routers.config.jail_config_service.list_inactive_jails",
|
|
|
|
|
AsyncMock(return_value=InactiveJailListResponse(jails=[], total=0)),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/jails/inactive")
|
|
|
|
|
@@ -778,7 +778,7 @@ class TestActivateJail:
|
|
|
|
|
message="Jail 'apache-auth' activated successfully.",
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.activate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -798,7 +798,7 @@ class TestActivateJail:
|
|
|
|
|
name="apache-auth", active=True, message="Activated."
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.activate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
) as mock_activate:
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -814,10 +814,10 @@ class TestActivateJail:
|
|
|
|
|
|
|
|
|
|
async def test_404_for_unknown_jail(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/missing/activate returns 404."""
|
|
|
|
|
from app.services.config_file_service import JailNotFoundInConfigError
|
|
|
|
|
from app.services.jail_config_service import JailNotFoundInConfigError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.activate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -828,10 +828,10 @@ class TestActivateJail:
|
|
|
|
|
|
|
|
|
|
async def test_409_when_already_active(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/sshd/activate returns 409 if already active."""
|
|
|
|
|
from app.services.config_file_service import JailAlreadyActiveError
|
|
|
|
|
from app.services.jail_config_service import JailAlreadyActiveError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.activate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailAlreadyActiveError("sshd")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -842,10 +842,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.config_file_service import JailNameError
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.activate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError("bad name")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -874,7 +874,7 @@ class TestActivateJail:
|
|
|
|
|
message="Jail 'airsonic-auth' cannot be activated: log file '/var/log/airsonic/airsonic.log' not found",
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.activate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.activate_jail",
|
|
|
|
|
AsyncMock(return_value=blocked_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -907,7 +907,7 @@ class TestDeactivateJail:
|
|
|
|
|
message="Jail 'sshd' deactivated successfully.",
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.deactivate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.deactivate_jail",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/sshd/deactivate")
|
|
|
|
|
@@ -919,10 +919,10 @@ class TestDeactivateJail:
|
|
|
|
|
|
|
|
|
|
async def test_404_for_unknown_jail(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/missing/deactivate returns 404."""
|
|
|
|
|
from app.services.config_file_service import JailNotFoundInConfigError
|
|
|
|
|
from app.services.jail_config_service import JailNotFoundInConfigError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.deactivate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.deactivate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -933,10 +933,10 @@ class TestDeactivateJail:
|
|
|
|
|
|
|
|
|
|
async def test_409_when_already_inactive(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/apache-auth/deactivate returns 409 if already inactive."""
|
|
|
|
|
from app.services.config_file_service import JailAlreadyInactiveError
|
|
|
|
|
from app.services.jail_config_service import JailAlreadyInactiveError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.deactivate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.deactivate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailAlreadyInactiveError("apache-auth")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -947,10 +947,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.config_file_service import JailNameError
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.deactivate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.deactivate_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -978,7 +978,7 @@ class TestDeactivateJail:
|
|
|
|
|
)
|
|
|
|
|
with (
|
|
|
|
|
patch(
|
|
|
|
|
"app.routers.config.config_file_service.deactivate_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.deactivate_jail",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
),
|
|
|
|
|
patch(
|
|
|
|
|
@@ -1029,7 +1029,7 @@ class TestListFilters:
|
|
|
|
|
total=1,
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.list_filters",
|
|
|
|
|
"app.routers.config.filter_config_service.list_filters",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/filters")
|
|
|
|
|
@@ -1045,7 +1045,7 @@ class TestListFilters:
|
|
|
|
|
from app.models.config import FilterListResponse
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.list_filters",
|
|
|
|
|
"app.routers.config.filter_config_service.list_filters",
|
|
|
|
|
AsyncMock(return_value=FilterListResponse(filters=[], total=0)),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/filters")
|
|
|
|
|
@@ -1068,7 +1068,7 @@ class TestListFilters:
|
|
|
|
|
total=2,
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.list_filters",
|
|
|
|
|
"app.routers.config.filter_config_service.list_filters",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/filters")
|
|
|
|
|
@@ -1097,7 +1097,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.config_file_service.get_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.get_filter",
|
|
|
|
|
AsyncMock(return_value=_make_filter_config("sshd")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/filters/sshd")
|
|
|
|
|
@@ -1110,10 +1110,10 @@ class TestGetFilter:
|
|
|
|
|
|
|
|
|
|
async def test_404_for_unknown_filter(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""GET /api/config/filters/missing returns 404."""
|
|
|
|
|
from app.services.config_file_service import FilterNotFoundError
|
|
|
|
|
from app.services.filter_config_service import FilterNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.get_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.get_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/filters/missing")
|
|
|
|
|
@@ -1140,7 +1140,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.config_file_service.update_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.update_filter",
|
|
|
|
|
AsyncMock(return_value=_make_filter_config("sshd")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1153,10 +1153,10 @@ class TestUpdateFilter:
|
|
|
|
|
|
|
|
|
|
async def test_404_for_unknown_filter(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""PUT /api/config/filters/missing returns 404."""
|
|
|
|
|
from app.services.config_file_service import FilterNotFoundError
|
|
|
|
|
from app.services.filter_config_service import FilterNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.update_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.update_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1168,10 +1168,10 @@ class TestUpdateFilter:
|
|
|
|
|
|
|
|
|
|
async def test_422_for_invalid_regex(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""PUT /api/config/filters/sshd returns 422 for bad regex."""
|
|
|
|
|
from app.services.config_file_service import FilterInvalidRegexError
|
|
|
|
|
from app.services.filter_config_service import FilterInvalidRegexError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.update_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.update_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterInvalidRegexError("[bad", "unterminated")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1183,10 +1183,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.config_file_service import FilterNameError
|
|
|
|
|
from app.services.filter_config_service import FilterNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.update_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.update_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1199,7 +1199,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.config_file_service.update_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.update_filter",
|
|
|
|
|
AsyncMock(return_value=_make_filter_config("sshd")),
|
|
|
|
|
) as mock_update:
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1230,7 +1230,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.config_file_service.create_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.create_filter",
|
|
|
|
|
AsyncMock(return_value=_make_filter_config("my-custom")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1243,10 +1243,10 @@ class TestCreateFilter:
|
|
|
|
|
|
|
|
|
|
async def test_409_when_already_exists(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/filters returns 409 if filter exists."""
|
|
|
|
|
from app.services.config_file_service import FilterAlreadyExistsError
|
|
|
|
|
from app.services.filter_config_service import FilterAlreadyExistsError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.create_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.create_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterAlreadyExistsError("sshd")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1258,10 +1258,10 @@ class TestCreateFilter:
|
|
|
|
|
|
|
|
|
|
async def test_422_for_invalid_regex(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/filters returns 422 for bad regex."""
|
|
|
|
|
from app.services.config_file_service import FilterInvalidRegexError
|
|
|
|
|
from app.services.filter_config_service import FilterInvalidRegexError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.create_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.create_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterInvalidRegexError("[bad", "unterminated")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1273,10 +1273,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.config_file_service import FilterNameError
|
|
|
|
|
from app.services.filter_config_service import FilterNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.create_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.create_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1306,7 +1306,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.config_file_service.delete_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.delete_filter",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/filters/my-custom")
|
|
|
|
|
@@ -1315,10 +1315,10 @@ class TestDeleteFilter:
|
|
|
|
|
|
|
|
|
|
async def test_404_for_unknown_filter(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""DELETE /api/config/filters/missing returns 404."""
|
|
|
|
|
from app.services.config_file_service import FilterNotFoundError
|
|
|
|
|
from app.services.filter_config_service import FilterNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.delete_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.delete_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/filters/missing")
|
|
|
|
|
@@ -1327,10 +1327,10 @@ class TestDeleteFilter:
|
|
|
|
|
|
|
|
|
|
async def test_409_for_readonly_filter(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""DELETE /api/config/filters/sshd returns 409 for shipped conf-only filter."""
|
|
|
|
|
from app.services.config_file_service import FilterReadonlyError
|
|
|
|
|
from app.services.filter_config_service import FilterReadonlyError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.delete_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.delete_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterReadonlyError("sshd")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/filters/sshd")
|
|
|
|
|
@@ -1339,10 +1339,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.config_file_service import FilterNameError
|
|
|
|
|
from app.services.filter_config_service import FilterNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.delete_filter",
|
|
|
|
|
"app.routers.config.filter_config_service.delete_filter",
|
|
|
|
|
AsyncMock(side_effect=FilterNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/filters/bad")
|
|
|
|
|
@@ -1369,7 +1369,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.config_file_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1381,10 +1381,10 @@ class TestAssignFilterToJail:
|
|
|
|
|
|
|
|
|
|
async def test_404_for_unknown_jail(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/missing/filter returns 404."""
|
|
|
|
|
from app.services.config_file_service import JailNotFoundInConfigError
|
|
|
|
|
from app.services.jail_config_service import JailNotFoundInConfigError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1396,10 +1396,10 @@ class TestAssignFilterToJail:
|
|
|
|
|
|
|
|
|
|
async def test_404_for_unknown_filter(self, config_client: AsyncClient) -> None:
|
|
|
|
|
"""POST /api/config/jails/sshd/filter returns 404 when filter not found."""
|
|
|
|
|
from app.services.config_file_service import FilterNotFoundError
|
|
|
|
|
from app.services.filter_config_service import FilterNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(side_effect=FilterNotFoundError("missing-filter")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1411,10 +1411,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.config_file_service import JailNameError
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1426,10 +1426,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.config_file_service import FilterNameError
|
|
|
|
|
from app.services.filter_config_service import FilterNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(side_effect=FilterNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1442,7 +1442,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.config_file_service.assign_filter_to_jail",
|
|
|
|
|
"app.routers.config.filter_config_service.assign_filter_to_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
) as mock_assign:
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1480,7 +1480,7 @@ class TestListActionsRouter:
|
|
|
|
|
mock_response = ActionListResponse(actions=[mock_action], total=1)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.list_actions",
|
|
|
|
|
"app.routers.config.action_config_service.list_actions",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/actions")
|
|
|
|
|
@@ -1498,7 +1498,7 @@ class TestListActionsRouter:
|
|
|
|
|
mock_response = ActionListResponse(actions=[inactive, active], total=2)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.list_actions",
|
|
|
|
|
"app.routers.config.action_config_service.list_actions",
|
|
|
|
|
AsyncMock(return_value=mock_response),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/actions")
|
|
|
|
|
@@ -1526,7 +1526,7 @@ class TestGetActionRouter:
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.get_action",
|
|
|
|
|
"app.routers.config.action_config_service.get_action",
|
|
|
|
|
AsyncMock(return_value=mock_action),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/actions/iptables")
|
|
|
|
|
@@ -1535,10 +1535,10 @@ class TestGetActionRouter:
|
|
|
|
|
assert resp.json()["name"] == "iptables"
|
|
|
|
|
|
|
|
|
|
async def test_404_when_not_found(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionNotFoundError
|
|
|
|
|
from app.services.action_config_service import ActionNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.get_action",
|
|
|
|
|
"app.routers.config.action_config_service.get_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.get("/api/config/actions/missing")
|
|
|
|
|
@@ -1565,7 +1565,7 @@ class TestUpdateActionRouter:
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.update_action",
|
|
|
|
|
"app.routers.config.action_config_service.update_action",
|
|
|
|
|
AsyncMock(return_value=updated),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1577,10 +1577,10 @@ class TestUpdateActionRouter:
|
|
|
|
|
assert resp.json()["actionban"] == "echo ban"
|
|
|
|
|
|
|
|
|
|
async def test_404_when_not_found(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionNotFoundError
|
|
|
|
|
from app.services.action_config_service import ActionNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.update_action",
|
|
|
|
|
"app.routers.config.action_config_service.update_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1590,10 +1590,10 @@ class TestUpdateActionRouter:
|
|
|
|
|
assert resp.status_code == 404
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionNameError
|
|
|
|
|
from app.services.action_config_service import ActionNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.update_action",
|
|
|
|
|
"app.routers.config.action_config_service.update_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.put(
|
|
|
|
|
@@ -1622,7 +1622,7 @@ class TestCreateActionRouter:
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.create_action",
|
|
|
|
|
"app.routers.config.action_config_service.create_action",
|
|
|
|
|
AsyncMock(return_value=created),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1634,10 +1634,10 @@ class TestCreateActionRouter:
|
|
|
|
|
assert resp.json()["name"] == "custom"
|
|
|
|
|
|
|
|
|
|
async def test_409_when_already_exists(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionAlreadyExistsError
|
|
|
|
|
from app.services.action_config_service import ActionAlreadyExistsError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.create_action",
|
|
|
|
|
"app.routers.config.action_config_service.create_action",
|
|
|
|
|
AsyncMock(side_effect=ActionAlreadyExistsError("iptables")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1648,10 +1648,10 @@ class TestCreateActionRouter:
|
|
|
|
|
assert resp.status_code == 409
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionNameError
|
|
|
|
|
from app.services.action_config_service import ActionNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.create_action",
|
|
|
|
|
"app.routers.config.action_config_service.create_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1673,7 +1673,7 @@ class TestCreateActionRouter:
|
|
|
|
|
class TestDeleteActionRouter:
|
|
|
|
|
async def test_204_on_delete(self, config_client: AsyncClient) -> None:
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.delete_action",
|
|
|
|
|
"app.routers.config.action_config_service.delete_action",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/actions/custom")
|
|
|
|
|
@@ -1681,10 +1681,10 @@ class TestDeleteActionRouter:
|
|
|
|
|
assert resp.status_code == 204
|
|
|
|
|
|
|
|
|
|
async def test_404_when_not_found(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionNotFoundError
|
|
|
|
|
from app.services.action_config_service import ActionNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.delete_action",
|
|
|
|
|
"app.routers.config.action_config_service.delete_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/actions/missing")
|
|
|
|
|
@@ -1692,10 +1692,10 @@ class TestDeleteActionRouter:
|
|
|
|
|
assert resp.status_code == 404
|
|
|
|
|
|
|
|
|
|
async def test_409_when_readonly(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionReadonlyError
|
|
|
|
|
from app.services.action_config_service import ActionReadonlyError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.delete_action",
|
|
|
|
|
"app.routers.config.action_config_service.delete_action",
|
|
|
|
|
AsyncMock(side_effect=ActionReadonlyError("iptables")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/actions/iptables")
|
|
|
|
|
@@ -1703,10 +1703,10 @@ class TestDeleteActionRouter:
|
|
|
|
|
assert resp.status_code == 409
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionNameError
|
|
|
|
|
from app.services.action_config_service import ActionNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.delete_action",
|
|
|
|
|
"app.routers.config.action_config_service.delete_action",
|
|
|
|
|
AsyncMock(side_effect=ActionNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete("/api/config/actions/badname")
|
|
|
|
|
@@ -1725,7 +1725,7 @@ class TestDeleteActionRouter:
|
|
|
|
|
class TestAssignActionToJailRouter:
|
|
|
|
|
async def test_204_on_success(self, config_client: AsyncClient) -> None:
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1736,10 +1736,10 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
assert resp.status_code == 204
|
|
|
|
|
|
|
|
|
|
async def test_404_when_jail_not_found(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import JailNotFoundInConfigError
|
|
|
|
|
from app.services.jail_config_service import JailNotFoundInConfigError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1750,10 +1750,10 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
assert resp.status_code == 404
|
|
|
|
|
|
|
|
|
|
async def test_404_when_action_not_found(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionNotFoundError
|
|
|
|
|
from app.services.action_config_service import ActionNotFoundError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(side_effect=ActionNotFoundError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1764,10 +1764,10 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
assert resp.status_code == 404
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_jail_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import JailNameError
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1778,10 +1778,10 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
assert resp.status_code == 400
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_action_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionNameError
|
|
|
|
|
from app.services.action_config_service import ActionNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(side_effect=ActionNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1793,7 +1793,7 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
|
|
|
|
|
async def test_reload_param_passed(self, config_client: AsyncClient) -> None:
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.assign_action_to_jail",
|
|
|
|
|
"app.routers.config.action_config_service.assign_action_to_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
) as mock_assign:
|
|
|
|
|
resp = await config_client.post(
|
|
|
|
|
@@ -1816,7 +1816,7 @@ class TestAssignActionToJailRouter:
|
|
|
|
|
class TestRemoveActionFromJailRouter:
|
|
|
|
|
async def test_204_on_success(self, config_client: AsyncClient) -> None:
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.remove_action_from_jail",
|
|
|
|
|
"app.routers.config.action_config_service.remove_action_from_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete(
|
|
|
|
|
@@ -1826,10 +1826,10 @@ class TestRemoveActionFromJailRouter:
|
|
|
|
|
assert resp.status_code == 204
|
|
|
|
|
|
|
|
|
|
async def test_404_when_jail_not_found(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import JailNotFoundInConfigError
|
|
|
|
|
from app.services.jail_config_service import JailNotFoundInConfigError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.remove_action_from_jail",
|
|
|
|
|
"app.routers.config.action_config_service.remove_action_from_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNotFoundInConfigError("missing")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete(
|
|
|
|
|
@@ -1839,10 +1839,10 @@ class TestRemoveActionFromJailRouter:
|
|
|
|
|
assert resp.status_code == 404
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_jail_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import JailNameError
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.remove_action_from_jail",
|
|
|
|
|
"app.routers.config.action_config_service.remove_action_from_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete(
|
|
|
|
|
@@ -1852,10 +1852,10 @@ class TestRemoveActionFromJailRouter:
|
|
|
|
|
assert resp.status_code == 400
|
|
|
|
|
|
|
|
|
|
async def test_400_for_bad_action_name(self, config_client: AsyncClient) -> None:
|
|
|
|
|
from app.services.config_file_service import ActionNameError
|
|
|
|
|
from app.services.action_config_service import ActionNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.remove_action_from_jail",
|
|
|
|
|
"app.routers.config.action_config_service.remove_action_from_jail",
|
|
|
|
|
AsyncMock(side_effect=ActionNameError()),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.delete(
|
|
|
|
|
@@ -1866,7 +1866,7 @@ class TestRemoveActionFromJailRouter:
|
|
|
|
|
|
|
|
|
|
async def test_reload_param_passed(self, config_client: AsyncClient) -> None:
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.remove_action_from_jail",
|
|
|
|
|
"app.routers.config.action_config_service.remove_action_from_jail",
|
|
|
|
|
AsyncMock(return_value=None),
|
|
|
|
|
) as mock_rm:
|
|
|
|
|
resp = await config_client.delete(
|
|
|
|
|
@@ -2065,7 +2065,7 @@ class TestValidateJailEndpoint:
|
|
|
|
|
jail_name="sshd", valid=True, issues=[]
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.validate_jail_config",
|
|
|
|
|
"app.routers.config.jail_config_service.validate_jail_config",
|
|
|
|
|
AsyncMock(return_value=mock_result),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/sshd/validate")
|
|
|
|
|
@@ -2085,7 +2085,7 @@ class TestValidateJailEndpoint:
|
|
|
|
|
jail_name="sshd", valid=False, issues=[issue]
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.validate_jail_config",
|
|
|
|
|
"app.routers.config.jail_config_service.validate_jail_config",
|
|
|
|
|
AsyncMock(return_value=mock_result),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/sshd/validate")
|
|
|
|
|
@@ -2098,10 +2098,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.config_file_service import JailNameError
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.validate_jail_config",
|
|
|
|
|
"app.routers.config.jail_config_service.validate_jail_config",
|
|
|
|
|
AsyncMock(side_effect=JailNameError("bad name")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/bad-name/validate")
|
|
|
|
|
@@ -2193,7 +2193,7 @@ class TestRollbackEndpoint:
|
|
|
|
|
message="Jail 'sshd' disabled and fail2ban restarted.",
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.rollback_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.rollback_jail",
|
|
|
|
|
AsyncMock(return_value=mock_result),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/sshd/rollback")
|
|
|
|
|
@@ -2230,7 +2230,7 @@ class TestRollbackEndpoint:
|
|
|
|
|
message="fail2ban did not come back online.",
|
|
|
|
|
)
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.rollback_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.rollback_jail",
|
|
|
|
|
AsyncMock(return_value=mock_result),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/sshd/rollback")
|
|
|
|
|
@@ -2243,10 +2243,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.config_file_service import JailNameError
|
|
|
|
|
from app.services.jail_config_service import JailNameError
|
|
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
|
"app.routers.config.config_file_service.rollback_jail",
|
|
|
|
|
"app.routers.config.jail_config_service.rollback_jail",
|
|
|
|
|
AsyncMock(side_effect=JailNameError("bad")),
|
|
|
|
|
):
|
|
|
|
|
resp = await config_client.post("/api/config/jails/bad/rollback")
|
|
|
|
|
|