TASK-018: Make config file writes atomic using write-to-temp + rename

- Replace Path.write_text() with tempfile.NamedTemporaryFile + os.replace()
  in _write_conf_file() and _create_conf_file()
- Ensures atomic operations on same filesystem (temp file in target.parent)
- Prevents config corruption if process is killed mid-write
- Follows existing pattern in jail_config_service.py
- Add proper cleanup of temp files on error with contextlib.suppress()
- Document atomic file write conventions in Backend-Development.md

This prevents fail2ban config files (especially jail.d/*.conf) from being
left in a truncated or corrupt state, which could disable active protection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-26 14:11:18 +02:00
parent b6e8e3f5ff
commit 4ceb11a4e3
3 changed files with 110 additions and 44 deletions

View File

@@ -1,33 +1,3 @@
## TASK-017 — `ip LIKE ?` without escaping `%` and `_` wildcards
**Severity:** Medium
### Where found
`backend/app/repositories/fail2ban_db_repo.py` and `backend/app/repositories/history_archive_repo.py` — SQL queries using `ip LIKE ?` with `f"{ip_filter}%"` interpolation.
### Why this is needed
SQLite's `LIKE` operator treats `%` (any sequence of characters) and `_` (any single character) as wildcards. If an IP filter value contains these characters — unusual for well-formed IPs, but possible via crafted input — the query matches unintended rows. For example, `ip_filter = "10.0.0_"` would match `10.0.0.1` through `10.0.0.9`.
### Goal
Escape LIKE metacharacters in all `LIKE` query parameters.
### What to do
1. Escape `%``\%` and `_``\_` in the filter string before use.
2. Add `ESCAPE '\'` to the SQL: `ip LIKE ? ESCAPE '\'`.
3. Extract this into a helper: `def escape_like(s: str) -> str: return s.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")`.
### Possible traps and issues
- The backslash escape character itself must also be escaped first to avoid double-escaping. Process in the order: `\``\\`, then `%``\%`, then `_``\_`.
- Test with IPs that contain dots — dots are not LIKE wildcards in SQLite, so they do not need escaping.
### Docs changes needed
- `Backend-Development.md` — database query conventions (LIKE escaping).
### Doc references
- [Backend-Development.md](Backend-Development.md) — database access patterns
---
## TASK-018 — `_write_conf_file` and `_create_conf_file` not atomic
**Severity:** Medium