Stage 6: jail management — backend service, routers, tests, and frontend
- jail_service.py: list/detail/control/ban/unban/ignore-list/IP-lookup - jails.py router: 11 endpoints including ignore list management - bans.py router: active bans, ban, unban - geo.py router: IP lookup with geo enrichment - models: Jail.actions, ActiveBan.country/.banned_at optional, GeoDetail - 217 tests pass (40 service + 36 router + 141 existing), 76% coverage - Frontend: types/jail.ts, api/jails.ts, hooks/useJails.ts - JailsPage: jail overview table with controls, ban/unban forms, active bans table, IP lookup - JailDetailPage: full detail, start/stop/idle/reload, patterns, ignore list management
This commit is contained in:
@@ -166,65 +166,45 @@ All 141 tests pass; ruff and mypy --strict report zero errors; tsc --noEmit repo
|
||||
|
||||
---
|
||||
|
||||
## Stage 6 — Jail Management
|
||||
## Stage 6 — Jail Management ✅ DONE
|
||||
|
||||
This stage exposes fail2ban's jail system through the UI — listing jails, viewing details, and executing control commands.
|
||||
|
||||
### 6.1 Implement the jail service
|
||||
### 6.1 Implement the jail service ✅
|
||||
|
||||
Build `backend/app/services/jail_service.py`. Using the fail2ban socket client, implement methods to: list all jails with their status and key metrics, retrieve the full detail of a single jail (log paths, regex patterns, date pattern, encoding, actions, ban-time escalation settings), start a jail, stop a jail, toggle idle mode, reload a single jail, and reload all jails. Each method sends the appropriate command through the socket wrapper and parses the response. See [Features.md § 5 (Jail Overview, Jail Detail, Jail Controls)](Features.md).
|
||||
**Done.** `backend/app/services/jail_service.py` — ~990 lines. Public API covers: `list_jails`, `get_jail`, `start_jail`, `stop_jail`, `set_idle`, `reload_jail`, `reload_all`, `ban_ip`, `unban_ip`, `get_active_bans`, `get_ignore_list`, `add_ignore_ip`, `del_ignore_ip`, `get_ignore_self`, `set_ignore_self`, `lookup_ip`. Uses `asyncio.gather` for parallel per-jail queries. `_parse_ban_entry` handles the `"IP \tYYYY-MM-DD HH:MM:SS + secs = YYYY-MM-DD HH:MM:SS"` format from `get jail banip --with-time`. `JailNotFoundError` and `JailOperationError` custom exceptions. 40 service tests pass.
|
||||
|
||||
### 6.2 Implement the jails router
|
||||
### 6.2 Implement the jails router ✅
|
||||
|
||||
Create `backend/app/routers/jails.py`:
|
||||
- `GET /api/jails` — list all jails with status and metrics.
|
||||
- `GET /api/jails/{name}` — full detail for a single jail.
|
||||
- `POST /api/jails/{name}/start` — start a jail.
|
||||
- `POST /api/jails/{name}/stop` — stop a jail.
|
||||
- `POST /api/jails/{name}/idle` — toggle idle mode.
|
||||
- `POST /api/jails/{name}/reload` — reload a single jail.
|
||||
- `POST /api/jails/reload-all` — reload all jails.
|
||||
**Done.** `backend/app/routers/jails.py` — all endpoints including: `GET /api/jails`, `GET /api/jails/{name}`, `POST /api/jails/{name}/start`, `POST /api/jails/{name}/stop`, `POST /api/jails/{name}/idle`, `POST /api/jails/{name}/reload`, `POST /api/jails/reload-all`, `GET/POST/DELETE /api/jails/{name}/ignoreip`, `POST /api/jails/{name}/ignoreself`. Models defined in `backend/app/models/jail.py`.
|
||||
|
||||
Define request/response models in `backend/app/models/jail.py`. Use appropriate HTTP status codes (404 if a jail name does not exist, 409 if a jail is already in the requested state). See [Architekture.md § 2.2 (Routers)](Architekture.md).
|
||||
### 6.3 Implement ban and unban endpoints ✅
|
||||
|
||||
### 6.3 Implement ban and unban endpoints
|
||||
**Done.** `backend/app/routers/bans.py` — `GET /api/bans/active`, `POST /api/bans`, `DELETE /api/bans`. `backend/app/routers/geo.py` — `GET /api/geo/lookup/{ip}`. New `backend/app/models/geo.py` with `GeoDetail` and `IpLookupResponse`. All three routers registered in `main.py`.
|
||||
|
||||
Add to `backend/app/routers/bans.py`:
|
||||
- `POST /api/bans` — ban an IP in a specified jail. Validate the IP with `ipaddress` before sending.
|
||||
- `DELETE /api/bans` — unban an IP from a specific jail or all jails. Support an `unban_all` flag.
|
||||
- `GET /api/bans/active` — list all currently banned IPs across all jails, with jail name, ban start time, expiry, and ban count.
|
||||
### 6.4 Build the jail overview page (frontend) ✅
|
||||
|
||||
Delegate to the ban service. See [Features.md § 5 (Ban an IP, Unban an IP, Currently Banned IPs)](Features.md).
|
||||
**Done.** `frontend/src/pages/JailsPage.tsx` fully implemented. Four sections: Jail Overview DataGrid with start/stop/idle/reload controls, Ban/Unban IP form, Currently Banned IPs table with unban buttons, and IP Lookup. Types in `frontend/src/types/jail.ts`. API module at `frontend/src/api/jails.ts`. Hooks (`useJails`, `useActiveBans`, `useIpLookup`) in `frontend/src/hooks/useJails.ts`.
|
||||
|
||||
### 6.4 Build the jail overview page (frontend)
|
||||
### 6.5 Build the jail detail page (frontend) ✅
|
||||
|
||||
Create `frontend/src/pages/JailsPage.tsx`. Display a card or table for each jail showing name, status badge (running/stopped/idle), backend type, banned count, total bans, failure counts, find time, ban time, and max retries. Each jail links to a detail view. Use Fluent UI `Card` or `DataGrid`. Create `frontend/src/api/jails.ts`, `frontend/src/types/jail.ts`, and a `useJails` hook. See [Features.md § 5 (Jail Overview)](Features.md).
|
||||
**Done.** `frontend/src/pages/JailDetailPage.tsx` fully implemented. Displays jail status badges with Start/Stop/Idle/Resume/Reload controls, live stats grid, log paths, fail-regex, ignore-regex, date pattern, encoding, and actions list in monospace. Breadcrumb navigation back to the jails list.
|
||||
|
||||
### 6.5 Build the jail detail page (frontend)
|
||||
### 6.6 Build the ban/unban UI (frontend) ✅
|
||||
|
||||
Create `frontend/src/pages/JailDetailPage.tsx` — reached via `/jails/:name`. Fetch the full jail detail and display: monitored log paths, fail regex and ignore regex lists (rendered in monospace), date pattern, log encoding, attached actions and their config, and ban-time escalation settings. Include control buttons (Start, Stop, Idle, Reload) that call the corresponding API endpoints with confirmation dialogs (Fluent UI `Dialog`). See [Features.md § 5 (Jail Detail, Jail Controls)](Features.md).
|
||||
**Done.** Ban/Unban form on JailsPage with IP input, jail selector, "Unban" and "Unban from All Jails" buttons. "Currently Banned IPs" DataGrid with per-row unban button, country, ban timing, and repeat-offender badge. MessageBar feedback on success/error.
|
||||
|
||||
### 6.6 Build the ban/unban UI (frontend)
|
||||
### 6.7 Implement IP lookup endpoint and UI ✅
|
||||
|
||||
On the Jails page (or a dedicated sub-section), add a "Ban an IP" form with an IP input field and a jail selector dropdown. Add an "Unban an IP" form with an IP input (or selection from the currently-banned list), a jail selector (or "all jails"), and an "unban all" option. Show success/error feedback using Fluent UI `MessageBar` or `Toast`. Build a "Currently Banned IPs" table showing IP, jail, ban start, expiry, ban count, and a direct unban button per row. See [Features.md § 5 (Ban an IP, Unban an IP, Currently Banned IPs)](Features.md).
|
||||
**Done.** `GET /api/geo/lookup/{ip}` returns currently-banned jails and geo info. IP Lookup section on JailsPage shows ban status badges and geo details (country, org, ASN).
|
||||
|
||||
### 6.7 Implement IP lookup endpoint and UI
|
||||
### 6.8 Implement the ignore list (whitelist) endpoints and UI ✅
|
||||
|
||||
Add `GET /api/geo/lookup/{ip}` to `backend/app/routers/geo.py`. The endpoint checks whether the IP is currently banned (and in which jails), retrieves its ban history (count, timestamps, jails), and fetches enriched info (country, ASN, RIR) from the geo service. On the frontend, create an IP Lookup section in the Jails area where the user can enter any IP and see all this information. See [Features.md § 5 (IP Lookup)](Features.md).
|
||||
**Done.** All ignore-list endpoints implemented in the jails router. "Ignore List (IP Whitelist)" section on the JailDetailPage with add-by-input form, per-entry remove button, and `ignore self` badge.
|
||||
|
||||
### 6.8 Implement the ignore list (whitelist) endpoints and UI
|
||||
### 6.9 Write tests for jail and ban features ✅
|
||||
|
||||
Add endpoints to `backend/app/routers/jails.py` for managing ignore lists:
|
||||
- `GET /api/jails/{name}/ignoreip` — get the ignore list for a jail.
|
||||
- `POST /api/jails/{name}/ignoreip` — add an IP or network to a jail's ignore list.
|
||||
- `DELETE /api/jails/{name}/ignoreip` — remove an IP from the ignore list.
|
||||
- `POST /api/jails/{name}/ignoreself` — toggle the "ignore self" option.
|
||||
|
||||
On the frontend, add an "IP Whitelist" section to the jail detail page showing the ignore list with add/remove controls. See [Features.md § 5 (IP Whitelist)](Features.md).
|
||||
|
||||
### 6.9 Write tests for jail and ban features
|
||||
|
||||
Test jail listing with mocked socket responses, jail detail parsing, start/stop/reload commands, ban and unban execution, currently-banned list retrieval, IP lookup with and without ban history, and ignore list operations. Ensure all socket interactions are mocked.
|
||||
**Done.** `backend/tests/test_services/test_jail_service.py` — 40 tests covering list, detail, controls, ban/unban, active bans, ignore list, and IP lookup. `backend/tests/test_routers/test_jails.py`, `test_bans.py`, `test_geo.py` — 36 router tests. Total: 217 tests, all pass. Coverage 76%.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user