7.4 KiB
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.
Open Issues
Architectural Review — 2026-03-16 The findings below were identified by auditing every backend and frontend module against the rules in Refactoring.md and Architekture.md. Tasks are grouped by layer and ordered so that lower-level fixes (repositories, services) are done before the layers that depend on them.
Task 1 — Blocklist-import jail ban time must be 24 hours
Status: ✅ Done
Context
When the blocklist importer bans an IP it calls jail_service.ban_ip(socket_path, BLOCKLIST_JAIL, ip) (see backend/app/services/blocklist_service.py, constant BLOCKLIST_JAIL = "blocklist-import"). That call sends set blocklist-import banip <ip> to fail2ban, which applies the jail's configured bantime. There is currently no guarantee that the blocklist-import jail's bantime is 86 400 s (24 h), so imported IPs may be released too early or held indefinitely depending on the jail template.
What to do
- Locate every place the
blocklist-importjail is defined or provisioned — checkDocker/fail2ban-dev-config/,Docker/Dockerfile.backend, any jail template files, and thesetup_service.py/SetupPage.tsxflow. - Ensure the
blocklist-importjail is created withbantime = 86400(24 h). If the jail is created at runtime by the setup service, add or update thebantimeparameter there. If it is defined in a static config file, setbantime = 86400in that file. - Verify that the existing
jail_service.ban_ipcall inblocklist_service.import_sourcedoes not need a per-call duration override; the jail-level default of 86 400 s is sufficient. - Add or update the relevant unit/integration test in
backend/tests/to assert that the blocklist-import jail is set up with a 24-hour bantime.
Task 2 — Clicking a jail in Jail Overview navigates to Configuration → Jails
Status: ✅ Done
Context
JailsPage.tsx renders a "Jail Overview" data grid with one row per jail (see frontend/src/pages/JailsPage.tsx). Clicking a row currently does nothing. ConfigPage.tsx hosts a tab bar with a "Jails" tab that renders JailsTab, which already uses a list/detail layout where a jail can be selected from the left pane.
What to do
- In
JailsPage.tsx, make each jail name cell (or the entire row) a clickable element that navigates to/configwith state{ tab: "jails", jail: "<jailName>" }. UseuseNavigatefromreact-router-dom; the existingLinkimport can be used or replaced with a programmatic navigate. - In
ConfigPage.tsx, read the location state on mount. Ifstate.tabis"jails", set the active tab to"jails". Passstate.jaildown to<JailsTab initialJail={state.jail} />. - In
JailsTab.tsx, accept an optionalinitialJail?: stringprop. When it is provided, pre-select that jail in the left-pane list on first render (i.e. set the selected jail state to the jail whose name matchesinitialJail). This should scroll the item into view if the list is long. - Add a frontend unit test in
frontend/src/pages/__tests__/that mountsJailsPagewith a mocked jail list, clicks a jail row, and asserts thatuseNavigatewas called with the correct path and state.
Task 3 — Setting bantime / findtime throws 400 error due to unsupported backend set command
Status: ✅ Done
Context
Editing ban time or find time in Configuration → Jails triggers an auto-save that sends the full JailConfigUpdate payload including the backend field. config_service.update_jail_config then calls set <jail> backend <value> on the fail2ban socket, which returns error code 1 with the message Invalid command 'backend' (no set action or not yet implemented). Fail2ban does not support changing a jail's backend at runtime; it must be set before the jail starts.
What to do
Backend (backend/app/services/config_service.py):
- Remove the
if update.backend is not None: await _set("backend", update.backend)block fromupdate_jail_config. Settingbackendvia the socket is not supported by fail2ban and will always fail. log_encodinghas the same constraint — verify whetherset <jail> logencodingis supported at runtime. If it is not, remove it too. If it is supported, leave it.- Ensure the function still accepts and stores the
backendvalue in the Pydantic model for read purposes; do not remove it fromJailConfigUpdateor the response model.
Frontend (frontend/src/components/config/JailsTab.tsx):
- Remove
backend(andlog_encodingif step 2 confirms it is unsupported) from theautoSavePayloadmemo so the field is never sent in the PATCH/PUT body. The displayed value should remain read-only — show them as plain text or a disabled select so the user can see the current value without being able to trigger the broken set command.
Tests:
- Add or update the backend test for
update_jail_configto assert that noset … backendcommand is issued, and that a payload containing abackendfield does not cause an error.
Task 4 — Unify filter bar: use DashboardFilterBar in World Map and History pages
Status: ✅ Done
Context
DashboardPage.tsx uses the shared <DashboardFilterBar> component for its time-range and origin-filter controls. MapPage.tsx and HistoryPage.tsx each implement their own ad-hoc filter UI: MapPage uses a Fluent UI <Select> for time range plus an inline Toolbar for origin filter; HistoryPage uses a <Select> for time range with no origin filter toggle. The DashboardFilterBar already supports both TimeRange and BanOriginFilter with the exact toggle-button style shown in the design reference. All three pages should share the same filter appearance and interaction patterns.
What to do
MapPage.tsx: Replace the custom time-range<Select>and the inline origin-filter Toolbar with<DashboardFilterBar timeRange={range} onTimeRangeChange={setRange} originFilter={originFilter} onOriginFilterChange={setOriginFilter} />. Remove the now-unusedTIME_RANGE_OPTIONSconstant and theBAN_ORIGIN_FILTER_LABELSinline usage. PassoriginFiltertouseMapDataif it does not already receive it (check the hook signature).HistoryPage.tsx: Replace the custom time-range<Select>with<DashboardFilterBar>. Add anoriginFilterstate (BanOriginFilter, default"all") and wire it through<DashboardFilterBar onOriginFilterChange={setOriginFilter} />. Pass the origin filter into theuseHistoryquery so the backend receives it. IfuseHistory/HistoryQuerydoes not yet acceptorigin_filter, add the parameter to the type and the hook's fetch call.- Remove any local
filterBarstyle definitions fromMapPage.tsxandHistoryPage.tsxthat duplicate whatDashboardFilterBaralready provides. - Ensure the
DashboardFilterBarcomponent's props interface (DashboardFilterBarPropsinfrontend/src/components/DashboardFilterBar.tsx) is not changed in a breaking way; only the call sites change. - Update or add component tests for
MapPageandHistoryPageto assert thatDashboardFilterBaris rendered and that changing the time range or origin filter updates the displayed data.