backup
This commit is contained in:
@@ -4,10 +4,10 @@ Covers jail config files (``jail.d/``), filter definitions (``filter.d/``),
|
||||
and action definitions (``action.d/``).
|
||||
"""
|
||||
|
||||
from pydantic import Field
|
||||
from pydantic import Field, field_validator
|
||||
|
||||
from app.models.response import BanGuiBaseModel
|
||||
|
||||
from app.utils.constants import FAIL2BAN_RESERVED_JAIL_NAMES
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Jail config file models (Task 4a)
|
||||
@@ -82,3 +82,15 @@ class ConfFileCreateRequest(BanGuiBaseModel):
|
||||
"alphanumeric characters, hyphens, underscores, and dots.",
|
||||
)
|
||||
content: str = Field(..., description="Initial raw file content (must not exceed 512 KB).")
|
||||
|
||||
@field_validator("name", mode="after")
|
||||
@classmethod
|
||||
def _reject_reserved_jail_name(cls, v: str) -> str:
|
||||
"""Reject fail2ban reserved jail names."""
|
||||
if v in FAIL2BAN_RESERVED_JAIL_NAMES:
|
||||
|
||||
valid_names = ", ".join(sorted(FAIL2BAN_RESERVED_JAIL_NAMES))
|
||||
raise ValueError(
|
||||
f"Jail name {v!r} is reserved by fail2ban ({valid_names})."
|
||||
)
|
||||
return v
|
||||
|
||||
@@ -156,3 +156,26 @@ RATE_LIMIT_JAIL_ACTIVATE_REQUESTS: Final[int] = 100
|
||||
|
||||
RATE_LIMIT_JAIL_DEACTIVATE_REQUESTS: Final[int] = 100
|
||||
"""Max jail deactivation requests per IP per minute."""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Jail configuration
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
FAIL2BAN_RESERVED_JAIL_NAMES: Final[frozenset[str]] = frozenset(
|
||||
{
|
||||
"all",
|
||||
"status",
|
||||
"purge",
|
||||
"start",
|
||||
"stop",
|
||||
"reload",
|
||||
"restart",
|
||||
"ban",
|
||||
"unban",
|
||||
"add",
|
||||
"del",
|
||||
"set",
|
||||
"get",
|
||||
}
|
||||
)
|
||||
"""fail2ban reserved jail names. Users cannot create jails with these names."""
|
||||
|
||||
@@ -347,3 +347,38 @@ def test_ban_country_empty_string_coerced_to_none() -> None:
|
||||
country="",
|
||||
)
|
||||
assert ban.country is None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ConfFileCreateRequest reserved jail name validation
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_conffile_create_request_rejects_reserved_jail_name() -> None:
|
||||
"""ConfFileCreateRequest rejects fail2ban reserved jail names."""
|
||||
from app.models.file_config import ConfFileCreateRequest
|
||||
|
||||
for reserved in ["all", "status", "purge", "start", "stop", "reload", "restart"]:
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
ConfFileCreateRequest(name=reserved, content="[my jail]")
|
||||
assert "reserved" in str(exc_info.value).lower()
|
||||
|
||||
|
||||
def test_conffile_create_request_accepts_valid_jail_name() -> None:
|
||||
"""ConfFileCreateRequest accepts valid non-reserved jail names."""
|
||||
from app.models.file_config import ConfFileCreateRequest
|
||||
|
||||
req = ConfFileCreateRequest(name="sshd", content="[my jail]")
|
||||
assert req.name == "sshd"
|
||||
|
||||
req = ConfFileCreateRequest(name="nginx-http-auth", content="[my jail]")
|
||||
assert req.name == "nginx-http-auth"
|
||||
|
||||
|
||||
def test_conffile_create_request_rejects_ban_and_unban() -> None:
|
||||
"""ConfFileCreateRequest rejects 'ban' and 'unban' as jail names."""
|
||||
from app.models.file_config import ConfFileCreateRequest
|
||||
|
||||
for name in ["ban", "unban", "add", "del", "set", "get"]:
|
||||
with pytest.raises(ValidationError):
|
||||
ConfFileCreateRequest(name=name, content="[my jail]")
|
||||
|
||||
Reference in New Issue
Block a user