- Rewrite FiltersTab: use fetchFilters() for FilterConfig[] with embedded active
status; show 'Active — sshd, apache-auth' badge labels; FilterDetail sub-
component with source_file/override badges, FilterForm, Assign button, raw
config section
- New AssignFilterDialog: selects jail from enabled-jails list, calls
POST /config/jails/{name}/filter with optional fail2ban reload
- New CreateFilterDialog: name+failregex+ignoreregex form, calls
POST /config/filters, closes and selects new filter on success
- Extend ConfigListDetail: add listHeader (for Create button) and
itemBadgeLabel (for custom badge text) optional props
- Fix updateFilterFile bug: was PUT /config/filters/{name} (structured
endpoint), now correctly PUT /config/filters/{name}/raw
- Fix createFilterFile bug: was POST /config/filters, now POST /config/filters/raw
- Add updateFilter, createFilter, deleteFilter, assignFilterToJail to api/config.ts
- Add FilterUpdateRequest, FilterCreateRequest, AssignFilterRequest to types/config.ts
- Add configFiltersRaw, configJailFilter endpoints
- Tests: 24 new tests across FiltersTab, AssignFilterDialog, CreateFilterDialog
(all 89 frontend tests passing)
346 lines
23 KiB
Markdown
346 lines
23 KiB
Markdown
# BanGUI — Task List
|
|
|
|
This document breaks the entire BanGUI project into development stages, ordered so that each stage builds on the previous one. Every task is described in prose with enough detail for a developer to begin work. References point to the relevant documentation.
|
|
|
|
---
|
|
|
|
## Stage 1 — Inactive Jail Discovery and Activation
|
|
|
|
Currently BanGUI only shows jails that are actively running in fail2ban. fail2ban ships with dozens of pre-defined jails in `jail.conf` (sshd, apache-auth, nginx-http-auth, postfix, etc.) that are disabled by default. Users must be able to see these inactive jails and activate them from the web interface.
|
|
|
|
### Task 1.1 — Backend: Parse Inactive Jails from Config Files ✅ DONE
|
|
|
|
**Goal:** Read all jail definitions from the fail2ban configuration files and identify which ones are not currently enabled.
|
|
|
|
**Details:**
|
|
|
|
- Create a new service `config_file_service.py` in `app/services/` responsible for reading and writing fail2ban config files on disk.
|
|
- Parse `jail.conf` and any `jail.local` / `jail.d/*.conf` / `jail.d/*.local` override files. Use Python's `configparser` (INI format) since fail2ban configs follow that format. Local files override `.conf` files (fail2ban merge order: `jail.conf` → `jail.local` → `jail.d/*.conf` → `jail.d/*.local`).
|
|
- For each jail section found, extract at minimum: jail name, `enabled` flag (defaults to `false` if absent), `filter` name (defaults to the jail name if absent), `action` references, `port`, `logpath`, `backend`, `bantime`, `findtime`, `maxretry`.
|
|
- Build a list of `InactiveJail` objects for jails where `enabled = false` or that are defined in config but not reported by `fail2ban-client status`.
|
|
- The fail2ban config base path should come from the application settings (default: `/etc/fail2ban/`). The path is already available via `config.py` settings or can be derived from the fail2ban socket connection.
|
|
- Handle the `[DEFAULT]` section properly — its values provide defaults inherited by every jail section.
|
|
- Handle `[INCLUDES]` sections (`before` / `after` directives) so that path includes like `paths-debian.conf` are resolved, providing variables like `%(sshd_log)s`.
|
|
|
|
**Files to create/modify:**
|
|
- `app/services/config_file_service.py` (new)
|
|
- `app/models/config.py` (add `InactiveJail`, `InactiveJailListResponse` models)
|
|
|
|
**References:** [Features.md §6](Features.md), [Architekture.md §2](Architekture.md), [Backend-Development.md](Backend-Development.md)
|
|
|
|
---
|
|
|
|
### Task 1.2 — Backend: API Endpoints for Inactive Jails ✅ DONE
|
|
|
|
**Goal:** Expose inactive jail data and an activation endpoint via the REST API.
|
|
|
|
**Details:**
|
|
|
|
- Add a `GET /api/config/jails/inactive` endpoint to the config router that returns all inactive jails found in the config files. Each entry should include: `name`, `filter`, `actions` (list), `port`, `logpath`, `bantime`, `findtime`, `maxretry`, and the source file where the jail is defined.
|
|
- Add a `POST /api/config/jails/{name}/activate` endpoint that enables an inactive jail. This endpoint should:
|
|
1. Validate the jail name exists in the parsed config.
|
|
2. Write `enabled = true` into the appropriate `.local` override file (`jail.local` or `jail.d/{name}.local`). Never modify `.conf` files directly — always use `.local` overrides following fail2ban convention.
|
|
3. Optionally accept a request body with override values (`bantime`, `findtime`, `maxretry`, `port`, `logpath`) that get written alongside the `enabled = true` line.
|
|
4. Trigger a fail2ban reload so the jail starts immediately.
|
|
5. Return the jail's new status after activation.
|
|
- Add a `POST /api/config/jails/{name}/deactivate` endpoint that sets `enabled = false` in the `.local` file and reloads fail2ban to stop the jail.
|
|
- All endpoints require authentication. Return 404 if the jail name is not found in any config file. Return 409 if the jail is already active/inactive.
|
|
|
|
**Files to create/modify:**
|
|
- `app/routers/config.py` (add endpoints)
|
|
- `app/services/config_file_service.py` (add activate/deactivate logic)
|
|
- `app/models/config.py` (add request/response models: `ActivateJailRequest`, `JailActivationResponse`)
|
|
|
|
**References:** [Features.md §6](Features.md), [Backend-Development.md §3](Backend-Development.md)
|
|
|
|
---
|
|
|
|
### Task 1.3 — Frontend: Inactive Jails in Configuration View ✅ DONE
|
|
|
|
**Goal:** Display inactive jails in the Configuration page and let users activate them.
|
|
|
|
**Details:**
|
|
|
|
- In the **Jails tab** of the Configuration page, extend the existing master/detail list layout. The left pane currently shows active jails — add a section or toggle that also shows inactive jails. Use the **Active/Inactive badge** system described in [Features.md §6](Features.md): active jails sorted to the top with an "Active" badge, inactive jails below with an "Inactive" badge, alphabetical within each group.
|
|
- Clicking an inactive jail in the list loads its config details in the right detail pane. Show all parsed fields (filter, actions, port, logpath, bantime, findtime, maxretry) as read-only or editable fields.
|
|
- Add an **"Activate Jail"** button (prominent, primary style) in the detail pane for inactive jails. Clicking it opens a confirmation dialog that allows the user to override default values (bantime, findtime, maxretry, port, logpath) before activation. On confirm, call `POST /api/config/jails/{name}/activate` with the overrides.
|
|
- After successful activation, refresh the jail list and show the jail under the active group with a success toast notification.
|
|
- For active jails, add a **"Deactivate Jail"** button (secondary/danger style) that calls the deactivate endpoint after confirmation.
|
|
- Add the API functions `fetchInactiveJails()`, `activateJail(name, overrides)`, `deactivateJail(name)` to `frontend/src/api/config.ts`.
|
|
- Add corresponding TypeScript types (`InactiveJail`, `ActivateJailRequest`) to `frontend/src/types/config.ts`.
|
|
|
|
**Files to create/modify:**
|
|
- `frontend/src/api/config.ts` (add API calls)
|
|
- `frontend/src/types/config.ts` (add types)
|
|
- `frontend/src/components/config/JailsTab.tsx` (add inactive jail list + activation UI)
|
|
- New component: `frontend/src/components/config/ActivateJailDialog.tsx`
|
|
|
|
**References:** [Features.md §6](Features.md), [Web-Design.md](Web-Design.md), [Web-Development.md](Web-Development.md)
|
|
|
|
---
|
|
|
|
### Task 1.4 — Frontend: Inactive Jails on Jails Page ✅ DONE
|
|
|
|
**Goal:** Show inactive jails alongside active jails in the Jail Management overview.
|
|
|
|
**Details:**
|
|
|
|
- On the **Jails Page** (`JailsPage.tsx`), extend the jail overview table to include inactive jails. Add a column or badge showing each jail's activation state.
|
|
- Inactive jails should appear in the table with dimmed/muted styling and show "Inactive" as status. They should not have start/stop/idle/reload controls — only an "Activate" action button.
|
|
- Add a toggle or filter above the table: "Show inactive jails" (default: on). When off, only active jails are displayed.
|
|
- Clicking an inactive jail's name navigates to the Configuration page's jail detail for that jail, pre-selecting it in the list.
|
|
|
|
**Files to create/modify:**
|
|
- `frontend/src/pages/JailsPage.tsx`
|
|
- `frontend/src/hooks/useJails.ts` (extend to optionally fetch inactive jails)
|
|
|
|
**References:** [Features.md §5](Features.md), [Web-Design.md](Web-Design.md)
|
|
|
|
---
|
|
|
|
### Task 1.5 — Tests: Inactive Jail Parsing and Activation ✅ DONE
|
|
|
|
**Goal:** Full test coverage for the new inactive-jail functionality.
|
|
|
|
**Details:**
|
|
|
|
- **Service tests** (`tests/test_services/test_config_file_service.py`): Test config file parsing with mock jail.conf content containing multiple jails (enabled and disabled). Test the merge order (`.conf` → `.local` → `jail.d/`). Test DEFAULT section inheritance. Test variable interpolation (`%(sshd_log)s`). Test activation writes to `.local` files. Test deactivation.
|
|
- **Router tests** (`tests/test_routers/test_config.py`): Add tests for the three new endpoints. Test 404 for unknown jail names. Test 409 for already-active/inactive jails. Test that override values are passed through correctly.
|
|
- **Frontend tests**: Add unit tests for the new API functions. Add component tests for the activation dialog and the inactive jail display.
|
|
|
|
**Files to create/modify:**
|
|
- `backend/tests/test_services/test_config_file_service.py` (new)
|
|
- `backend/tests/test_routers/test_config.py` (extend)
|
|
- `frontend/src/components/config/__tests__/` (new tests)
|
|
|
|
**References:** [Backend-Development.md](Backend-Development.md), [Web-Development.md](Web-Development.md)
|
|
|
|
---
|
|
|
|
## Stage 2 — Filter Configuration Discovery and Activation
|
|
|
|
fail2ban ships with a large collection of filter definitions in `filter.d/` (over 80 files). Users need to see all available filters — both those currently in use by active jails and those available but unused — and assign them to jails.
|
|
|
|
### Task 2.1 — Backend: List All Available Filters with Active/Inactive Status ✅ DONE
|
|
|
|
**Goal:** Enumerate all filter config files and mark each as active or inactive.
|
|
|
|
**Details:**
|
|
|
|
- Add a method `list_filters()` to `config_file_service.py` that scans the `filter.d/` directory within the fail2ban config path.
|
|
- For each `.conf` file found, parse its `[Definition]` section to extract: `failregex` (list of patterns), `ignoreregex` (list), `datepattern`, `journalmatch`, and any other fields present. Also parse `[Init]` sections for default variable bindings.
|
|
- Handle `.local` overrides: if `sshd.local` exists alongside `sshd.conf`, merge the local values on top of the conf values (local wins).
|
|
- Determine active/inactive status: a filter is "active" if its name matches the `filter` field of any currently enabled jail (cross-reference with the active jail list from fail2ban and the inactive jail configs). Mark it accordingly.
|
|
- Return a list of `FilterConfig` objects with: `name`, `active` (bool), `used_by_jails` (list of jail names using this filter), `failregex` (list), `ignoreregex` (list), `datepattern`, `source_file` (path to the `.conf` file), `has_local_override` (bool).
|
|
- Add a `GET /api/config/filters` endpoint to the config router returning all filters.
|
|
- Add a `GET /api/config/filters/{name}` endpoint returning the full parsed detail of a single filter.
|
|
|
|
**Files to create/modify:**
|
|
- `app/services/config_file_service.py` (add `list_filters`, `get_filter`)
|
|
- `app/models/config.py` (add `FilterConfig`, `FilterListResponse`, `FilterDetailResponse`)
|
|
- `app/routers/config.py` (add endpoints)
|
|
|
|
**References:** [Features.md §6](Features.md), [Architekture.md §2](Architekture.md)
|
|
|
|
---
|
|
|
|
### Task 2.2 — Backend: Activate and Edit Filters ✅ DONE
|
|
|
|
**Implemented:**
|
|
- `PUT /api/config/filters/{name}` — writes `failregex`, `ignoreregex`, `datepattern`, `journalmatch` changes to `filter.d/{name}.local`. Validates regex before writing. Supports `?reload=true`.
|
|
- `POST /api/config/filters` — creates `filter.d/{name}.local` from `FilterCreateRequest`. Returns 409 if file already exists.
|
|
- `DELETE /api/config/filters/{name}` — deletes `.local` only; refuses with 409 if filter is conf-only (readonly).
|
|
- `POST /api/config/jails/{name}/filter` — assigns a filter to a jail by writing `filter = {name}` to `jail.d/{jail}.local`. Supports `?reload=true`.
|
|
- All regex patterns validated via `re.compile()` before writing; invalid patterns return 422.
|
|
- New models: `FilterUpdateRequest`, `FilterCreateRequest`, `AssignFilterRequest`.
|
|
- Resolved routing conflict: `file_config.py` raw-write routes renamed to `PUT /filters/{name}/raw` and `POST /filters/raw` (consistent with existing `GET /filters/{name}/raw`).
|
|
- Full service + router tests added; all 930 tests pass.
|
|
|
|
**Files modified:** `app/models/config.py`, `app/services/config_file_service.py`, `app/routers/config.py`, `app/routers/file_config.py`, `tests/test_services/test_config_file_service.py`, `tests/test_routers/test_config.py`, `tests/test_routers/test_file_config.py`
|
|
|
|
---
|
|
|
|
### Task 2.3 — Frontend: Filters Tab with Active/Inactive Display and Activation ✅ DONE
|
|
|
|
**Goal:** Enhance the Filters tab in the Configuration page to show all filters with their active/inactive status and allow editing.
|
|
|
|
**Details:**
|
|
|
|
- Redesign the **Filters tab** to use the master/detail list layout described in [Features.md §6](Features.md).
|
|
- The **left pane** lists all filter names with an Active or Inactive badge. Active filters (those used by at least one enabled jail) are sorted to the top. Within each group, sort alphabetically.
|
|
- The badge should also show which jails use the filter (e.g., "Active — used by sshd, apache-auth").
|
|
- Clicking a filter loads its detail in the **right pane**: `failregex` patterns (editable list), `ignoreregex` patterns (editable list), `datepattern` (editable), source file info, and whether a `.local` override exists.
|
|
- Add a **"Save Changes"** button that calls `PUT /api/config/filters/{name}` to persist edits to the `.local` override. Show save-state feedback (idle → saving → saved → error).
|
|
- Add an **"Assign to Jail"** button that opens a dialog where the user selects a jail and assigns this filter to it. This calls the assign-filter endpoint.
|
|
- Add a **"Create Filter"** button at the top of the list pane that opens a dialog for entering a new filter name and regex patterns.
|
|
- On narrow screens (< 900 px), collapse the list pane into a dropdown as specified in [Features.md §6](Features.md).
|
|
- Include the existing **Raw Configuration** collapsible section at the bottom of the detail pane for direct file editing.
|
|
|
|
**Files to create/modify:**
|
|
- `frontend/src/components/config/FiltersTab.tsx` (rewrite with master/detail layout)
|
|
- `frontend/src/components/config/FilterForm.tsx` (update for editable fields)
|
|
- `frontend/src/api/config.ts` (add `fetchFilters`, `fetchFilter`, `updateFilter`, `createFilter`, `deleteFilter`, `assignFilterToJail`)
|
|
- `frontend/src/types/config.ts` (add types)
|
|
- New component: `frontend/src/components/config/AssignFilterDialog.tsx`
|
|
|
|
**References:** [Features.md §6](Features.md), [Web-Design.md](Web-Design.md), [Web-Development.md](Web-Development.md)
|
|
|
|
---
|
|
|
|
### Task 2.4 — Tests: Filter Discovery and Management ✅ DONE
|
|
|
|
**Goal:** Test coverage for filter listing, editing, creation, and assignment.
|
|
|
|
**Details:**
|
|
|
|
- **Service tests**: Mock the `filter.d/` directory with sample `.conf` and `.local` files. Test parsing of `[Definition]` sections. Test merge of `.local` over `.conf`. Test active/inactive detection by cross-referencing with mock jail data. Test write operations create correct `.local` content. Test regex validation rejects bad patterns.
|
|
- **Router tests**: Test all new filter endpoints (list, detail, update, create, delete, assign). Test auth required. Test 404/409/422 responses.
|
|
- **Frontend tests**: Test the filter list rendering with mixed active/inactive items. Test the form submission in the detail pane. Test the assign dialog.
|
|
|
|
**Files to create/modify:**
|
|
- `backend/tests/test_services/test_config_file_service.py` (extend)
|
|
- `backend/tests/test_routers/test_config.py` (extend)
|
|
- `frontend/src/components/config/__tests__/` (add filter tests)
|
|
|
|
---
|
|
|
|
## Stage 3 — Action Configuration Discovery and Activation
|
|
|
|
fail2ban ships with many action definitions in `action.d/` (iptables, firewalld, cloudflare, sendmail, etc.). Users need to see all available actions, understand which are in use, and assign them to jails.
|
|
|
|
### Task 3.1 — Backend: List All Available Actions with Active/Inactive Status
|
|
|
|
**Goal:** Enumerate all action config files and mark each as active or inactive based on jail usage.
|
|
|
|
**Details:**
|
|
|
|
- Add a method `list_actions()` to `config_file_service.py` that scans the `action.d/` directory.
|
|
- For each `.conf` file, parse the `[Definition]` section to extract: `actionstart`, `actionstop`, `actioncheck`, `actionban`, `actionunban` commands. Also parse `[Init]` for default variable bindings (port, protocol, chain, etc.).
|
|
- Handle `.local` overrides the same way as filters.
|
|
- Determine active/inactive status: an action is "active" if its name appears in the `action` field of any currently enabled jail. Cross-reference against both running jails (from fail2ban) and the config files.
|
|
- Return `ActionConfig` objects with: `name`, `active` (bool), `used_by_jails` (list), `actionban` (command template), `actionunban` (command template), `actionstart`, `actionstop`, `init_params` (dict of Init variables), `source_file`, `has_local_override`.
|
|
- Add `GET /api/config/actions` endpoint returning all actions.
|
|
- Add `GET /api/config/actions/{name}` endpoint returning the full parsed detail of one action.
|
|
|
|
**Files to create/modify:**
|
|
- `app/services/config_file_service.py` (add `list_actions`, `get_action`)
|
|
- `app/models/config.py` (add `ActionConfig`, `ActionListResponse`, `ActionDetailResponse`)
|
|
- `app/routers/config.py` (add endpoints)
|
|
|
|
**References:** [Features.md §6](Features.md), [Architekture.md §2](Architekture.md)
|
|
|
|
---
|
|
|
|
### Task 3.2 — Backend: Activate and Edit Actions
|
|
|
|
**Goal:** Allow users to assign actions to jails, edit action definitions, and create new actions.
|
|
|
|
**Details:**
|
|
|
|
- Add a `PUT /api/config/actions/{name}` endpoint that writes changes to an action's `.local` override file. Accepts updated `actionban`, `actionunban`, `actionstart`, `actionstop`, `actioncheck` values and any `[Init]` parameters.
|
|
- Add a `POST /api/config/jails/{jail_name}/action` endpoint that adds an action to a jail's action list. This writes the action reference into the jail's `.local` config file. Multiple actions per jail are supported (fail2ban allows comma-separated action lists). Include optional parameters for the action (e.g., port, protocol).
|
|
- Add a `DELETE /api/config/jails/{jail_name}/action/{action_name}` endpoint that removes an action from a jail's configuration.
|
|
- Add a `POST /api/config/actions` endpoint to create a brand-new action definition (`.local` file).
|
|
- Add a `DELETE /api/config/actions/{name}` endpoint to delete a custom action's `.local` file. Same safety rules as filters — refuse to delete shipped `.conf` files.
|
|
- After any write, optionally reload fail2ban (`?reload=true`).
|
|
|
|
**Files to create/modify:**
|
|
- `app/services/config_file_service.py` (add action write/create/delete/assign methods)
|
|
- `app/routers/config.py` (add endpoints)
|
|
- `app/models/config.py` (add `ActionUpdateRequest`, `ActionCreateRequest`, `AssignActionRequest`)
|
|
|
|
**References:** [Features.md §6](Features.md), [Backend-Development.md](Backend-Development.md)
|
|
|
|
---
|
|
|
|
### Task 3.3 — Frontend: Actions Tab with Active/Inactive Display and Activation
|
|
|
|
**Goal:** Enhance the Actions tab in the Configuration page to show all actions with active/inactive status and allow editing and assignment.
|
|
|
|
**Details:**
|
|
|
|
- Redesign the **Actions tab** to use the same master/detail list layout as Filters.
|
|
- The **left pane** lists all action names with Active/Inactive badges. Active actions (used by at least one enabled jail) sorted to the top.
|
|
- Badge shows which jails reference the action (e.g., "Active — used by sshd, postfix").
|
|
- Clicking an action loads its detail in the **right pane**: `actionban`, `actionunban`, `actionstart`, `actionstop`, `actioncheck` (each in a code/textarea editor), `[Init]` parameters as key-value fields.
|
|
- Add a **"Save Changes"** button for persisting edits to the `.local` override.
|
|
- Add an **"Assign to Jail"** button that opens a dialog for selecting a jail and providing action parameters (port, protocol, chain). Calls the assign-action endpoint.
|
|
- Add a **"Remove from Jail"** option in the detail pane — shows a list of jails currently using the action with a remove button next to each.
|
|
- Add a **"Create Action"** button at the top of the list pane.
|
|
- Raw Configuration collapsible section at the bottom.
|
|
- Responsive collapse on narrow screens.
|
|
|
|
**Files to create/modify:**
|
|
- `frontend/src/components/config/ActionsTab.tsx` (rewrite with master/detail layout)
|
|
- `frontend/src/components/config/ActionForm.tsx` (update for editable fields)
|
|
- `frontend/src/api/config.ts` (add `fetchActions`, `fetchAction`, `updateAction`, `createAction`, `deleteAction`, `assignActionToJail`, `removeActionFromJail`)
|
|
- `frontend/src/types/config.ts` (add types)
|
|
- New component: `frontend/src/components/config/AssignActionDialog.tsx`
|
|
|
|
**References:** [Features.md §6](Features.md), [Web-Design.md](Web-Design.md), [Web-Development.md](Web-Development.md)
|
|
|
|
---
|
|
|
|
### Task 3.4 — Tests: Action Discovery and Management
|
|
|
|
**Goal:** Test coverage for action listing, editing, creation, and assignment.
|
|
|
|
**Details:**
|
|
|
|
- **Service tests**: Mock `action.d/` with sample configs. Test parsing of `[Definition]` and `[Init]` sections. Test active/inactive detection. Test write and create operations. Test delete safety (refuse `.conf` deletion).
|
|
- **Router tests**: Test all new action endpoints. Test auth, 404, 409, 422 responses.
|
|
- **Frontend tests**: Test action list rendering, form editing, assign dialog, remove-from-jail flow.
|
|
|
|
**Files to create/modify:**
|
|
- `backend/tests/test_services/test_config_file_service.py` (extend)
|
|
- `backend/tests/test_routers/test_config.py` (extend)
|
|
- `frontend/src/components/config/__tests__/` (add action tests)
|
|
|
|
---
|
|
|
|
## Stage 4 — Unified Config File Service and Shared Utilities
|
|
|
|
### Task 4.1 — Config File Parser Utility
|
|
|
|
**Goal:** Build a robust, reusable parser for fail2ban INI-style config files that all config-related features share.
|
|
|
|
**Details:**
|
|
|
|
- Create `app/utils/config_parser.py` with a `Fail2BanConfigParser` class that wraps Python's `configparser.ConfigParser` with fail2ban-specific behaviour:
|
|
- **Merge order**: `.conf` file first, then `.local` overlay, then `*.d/` directory overrides.
|
|
- **Variable interpolation**: Support `%(variable)s` syntax, resolving against `[DEFAULT]` and `[Init]` sections.
|
|
- **Include directives**: Process `before = filename` and `after = filename` in `[INCLUDES]` sections, resolving paths relative to the config directory.
|
|
- **Multi-line values**: Handle backslash-continuation and multi-line regex lists.
|
|
- **Comments**: Strip `#` and `;` line/inline comments correctly.
|
|
- The parser should return structured `dict` data that the `config_file_service` methods consume.
|
|
- This is a pure utility — no I/O aside from reading files. Everything is synchronous, callable from async context via `run_in_executor`.
|
|
- Write comprehensive unit tests in `tests/test_utils/test_config_parser.py` covering all edge cases: empty sections, missing files, circular includes, invalid interpolation, multi-line regex, override merging.
|
|
|
|
**Files to create/modify:**
|
|
- `app/utils/config_parser.py` (new)
|
|
- `tests/test_utils/test_config_parser.py` (new)
|
|
|
|
**References:** [Backend-Development.md](Backend-Development.md)
|
|
|
|
---
|
|
|
|
### Task 4.2 — Config File Writer Utility
|
|
|
|
**Goal:** Build a safe writer utility for creating and updating `.local` override files.
|
|
|
|
**Details:**
|
|
|
|
- Create `app/utils/config_writer.py` with functions for:
|
|
- `write_local_override(base_path, section, key_values)` — Writes or updates a `.local` file. If the file exists, update only the specified keys under the given section. If it does not exist, create it with a header comment explaining it's a BanGUI-managed override.
|
|
- `remove_local_key(base_path, section, key)` — Removes a specific key from a `.local` file.
|
|
- `delete_local_file(path)` — Deletes a `.local` file, but only if no corresponding `.conf` exists or the caller explicitly allows orphan deletion.
|
|
- All write operations must be atomic: write to a temporary file first, then rename into place (`os.replace`). This prevents corruption on crash.
|
|
- Add a file-level lock (per config file) to prevent concurrent writes from racing.
|
|
- Never write to `.conf` files — assert this in every write function.
|
|
|
|
**Files to create/modify:**
|
|
- `app/utils/config_writer.py` (new)
|
|
- `tests/test_utils/test_config_writer.py` (new)
|
|
|
|
**References:** [Backend-Development.md](Backend-Development.md)
|