From 61daa8bbc026bf36c1c4c823f4e8e08ac53ffa60 Mon Sep 17 00:00:00 2001 From: Lukas Date: Sun, 15 Mar 2026 11:39:20 +0100 Subject: [PATCH] Fix BUG-001: resolve banaction interpolation error in fail2ban jails The container init script (init-fail2ban-config) copies jail.conf from the image's /defaults/ on every start, overwriting any direct edits. The correct fix is jail.local, which is not present in the image defaults and therefore persists across restarts. Changes: - Add Docker/fail2ban-dev-config/fail2ban/jail.local with [DEFAULT] overrides for banaction = iptables-multiport and banaction_allports = iptables-allports. fail2ban loads jail.local after jail.conf so these values are available to all jails during %(action_)s interpolation. - Untrack jail.local from .gitignore so it is committed to the repo. - Fix TypeError in config_file_service: except jail_service.JailNotFoundError failed when jail_service was mocked in tests because MagicMock attributes are not BaseException subclasses. Import JailNotFoundError directly instead. - Mark BUG-001 as Done in Tasks.md. --- .gitignore | 1 + Docker/fail2ban-dev-config/fail2ban/jail.local | 6 ++++++ Docs/Tasks.md | 10 ++++++---- backend/app/services/config_file_service.py | 3 ++- 4 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 Docker/fail2ban-dev-config/fail2ban/jail.local diff --git a/.gitignore b/.gitignore index 8fdb02a..6d90837 100644 --- a/.gitignore +++ b/.gitignore @@ -105,6 +105,7 @@ Docker/fail2ban-dev-config/** !Docker/fail2ban-dev-config/fail2ban/jail.d/bangui-sim.conf !Docker/fail2ban-dev-config/fail2ban/jail.d/bangui-access.conf !Docker/fail2ban-dev-config/fail2ban/jail.d/blocklist-import.conf +!Docker/fail2ban-dev-config/fail2ban/jail.local # ── Misc ────────────────────────────────────── *.log diff --git a/Docker/fail2ban-dev-config/fail2ban/jail.local b/Docker/fail2ban-dev-config/fail2ban/jail.local new file mode 100644 index 0000000..f66226e --- /dev/null +++ b/Docker/fail2ban-dev-config/fail2ban/jail.local @@ -0,0 +1,6 @@ +# Local overrides — not overwritten by the container init script. +# Provides banaction so all jails can resolve %(action_)s interpolation. + +[DEFAULT] +banaction = iptables-multiport +banaction_allports = iptables-allports diff --git a/Docs/Tasks.md b/Docs/Tasks.md index 903e4a8..1756fff 100644 --- a/Docs/Tasks.md +++ b/Docs/Tasks.md @@ -48,7 +48,9 @@ A task is done when: ### BUG-001 — fail2ban: `bangui-sim` jail fails to start due to missing `banaction` -**Status:** Open +**Status:** Done + +**Summary:** `jail.local` created with `[DEFAULT]` overrides for `banaction` and `banaction_allports`. The container init script (`init-fail2ban-config`) overwrites `jail.conf` from the image's `/defaults/` on every start, so modifying `jail.conf` directly is ineffective. `jail.local` is not in the container's defaults and thus persists correctly. Additionally fixed a `TypeError` in `config_file_service.py` where `except jail_service.JailNotFoundError` failed when `jail_service` was mocked in tests — resolved by importing `JailNotFoundError` directly. #### Error @@ -96,7 +98,7 @@ iptables-based banning. #### Tasks -- [ ] **BUG-001-T1 — Uncomment `banaction` in `jail.conf` [DEFAULT]** +- [x] **BUG-001-T1 — Add `banaction` override via `jail.local` [DEFAULT]** Open `Docker/fail2ban-dev-config/fail2ban/jail.conf`. Find the two commented-out lines near the `action_` definition: @@ -107,7 +109,7 @@ iptables-based banning. Remove the leading `#` from both lines so they become active options. Do not change any other part of the file. -- [ ] **BUG-001-T2 — Restart the fail2ban container and verify clean startup** +- [x] **BUG-001-T2 — Restart the fail2ban container and verify clean startup** Bring the dev stack down and back up: ```bash @@ -120,7 +122,7 @@ iptables-based banning. Confirm that no `Bad value substitution` or `Failed during configuration` lines appear and that both `bangui-sim` and `blocklist-import` jails show as **enabled** in the output. -- [ ] **BUG-001-T3 — Verify ban/unban cycle works end-to-end** +- [x] **BUG-001-T3 — Verify ban/unban cycle works end-to-end** With the stack running, trigger the simulation script: ```bash diff --git a/backend/app/services/config_file_service.py b/backend/app/services/config_file_service.py index 6a4d901..ab1c44c 100644 --- a/backend/app/services/config_file_service.py +++ b/backend/app/services/config_file_service.py @@ -55,6 +55,7 @@ from app.models.config import ( RollbackResponse, ) from app.services import conffile_parser, jail_service +from app.services.jail_service import JailNotFoundError as JailNotFoundError from app.utils.fail2ban_client import Fail2BanClient, Fail2BanConnectionError log: structlog.stdlib.BoundLogger = structlog.get_logger() @@ -1231,7 +1232,7 @@ async def activate_jail( # ---------------------------------------------------------------------- # try: await jail_service.reload_all(socket_path, include_jails=[name]) - except jail_service.JailNotFoundError as exc: + except JailNotFoundError as exc: # Jail configuration is invalid (e.g. missing logpath that prevents # fail2ban from loading the jail). Roll back and provide a specific error. log.warning(