Stage 7: configuration view — backend service, routers, tests, and frontend
- config_service.py: read/write jail config via asyncio.gather, global settings, in-process regex validation, log preview via _read_tail_lines - server_service.py: read/write server settings, flush logs - config router: 9 endpoints for jail/global config, regex-test, logpath management, log preview - server router: GET/PUT settings, POST flush-logs - models/config.py expanded with JailConfig, GlobalConfigUpdate, LogPreview* models - 285 tests pass (68 new), ruff clean, mypy clean (44 files) - Frontend: types/config.ts, api/config.ts, hooks/useConfig.ts, ConfigPage.tsx full implementation (Jails accordion editor, Global config, Server settings, Regex Tester with preview) - Fixed pre-existing frontend lint: JSX.Element → React.JSX.Element (10 files), void/promise patterns in useServerStatus + useJails, no-misused-spread in client.ts, eslint.config.ts self-excluded
This commit is contained in:
@@ -208,58 +208,73 @@ This stage exposes fail2ban's jail system through the UI — listing jails, view
|
||||
|
||||
---
|
||||
|
||||
## Stage 7 — Configuration View
|
||||
## Stage 7 — Configuration View ✅ DONE
|
||||
|
||||
This stage lets users inspect and edit fail2ban configuration directly from the web interface.
|
||||
|
||||
### 7.1 Implement the config service
|
||||
### 7.1 Implement the config service ✅ DONE
|
||||
|
||||
Build `backend/app/services/config_service.py`. It reads the active fail2ban configuration by querying the daemon for jail settings, filter regex patterns, and global parameters. It also writes configuration changes by sending the appropriate set commands through the socket (or by editing config files and triggering a reload, depending on what fail2ban supports for each setting). The service must validate regex patterns before applying them — attempting to compile each pattern and returning a clear error if it is invalid. See [Features.md § 6 (View Configuration, Edit Configuration)](Features.md).
|
||||
Built `backend/app/services/config_service.py` (~613 lines). Reads active jail config via parallel `asyncio.gather` across 10 socket commands per jail. Writes via `set <jail> <key> <val>` commands. `_replace_regex_list` diffs old/new patterns using `contextlib.suppress(ValueError)`. In-process regex validation via the `re` module with `ConfigValidationError` on failure. `test_regex` is synchronous/pure-Python (no socket). `preview_log` reads file tail via `_read_tail_lines` (executor) and pattern-tests each line. Custom exceptions: `JailNotFoundError`, `ConfigValidationError`, `ConfigOperationError`.
|
||||
|
||||
### 7.2 Implement the config router
|
||||
### 7.2 Implement the config router ✅ DONE
|
||||
|
||||
Create `backend/app/routers/config.py`:
|
||||
- `GET /api/config/jails` — list all jails with their current configuration.
|
||||
- `GET /api/config/jails/{name}` — full configuration for a single jail (filter, regex, dates, actions, escalation).
|
||||
- `PUT /api/config/jails/{name}` — update a jail's configuration (ban time, max retries, enabled, regex patterns, date pattern, DNS mode, escalation settings).
|
||||
- `GET /api/config/global` — global fail2ban settings.
|
||||
- `PUT /api/config/global` — update global settings.
|
||||
- `POST /api/config/reload` — reload fail2ban to apply changes.
|
||||
Created `backend/app/routers/config.py` (~310 lines) with 9 endpoints:
|
||||
- `GET /api/config/jails` → `JailConfigListResponse`
|
||||
- `GET /api/config/jails/{name}` → `JailConfigResponse` (404 on unknown jail)
|
||||
- `PUT /api/config/jails/{name}` → 204 (422 on bad regex, 400 on socket error)
|
||||
- `GET /api/config/global` → `GlobalConfigResponse`
|
||||
- `PUT /api/config/global` → 204
|
||||
- `POST /api/config/reload` → 204
|
||||
- `POST /api/config/regex-test` → `RegexTestResponse`
|
||||
- `POST /api/config/jails/{name}/logpath` → 204
|
||||
- `POST /api/config/preview-log` → `LogPreviewResponse`
|
||||
|
||||
Define models in `backend/app/models/config.py`. Return validation errors before saving. See [Architekture.md § 2.2 (Routers)](Architekture.md).
|
||||
Models expanded in `backend/app/models/config.py`: `JailConfig`, `JailConfigResponse`, `JailConfigListResponse`, `JailConfigUpdate`, `GlobalConfigResponse`, `GlobalConfigUpdate`, `AddLogPathRequest`, `LogPreviewRequest`, `LogPreviewLine`, `LogPreviewResponse`.
|
||||
|
||||
### 7.3 Implement log observation endpoints
|
||||
### 7.3 Implement log observation endpoints ✅ DONE
|
||||
|
||||
Add endpoints for registering new log files that fail2ban should monitor. The user needs to specify a log file path, one or more failure-detection regex patterns, a jail name, and basic jail settings. Include a preview endpoint that reads the specified log file and tests the provided regex against its contents, returning matching lines so the user can verify the pattern before saving. See [Features.md § 6 (Add Log Observation)](Features.md).
|
||||
`POST /api/config/jails/{name}/logpath` — adds a new log path via `set <jail> addlogpath <path> tail|head`. `POST /api/config/preview-log` — reads the last N lines from a server-side log file and tests each line against a provided fail-regex, returning `LogPreviewResponse` with per-line match status and aggregate counts.
|
||||
|
||||
### 7.4 Implement the regex tester endpoint
|
||||
### 7.4 Implement the regex tester endpoint ✅ DONE
|
||||
|
||||
Add `POST /api/config/regex-test` to the config router. It accepts a sample log line and a fail regex pattern, attempts to match them, and returns whether the pattern matched along with any captured groups highlighted by position. This is a stateless utility endpoint. See [Features.md § 6 (Regex Tester)](Features.md).
|
||||
`POST /api/config/regex-test` implemented as a stateless, synchronous endpoint (no socket). Compiles the provided pattern with `re.compile`, applies it to the sample log line, returns `RegexTestResponse` with `matched` bool, `groups` list, and `error` string on invalid regex.
|
||||
|
||||
### 7.5 Implement server settings endpoints
|
||||
### 7.5 Implement server settings endpoints ✅ DONE
|
||||
|
||||
Create `backend/app/routers/server.py`:
|
||||
- `GET /api/server/settings` — current log level, log target, syslog socket, DB path, purge age, max matches.
|
||||
- `PUT /api/server/settings` — update server-level settings.
|
||||
- `POST /api/server/flush-logs` — flush and re-open log files.
|
||||
Created `backend/app/services/server_service.py` (~165 lines) and `backend/app/routers/server.py` (~115 lines):
|
||||
- `GET /api/server/settings` → `ServerSettingsResponse` (parallel gather of 6 settings)
|
||||
- `PUT /api/server/settings` → 204
|
||||
- `POST /api/server/flush-logs` → `{"message": str}`
|
||||
|
||||
Delegate to `backend/app/services/server_service.py`. See [Features.md § 6 (Server Settings)](Features.md).
|
||||
Custom exception: `ServerOperationError`.
|
||||
|
||||
### 7.6 Build the configuration page (frontend)
|
||||
### 7.6 Build the configuration page (frontend) ✅ DONE
|
||||
|
||||
Create `frontend/src/pages/ConfigPage.tsx`. The page should show all jails with their current settings in a readable format. Each jail section expands to show filter regex, ignore regex, date pattern, actions, and escalation settings. Provide inline editing: clicking a value turns it into an editable field. Add/remove buttons for regex patterns. A "Save" button persists changes and optionally triggers a reload. Show validation errors inline. Use Fluent UI `Accordion`, `Input`, `Textarea`, `Switch`, and `Button`. See [Features.md § 6](Features.md) and [Web-Design.md](Web-Design.md).
|
||||
Created `frontend/src/pages/ConfigPage.tsx` with four tabs:
|
||||
- **Jails** — Accordion of all jails, each expandable with editable ban_time/find_time/max_retry, `RegexList` component for fail_regex/ignore_regex (add/remove inline), read-only log_paths/backend/actions, Save button per jail, Reload fail2ban button.
|
||||
- **Global** — log_level dropdown, log_target input, db_purge_age/db_max_matches number inputs, Save button.
|
||||
- **Server** — same plus read-only db_path/syslog_socket, Flush Logs button.
|
||||
- **Regex Tester** — pattern + log line inputs, "Test Pattern" button with match badge + groups, plus log file preview section.
|
||||
|
||||
### 7.7 Build the regex tester UI (frontend)
|
||||
### 7.7 Build the regex tester UI (frontend) ✅ DONE
|
||||
|
||||
Add a "Regex Tester" section to the configuration page (or as a dialog/panel). Two input fields: one for a sample log line, one for the regex pattern. On every change (debounced), call the regex-test endpoint and display the result — whether it matched, and highlight the matched groups. Use monospace font for both inputs. See [Features.md § 6 (Regex Tester)](Features.md).
|
||||
"Regex Tester" tab in `ConfigPage.tsx`. Pattern input (monospace) + sample log-line Textarea. On click calls `POST /api/config/regex-test` via `useRegexTester` hook. Displays match/no-match `Badge` with icon and lists captured groups. Below it: log file preview form calling `POST /api/config/preview-log`, renders each line color-coded (green = matched, neutral = no match) with summary count.
|
||||
|
||||
### 7.8 Build the server settings UI (frontend)
|
||||
### 7.8 Build the server settings UI (frontend) ✅ DONE
|
||||
|
||||
Add a "Server Settings" section to the configuration page. Display current values for log level, log target, syslog socket, DB path, purge age, and max matches. Provide dropdowns for log level and log target, text inputs for paths and numeric values. Include a "Flush Logs" button. See [Features.md § 6 (Server Settings)](Features.md).
|
||||
"Server" tab in `ConfigPage.tsx`. Shows all six settings editable (log_level dropdown, log_target, db_purge_age, db_max_matches) plus read-only db_path and syslog_socket fields. Includes "Flush Logs" button via `useServerSettings` hook. All via `frontend/src/api/config.ts` and `frontend/src/hooks/useConfig.ts`.
|
||||
|
||||
### 7.9 Write tests for configuration features
|
||||
Also created `frontend/src/types/config.ts` (all TS interfaces) and fixed pre-existing lint errors across the codebase: deprecated `JSX.Element` → `React.JSX.Element` in 10 files, void/promise patterns in `useServerStatus.ts` and `useJails.ts`, `no-misused-spread` in `client.ts`, `eslint.config.ts` excluded from linting.
|
||||
|
||||
Test config read and write operations with mocked fail2ban responses, regex validation (valid and invalid patterns), the regex tester with matching and non-matching inputs, and server settings read/write. Verify that changes are only applied after validation passes.
|
||||
### 7.9 Write tests for configuration features ✅ DONE
|
||||
|
||||
285 backend tests pass (68 new vs 217 before Stage 7). New test files:
|
||||
- `backend/tests/test_services/test_config_service.py` — `TestGetJailConfig`, `TestListJailConfigs`, `TestUpdateJailConfig`, `TestGetGlobalConfig`, `TestUpdateGlobalConfig`, `TestTestRegex`, `TestPreviewLog`
|
||||
- `backend/tests/test_services/test_server_service.py` — `TestGetSettings`, `TestUpdateSettings`, `TestFlushLogs`
|
||||
- `backend/tests/test_routers/test_config.py` — `TestGetJailConfigs`, `TestGetJailConfig`, `TestUpdateJailConfig`, `TestGetGlobalConfig`, `TestUpdateGlobalConfig`, `TestReloadFail2ban`, `TestRegexTest`, `TestAddLogPath`, `TestPreviewLog`
|
||||
- `backend/tests/test_routers/test_server.py` — `TestGetServerSettings`, `TestUpdateServerSettings`, `TestFlushLogs`
|
||||
|
||||
Backend linters: `ruff check` clean, `mypy app/` clean (44 files). Frontend: `tsc --noEmit` clean, `eslint` clean (0 errors, 0 warnings).
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user