TASK-010: Replace .split() with shlex.split() for fail2ban_start_command

- Add @field_validator for fail2ban_start_command to validate with shlex.split()
  at startup, catching misconfigured commands with mismatched quotes
- Replace .split() with shlex.split() in jail_config.py line 450
- Replace .split() with shlex.split() in config_misc.py line 154
- Update Backend-Development.md with configuration documentation explaining
  quoted path handling and common pitfalls
- Add comprehensive test suite (8 tests) covering valid commands, quoted paths,
  and mismatched quote errors

This fix ensures commands like '/opt/my tools/fail2ban-client' start are
correctly parsed as two tokens instead of three, preventing execution failures
when the path contains spaces.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-26 13:04:14 +02:00
parent 4ab767e3d4
commit 8698b89f6a
6 changed files with 160 additions and 38 deletions

View File

@@ -1,5 +1,6 @@
from __future__ import annotations
import shlex
from typing import Annotated
import structlog
@@ -149,7 +150,7 @@ async def restart_fail2ban(
``POST /api/config/jails/{name}/rollback``
if a specific jail is suspect.
"""
start_cmd_parts: list[str] = start_cmd.split()
start_cmd_parts: list[str] = shlex.split(start_cmd)
restarted = await jail_service.restart_daemon(
socket_path,

View File

@@ -1,5 +1,6 @@
from __future__ import annotations
import shlex
from typing import Annotated
from fastapi import APIRouter, Path, Query, Request, status
@@ -445,7 +446,7 @@ async def rollback_jail(
HTTPException: 400 if *name* contains invalid characters.
HTTPException: 500 if writing the .local override file fails.
"""
start_cmd_parts: list[str] = start_cmd.split()
start_cmd_parts: list[str] = shlex.split(start_cmd)
result = await jail_config_service.rollback_jail(config_dir, socket_path, name, start_cmd_parts)