From 38d1594d21d3b0d891b6a3ccfa1926746df30e7a Mon Sep 17 00:00:00 2001 From: Lukas Date: Sun, 21 Jun 2026 20:14:22 +0200 Subject: [PATCH] docs: update tasks, runner and e2e auth tests --- Docs/Tasks.md | 2036 ++++++++++++++++++++++++++++- Docs/runner.csx | 2 +- e2e/tests/01_setup_and_auth.robot | 4 +- 3 files changed, 2033 insertions(+), 9 deletions(-) diff --git a/Docs/Tasks.md b/Docs/Tasks.md index 88772f0..f4303b2 100644 --- a/Docs/Tasks.md +++ b/Docs/Tasks.md @@ -1,15 +1,2039 @@ -## Task: 01 Setup And Auth — Password Strength Indicator Updates On Input +## Task: 01 Setup And Auth — Password Mismatch Shows Validation Error -**Test:** `Password Strength Indicator Updates On Input` +**Test:** `Password Mismatch Shows Validation Error` **Suite:** `01_setup_and_auth.robot` -**Step That Fails:** Parent suite setup (`Wait For Backend Health`). +**Step That Fails:** Waiting for validation alert after submitting mismatched passwords. + +**Error:** `TimeoutError: locator.evaluate: Timeout 10000ms exceeded.` +Waiting for locator: `//*[@aria-label="Confirm Password"]/ancestor::*[contains(@class,"field")]//*[@role="alert"]` **Files to Check:** - `e2e/tests/01_setup_and_auth.robot` -- `frontend/src/components/PasswordStrengthIndicator.tsx` (or equivalent) +- `frontend/src/pages/SetupPage.tsx` +- `e2e/resources/common.resource` **Reference Docs:** -- `Docs/Features.md` — Password strength indicator behavior +- `Docs/Features.md` — Setup wizard validation behavior +- `Docs/Testing-Requirements.md` — E2E assertion patterns -**Expected Behavior:** Four-segment strength bar updates dynamically as user types password. Weak password shows 1 segment, strong password shows 4 segments. +**Expected Behavior:** When passwords don't match and form is submitted, a visible `[role="alert"]` element should appear inside the Confirm Password field container within 10 seconds. + +--- + +## Task: 01 Setup And Auth — Empty Required Fields Show Validation Errors + +**Test:** `Empty Required Fields Show Validation Errors` +**Suite:** `01_setup_and_auth.robot` + +**Step That Fails:** Waiting for validation alert on Master Password field. + +**Error:** `TimeoutError: locator.evaluate: Timeout 10000ms exceeded.` +Waiting for locator: `//*[@aria-label="Master Password"]/ancestor::*[contains(@class,"field")]//*[@role="alert"]` + +**Files to Check:** +- `e2e/tests/01_setup_and_auth.robot` +- `frontend/src/pages/SetupPage.tsx` +- `e2e/resources/common.resource` + +**Reference Docs:** +- `Docs/Features.md` — Setup wizard required field validation +- `Docs/Testing-Requirements.md` + +**Expected Behavior:** Submitting the setup form with blank required fields should trigger visible `[role="alert"]` validation messages within 10 seconds. + +--- + +## Task: 01 Setup And Auth — Invalid Session Duration Shows Validation Error + +**Test:** `Invalid Session Duration Shows Validation Error` +**Suite:** `01_setup_and_auth.robot` + +**Step That Fails:** Waiting for validation alert on Session Duration field. + +**Error:** `TimeoutError: locator.evaluate: Timeout 10000ms exceeded.` +Waiting for locator: `//*[@aria-label="Session Duration (minutes)"]/ancestor::*[contains(@class,"field")]//*[@role="alert"]` + +**Files to Check:** +- `e2e/tests/01_setup_and_auth.robot` +- `frontend/src/pages/SetupPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Session duration validation rules + +**Expected Behavior:** Entering an invalid session duration and submitting should display a `[role="alert"]` error in the field container. + +--- + +## Task: 01 Setup And Auth — Incomplete Password Shows Complexity Error + +**Test:** `Incomplete Password Shows Complexity Error` +**Suite:** `01_setup_and_auth.robot` + +**Step That Fails:** Waiting for validation alert on Master Password field after weak password input. + +**Error:** `TimeoutError: locator.evaluate: Timeout 10000ms exceeded.` +Waiting for locator: `//*[@aria-label="Master Password"]/ancestor::*[contains(@class,"field")]//*[@role="alert"]` + +**Files to Check:** +- `e2e/tests/01_setup_and_auth.robot` +- `frontend/src/pages/SetupPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Password complexity requirements + +**Expected Behavior:** Submitting a password that doesn't meet complexity rules should show a `[role="alert"]` error message. + +--- + +## Task: 02 Ban Records — Simulated Failed Logins Appear As Ban Records + +**Test:** `Simulated Failed Logins Appear As Ban Records` +**Suite:** `02_ban_records.robot` + +**Step That Fails:** Checking ban record contains expected IP. + +**Error:** `'' does not contain '192.168.100.99'` + +**Files to Check:** +- `e2e/tests/02_ban_records.robot` +- `e2e/proxy_server.py` +- `backend/app/routers/bans.py` +- `backend/app/services/ban_service.py` + +**Reference Docs:** +- `Docs/Features.md` — Ban record pipeline +- `Docker/simulate_failed_logins.sh` + +**Expected Behavior:** After simulating failed logins, the ban record should contain the test IP `192.168.100.99` in the response or UI. + +--- + +## Task: 02 Login — Login Page Renders Password Input + +**Test:** `Login Page Renders Password Input` +**Suite:** `02_login.robot` + +**Step That Fails:** Browser launch. + +**Error:** `browserType.launch: Executable doesn't exist at .../chromium_headless_shell-1223/chrome-headless-shell-linux64/chrome-headless-shell` + +**Files to Check:** +- `e2e/tests/02_login.robot` +- Playwright browser installation + +**Reference Docs:** +- `e2e/Instructions.md` — Setup section + +**Expected Behavior:** Chromium browser should launch successfully for UI tests. Run `npx playwright install` or `rfbrowser init` to install browsers. + +--- + +## Task: 02 Login — Login Page Has No Username Field + +**Test:** `Login Page Has No Username Field` +**Suite:** `02_login.robot` + +**Step That Fails:** Browser launch. + +**Error:** `browserType.launch: Executable doesn't exist at .../chromium_headless_shell` + +**Files to Check:** +- `e2e/tests/02_login.robot` +- Playwright browser installation + +**Reference Docs:** +- `e2e/Instructions.md` + +**Expected Behavior:** Browser should launch. This is an environment setup issue, not an application bug. + +--- + +## Task: 02 Login — Login With Wrong Password Shows Error + +**Test:** `Login With Wrong Password Shows Error` +**Suite:** `02_login.robot` + +**Step That Fails:** Browser launch. + +**Error:** `browserType.launch: Executable doesn't exist at .../chromium_headless_shell` + +**Files to Check:** +- `e2e/tests/02_login.robot` +- Playwright browser installation + +**Reference Docs:** +- `e2e/Instructions.md` + +**Expected Behavior:** Browser should launch to perform the login UI test. + +--- + +## Task: 02 Login — Login Rate Limits After Multiple Failures + +**Test:** `Login Rate Limits After Multiple Failures` +**Suite:** `02_login.robot` + +**Step That Fails:** Rate limit not triggered after multiple failed logins. + +**Error:** `Expected a 429 response after multiple failed logins` + +**Files to Check:** +- `e2e/tests/02_login.robot` +- `e2e/resources/auth.resource` +- `backend/app/routers/auth.py` +- `backend/app/middleware/rate_limit.py` + +**Reference Docs:** +- `Docs/Features.md` — Rate limiting rules +- `Docs/Security.md` + +**Expected Behavior:** After 5 failed login attempts from the same IP within 60 seconds, the backend should return HTTP 429 (Too Many Requests). + +--- + +## Task: 02 Login — Direct Access To Protected Route Redirects To Login + +**Test:** `Direct Access To Protected Route Redirects To Login` +**Suite:** `02_login.robot` + +**Step That Fails:** Browser launch. + +**Error:** `browserType.launch: Executable doesn't exist at .../chromium_headless_shell` + +**Files to Check:** +- `e2e/tests/02_login.robot` +- Playwright browser installation + +**Reference Docs:** +- `e2e/Instructions.md` + +**Expected Behavior:** Browser should launch for UI navigation test. + +--- + +## Task: 02 Login — Session Validation 401 On Mount Redirects To Login + +**Test:** `Session Validation 401 On Mount Redirects To Login` +**Suite:** `02_login.robot` + +**Step That Fails:** Browser launch. + +**Error:** `browserType.launch: Executable doesn't exist at .../chromium_headless_shell` + +**Files to Check:** +- `e2e/tests/02_login.robot` +- Playwright browser installation + +**Reference Docs:** +- `e2e/Instructions.md` + +**Expected Behavior:** Browser should launch for UI test. + +--- + +## Task: 02 Login — Logout Clears Session + +**Test:** `Logout Clears Session` +**Suite:** `02_login.robot` + +**Step That Fails:** API call after logout returns 401 instead of 200. + +**Error:** `401 != 200` + +**Files to Check:** +- `e2e/tests/02_login.robot` +- `e2e/resources/auth.resource` +- `backend/app/routers/auth.py` +- `backend/app/services/session_service.py` + +**Reference Docs:** +- `Docs/Features.md` — Session management +- `Docs/API_STATUS_CODES.md` + +**Expected Behavior:** After clicking Sign Out, subsequent API calls should return 401 (unauthenticated), but the logout endpoint itself should return 200. + +--- + +## Task: 02 Login — After Logout Protected Pages Redirect To Login + +**Test:** `After Logout Protected Pages Redirect To Login` +**Suite:** `02_login.robot` + +**Step That Fails:** URL does not contain `/login` after accessing protected page post-logout. + +**Error:** `'http://localhost:5173/' does not contain '/login'` + +**Files to Check:** +- `e2e/tests/02_login.robot` +- `frontend/src/router.tsx` or routing config +- `frontend/src/App.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Authentication flow + +**Expected Behavior:** After logout, navigating to a protected page should redirect to `/login`. + +--- + +## Task: 02 Login — Login Preserves Originally Requested Page Via Next Parameter + +**Test:** `Login Preserves Originally Requested Page Via Next Parameter` +**Suite:** `02_login.robot` + +**Step That Fails:** URL does not contain `next=` parameter after redirect. + +**Error:** `'http://localhost:5173/login' does not contain 'next='` + +**Files to Check:** +- `e2e/tests/02_login.robot` +- `frontend/src/router.tsx` +- `frontend/src/pages/LoginPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Post-login redirect behavior + +**Expected Behavior:** When redirected to login from a protected page, the URL should include a `next=` query parameter preserving the original destination. + +--- + +## Task: 03 Blocklist Import — Manual Blocklist Import Completes Without Error + +**Test:** `Manual Blocklist Import Completes Without Error` +**Suite:** `03_blocklist_import.robot` + +**Step That Fails:** API call returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/blocklists Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/03_blocklist_import.robot` +- `e2e/resources/api.resource` +- `e2e/resources/auth.resource` +- `backend/app/routers/blocklists.py` + +**Reference Docs:** +- `Docs/Features.md` — Blocklist import flow +- `Docs/API_STATUS_CODES.md` + +**Expected Behavior:** Authenticated API call to `/api/v1/blocklists` should return 200, not 401. + +--- + +## Task: 03 Dashboard — Dashboard Ban List Renders Columns + +**Test:** `Dashboard Ban List Renders Columns` +**Suite:** `03_dashboard.robot` + +**Step That Fails:** Page text 'IP' not found. + +**Error:** `Page text 'IP' not found in body` + +**Files to Check:** +- `e2e/tests/03_dashboard.robot` +- `frontend/src/pages/DashboardPage.tsx` +- `frontend/src/components/BanList.tsx` or equivalent + +**Reference Docs:** +- `Docs/Features.md` — Dashboard ban list columns + +**Expected Behavior:** The dashboard ban list table should contain a column header with the text "IP". + +--- + +## Task: 03 Dashboard — Dashboard Time Range 24h Shows Live Source + +**Test:** `Dashboard Time Range 24h Shows Live Source` +**Suite:** `03_dashboard.robot` + +**Step That Fails:** No data-source badge visible after selecting 24h preset. + +**Error:** `No data-source badge visible after selecting preset` + +**Files to Check:** +- `e2e/tests/03_dashboard.robot` +- `frontend/src/pages/DashboardPage.tsx` +- `frontend/src/components/DataSourceBadge.tsx` or equivalent + +**Reference Docs:** +- `Docs/Features.md` — Data source badges + +**Expected Behavior:** Selecting "Last 24 hours" should display a "Live" data-source badge. + +--- + +## Task: 03 Dashboard — Dashboard Time Range 7d Shows Archive Source + +**Test:** `Dashboard Time Range 7d Shows Archive Source` +**Suite:** `03_dashboard.robot` + +**Step That Fails:** No data-source badge visible for 7d preset. + +**Error:** `No data-source badge visible for 7d preset` + +**Files to Check:** +- `e2e/tests/03_dashboard.robot` +- `frontend/src/pages/DashboardPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Data source badges + +**Expected Behavior:** Selecting "Last 7 days" should display an "Archive" data-source badge. + +--- + +## Task: 03 Dashboard — Dashboard Bans Endpoint Returns Expected Shape + +**Test:** `Dashboard Bans Endpoint Returns Expected Shape` +**Suite:** `03_dashboard.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Unexpected status: 401` + +**Files to Check:** +- `e2e/tests/03_dashboard.robot` +- `e2e/resources/api.resource` +- `backend/app/routers/dashboard.py` or `bans.py` + +**Reference Docs:** +- `Docs/API-Reference.md` +- `Docs/API_STATUS_CODES.md` + +**Expected Behavior:** Authenticated GET to bans endpoint should return 200 with expected JSON shape. + +--- + +## Task: 03 Dashboard — Dashboard Status Endpoint Returns Version + +**Test:** `Dashboard Status Endpoint Returns Version` +**Suite:** `03_dashboard.robot` + +**Step That Fails:** API returns 401. + +**Error:** `401 != 200` + +**Files to Check:** +- `e2e/tests/03_dashboard.robot` +- `backend/app/routers/health.py` or status endpoint + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Status endpoint should return 200 with version info when authenticated. + +--- + +## Task: 03 Dashboard — Dashboard Bans By Country Endpoint + +**Test:** `Dashboard Bans By Country Endpoint` +**Suite:** `03_dashboard.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/03_dashboard.robot` +- `backend/app/routers/dashboard.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Bans-by-country endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 03 Dashboard — Dashboard Bans Trend Endpoint + +**Test:** `Dashboard Bans Trend Endpoint` +**Suite:** `03_dashboard.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/03_dashboard.robot` +- `backend/app/routers/dashboard.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Bans trend endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 03 Dashboard — Dashboard Bans By Jail Endpoint + +**Test:** `Dashboard Bans By Jail Endpoint` +**Suite:** `03_dashboard.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/03_dashboard.robot` +- `backend/app/routers/dashboard.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Bans-by-jail endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 04 Map — Map Page 24h Preset Shows Live Source Badge + +**Test:** `Map Page 24h Preset Shows Live Source Badge` +**Suite:** `04_map.robot` + +**Step That Fails:** No data-source badge on map after preset click. + +**Error:** `No data-source badge on map after preset click` + +**Files to Check:** +- `e2e/tests/04_map.robot` +- `frontend/src/pages/MapPage.tsx` +- `frontend/src/components/DataSourceBadge.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Map view data sources + +**Expected Behavior:** Clicking the 24h preset on the map should show a "Live" data-source badge. + +--- + +## Task: 04 Map — Map Page 7d Preset Shows Archive Source Badge + +**Test:** `Map Page 7d Preset Shows Archive Source Badge` +**Suite:** `04_map.robot` + +**Step That Fails:** No data-source badge on map after 7d preset click. + +**Error:** `No data-source badge on map after 7d preset click` + +**Files to Check:** +- `e2e/tests/04_map.robot` +- `frontend/src/pages/MapPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Map view data sources + +**Expected Behavior:** Clicking the 7d preset should show an "Archive" data-source badge. + +--- + +## Task: 04 Map — Map Page Has Zoom Controls + +**Test:** `Map Page Has Zoom Controls` +**Suite:** `04_map.robot` + +**Step That Fails:** Zoom controls not found. + +**Error:** `No zoom controls found` + +**Files to Check:** +- `e2e/tests/04_map.robot` +- `frontend/src/pages/MapPage.tsx` +- `frontend/src/components/WorldMap.tsx` or map component + +**Reference Docs:** +- `Docs/Features.md` — Map zoom controls + +**Expected Behavior:** The map page should have visible zoom in / zoom out / reset buttons. + +--- + +## Task: 04 Map — Map Bans By Country API Endpoint + +**Test:** `Map Bans By Country API Endpoint` +**Suite:** `04_map.robot` + +**Step That Fails:** API returns 401. + +**Error:** `401 != 200` + +**Files to Check:** +- `e2e/tests/04_map.robot` +- `backend/app/routers/map.py` or geo endpoint + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Bans-by-country endpoint should return 200 when authenticated. + +--- + +## Task: 05 Jails — Jails API Returns Active Jails + +**Test:** `Jails API Returns Active Jails` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/jails Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `e2e/resources/api.resource` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` +- `Docs/Features.md` — Jail management + +**Expected Behavior:** GET `/api/v1/jails` should return 200 with active jails list when authenticated. + +--- + +## Task: 05 Jails — Jail Detail Page Loads For First Active Jail + +**Test:** `Jail Detail Page Loads For First Active Jail` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401 when fetching jails list. + +**Error:** `Url: http://localhost:8000/api/v1/jails Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Should be able to fetch jails and navigate to the first active jail's detail page. + +--- + +## Task: 05 Jails — Ban An IP Via API + +**Test:** `Ban An IP Via API` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/jails Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/bans.py` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** POST to ban endpoint should succeed (200) when authenticated. + +--- + +## Task: 05 Jails — Unban The IP We Just Banned + +**Test:** `Unban The IP We Just Banned` +**Suite:** `05_jails.robot` + +**Step That Fails:** Variable `${BANNED_JAIL}` not found. + +**Error:** `Variable '${BANNED_JAIL}' not found.` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `e2e/resources/data.resource` + +**Reference Docs:** +- `Docs/Testing-Requirements.md` — Test variable scoping + +**Expected Behavior:** The `Ban An IP Via API` test should set the `${BANNED_JAIL}` variable so subsequent tests can reference it. + +--- + +## Task: 05 Jails — Unban All Endpoint Accepts Request + +**Test:** `Unban All Endpoint Accepts Request` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Unexpected unban-all status: 401` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/bans.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Unban-all endpoint should accept the request (200/204) when authenticated. + +--- + +## Task: 05 Jails — Active Bans Endpoint Returns List + +**Test:** `Active Bans Endpoint Returns List` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/bans.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Active bans endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 05 Jails — IP Lookup Endpoint Returns Geo + +**Test:** `IP Lookup Endpoint Returns Geo` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Unexpected lookup status: 401` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/geo.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Geo lookup endpoint should return geo data (200) when authenticated. + +--- + +## Task: 05 Jails — Ignore List Add And Remove Via API + +**Test:** `Ignore List Add And Remove Via API` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/jails Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Ignore list add/remove endpoints should work (200) when authenticated. + +--- + +## Task: 05 Jails — Ignore Self Toggle Via API + +**Test:** `Ignore Self Toggle Via API` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/jails Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Ignore-self toggle endpoint should return 200 when authenticated. + +--- + +## Task: 05 Jails — Jail Reload Endpoint Works + +**Test:** `Jail Reload Endpoint Works` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/jails Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Jail reload endpoint should return 200 when authenticated. + +--- + +## Task: 05 Jails — Jail Stop Endpoint Works + +**Test:** `Jail Stop Endpoint Works` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/jails Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Jail stop endpoint should return 200 when authenticated. + +--- + +## Task: 05 Jails — Jail Start Endpoint Works + +**Test:** `Jail Start Endpoint Works` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/jails Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Jail start endpoint should return 200 when authenticated. + +--- + +## Task: 05 Jails — Jail Idle Endpoint Works + +**Test:** `Jail Idle Endpoint Works` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/jails Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Jail idle endpoint should return 200 when authenticated. + +--- + +## Task: 05 Jails — Reload All Jails Endpoint Works + +**Test:** `Reload All Jails Endpoint Works` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Reload-all endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 05 Jails — Geo Stats Endpoint Returns Counters + +**Test:** `Geo Stats Endpoint Returns Counters` +**Suite:** `05_jails.robot` + +**Step That Fails:** API returns 401. + +**Error:** `401 != 200` + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `backend/app/routers/geo.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Geo stats endpoint should return 200 with counters when authenticated. + +--- + +## Task: 06 Config — Config Page Renders All Required Tabs + +**Test:** `Config Page Renders All Required Tabs` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** Page text 'Actions' not found. + +**Error:** `Page text 'Actions' not found in body` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `frontend/src/pages/ConfigPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Configuration view tabs + +**Expected Behavior:** Config page should display tabs for Jails, Filters, Actions, Server, and Regex Tester. + +--- + +## Task: 06 Config — Config Jails Tab Defaults To Active + +**Test:** `Config Jails Tab Defaults To Active` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** Page text 'Active' not found. + +**Error:** `Page text 'Active' not found in body` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `frontend/src/pages/ConfigPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Config tab defaults + +**Expected Behavior:** The Jails tab should show an "Active" label or section by default. + +--- + +## Task: 06 Config — Config Filters Tab Loads + +**Test:** `Config Filters Tab Loads` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** Page text 'Filter' not found. + +**Error:** `Page text 'Filter' not found in body` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `frontend/src/pages/ConfigPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` + +**Expected Behavior:** Clicking the Filters tab should show filter-related content with the text "Filter". + +--- + +## Task: 06 Config — Config Actions Tab Loads + +**Test:** `Config Actions Tab Loads` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** Page text 'Action' not found. + +**Error:** `Page text 'Action' not found in body` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `frontend/src/pages/ConfigPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` + +**Expected Behavior:** Clicking the Actions tab should show action-related content with the text "Action". + +--- + +## Task: 06 Config — Config Server Tab Loads + +**Test:** `Config Server Tab Loads` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** Page text 'Server' not found. + +**Error:** `Page text 'Server' not found in body` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `frontend/src/pages/ConfigPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` + +**Expected Behavior:** Clicking the Server tab should show server settings content with the text "Server". + +--- + +## Task: 06 Config — Config Regex Tester Tab Loads + +**Test:** `Config Regex Tester Tab Loads` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** Page text 'Regex' not found. + +**Error:** `Page text 'Regex' not found in body` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `frontend/src/pages/ConfigPage.tsx` + +**Reference Docs:** +- `Docs/Features.md` + +**Expected Behavior:** Clicking the Regex Tester tab should show regex testing UI with the text "Regex". + +--- + +## Task: 06 Config — Config Regex Tester API Endpoint Validates Pattern + +**Test:** `Config Regex Tester API Endpoint Validates Pattern` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 404. + +**Error:** `Unexpected regex test status: 404` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Regex tester endpoint should exist and validate patterns (return 200/400, not 404). + +--- + +## Task: 06 Config — Config Jails Endpoint Lists Jail Configs + +**Test:** `Config Jails Endpoint Lists Jail Configs` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Jail configs endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 06 Config — Config Filters Endpoint Lists Filter Configs + +**Test:** `Config Filters Endpoint Lists Filter Configs` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Filter configs endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 06 Config — Config Actions Endpoint Lists Action Configs + +**Test:** `Config Actions Endpoint Lists Action Configs` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Action configs endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 06 Config — Config Global Settings Endpoint + +**Test:** `Config Global Settings Endpoint` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Global settings endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 06 Config — Config Service Status Endpoint + +**Test:** `Config Service Status Endpoint` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Service status endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 06 Config — Config Security Headers Endpoint + +**Test:** `Config Security Headers Endpoint` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Security headers endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 06 Config — Config Inline Edit Round Trip For First Jail + +**Test:** `Config Inline Edit Round Trip For First Jail` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/jails Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` +- `backend/app/routers/jails.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Inline edit (PUT) for jail config should return 200 when authenticated. + +--- + +## Task: 06 Config — Config Raw Section Lazy Load + +**Test:** `Config Raw Section Lazy Load` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Unexpected raw filter status: 401` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Raw config endpoint should return 200 when authenticated. + +--- + +## Task: 06 Config — Config Raw Action File Endpoint + +**Test:** `Config Raw Action File Endpoint` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Unexpected raw action status: 401` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Raw action file endpoint should return 200 when authenticated. + +--- + +## Task: 06 Config — Config Jail Files Endpoint + +**Test:** `Config Jail Files Endpoint` +**Suite:** `06_config_jails_filters_actions.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/06_config_jails_filters_actions.robot` +- `backend/app/routers/config.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Jail files endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 07 Server Settings — Server Settings GET Returns Expected Keys + +**Test:** `Server Settings GET Returns Expected Keys` +**Suite:** `07_config_log_and_serversettings.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Url: http://localhost:8000/api/v1/server/settings Expected status: 401 != 200` + +**Files to Check:** +- `e2e/tests/07_config_log_and_serversettings.robot` +- `backend/app/routers/server.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** GET `/api/v1/server/settings` should return 200 with expected keys when authenticated. + +--- + +## Task: 07 Server Settings — Server Settings Update Log Level + +**Test:** `Server Settings Update Log Level` +**Suite:** `07_config_log_and_serversettings.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/07_config_log_and_serversettings.robot` +- `backend/app/routers/server.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** PUT to update log level should return 200 or 204 when authenticated. + +--- + +## Task: 07 Server Settings — Server Settings Update DB Purge Age + +**Test:** `Server Settings Update DB Purge Age` +**Suite:** `07_config_log_and_serversettings.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/07_config_log_and_serversettings.robot` +- `backend/app/routers/server.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** PUT to update DB purge age should return 200 or 204 when authenticated. + +--- + +## Task: 07 Server Settings — Server Settings Update Max Matches + +**Test:** `Server Settings Update Max Matches` +**Suite:** `07_config_log_and_serversettings.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/07_config_log_and_serversettings.robot` +- `backend/app/routers/server.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** PUT to update max matches should return 200 or 204 when authenticated. + +--- + +## Task: 07 Server Settings — Server Settings Accept Stdout Special Target + +**Test:** `Server Settings Accept Stdout Special Target` +**Suite:** `07_config_log_and_serversettings.robot` + +**Step That Fails:** STDOUT target rejected. + +**Error:** `STDOUT target rejected` + +**Files to Check:** +- `e2e/tests/07_config_log_and_serversettings.robot` +- `backend/app/routers/server.py` +- `backend/app/models/server_settings.py` + +**Reference Docs:** +- `Docs/Features.md` — Log target special values + +**Expected Behavior:** Setting log target to "STDOUT" should be accepted as a valid special target. + +--- + +## Task: 07 Server Settings — Server Settings Accept Syslog Special Target + +**Test:** `Server Settings Accept Syslog Special Target` +**Suite:** `07_config_log_and_serversettings.robot` + +**Step That Fails:** SYSLOG target rejected. + +**Error:** `SYSLOG target rejected` + +**Files to Check:** +- `e2e/tests/07_config_log_and_serversettings.robot` +- `backend/app/routers/server.py` +- `backend/app/models/server_settings.py` + +**Reference Docs:** +- `Docs/Features.md` — Log target special values + +**Expected Behavior:** Setting log target to "SYSLOG" should be accepted as a valid special target. + +--- + +## Task: 07 Server Settings — Server Settings Accept Safe File Path + +**Test:** `Server Settings Accept Safe File Path` +**Suite:** `07_config_log_and_serversettings.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/07_config_log_and_serversettings.robot` +- `backend/app/routers/server.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Setting a safe file path inside `/var/log` should be accepted (200/204) when authenticated. + +--- + +## Task: 07 Server Settings — Flush Logs Endpoint Works + +**Test:** `Flush Logs Endpoint Works` +**Suite:** `07_config_log_and_serversettings.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/07_config_log_and_serversettings.robot` +- `backend/app/routers/server.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Flush logs endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 08 History — History Page Shows Archive Source Badge By Default + +**Test:** `History Page Shows Archive Source Badge By Default` +**Suite:** `08_history.robot` + +**Step That Fails:** No source badge visible on history page. + +**Error:** `No source badge visible on history page` + +**Files to Check:** +- `e2e/tests/08_history.robot` +- `frontend/src/pages/HistoryPage.tsx` +- `frontend/src/components/DataSourceBadge.tsx` + +**Reference Docs:** +- `Docs/Features.md` — History page data source badges + +**Expected Behavior:** The history page should display an "Archive" source badge by default. + +--- + +## Task: 08 History — History Endpoint Returns Paginated Data + +**Test:** `History Endpoint Returns Paginated Data` +**Suite:** `08_history.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/08_history.robot` +- `backend/app/routers/history.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** History endpoint should return 200 or 204 with paginated data when authenticated. + +--- + +## Task: 08 History — History Archive Endpoint Returns Data + +**Test:** `History Archive Endpoint Returns Data` +**Suite:** `08_history.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/08_history.robot` +- `backend/app/routers/history.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Archive endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 08 History — History Per IP Endpoint Returns Data + +**Test:** `History Per IP Endpoint Returns Data` +**Suite:** `08_history.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/08_history.robot` +- `backend/app/routers/history.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Per-IP history endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 08 History — History Filter By Jail Returns Data + +**Test:** `History Filter By Jail Returns Data` +**Suite:** `08_history.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/08_history.robot` +- `backend/app/routers/history.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Jail-filtered history endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 08 History — History Filter By Source Fail2ban + +**Test:** `History Filter By Source Fail2ban` +**Suite:** `08_history.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/08_history.robot` +- `backend/app/routers/history.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** fail2ban-source filter endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 08 History — History Filter By Source Archive + +**Test:** `History Filter By Source Archive` +**Suite:** `08_history.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/08_history.robot` +- `backend/app/routers/history.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Archive-source filter endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 09 Blocklists — Blocklists Sources List Endpoint + +**Test:** `Blocklists Sources List Endpoint` +**Suite:** `09_blocklists.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/09_blocklists.robot` +- `backend/app/routers/blocklists.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Blocklist sources list endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 09 Blocklists — Blocklist Source Create Rejects Invalid Scheme + +**Test:** `Blocklist Source Create Rejects Invalid Scheme` +**Suite:** `09_blocklists.robot` + +**Step That Fails:** Invalid scheme was accepted (401 instead of 400). + +**Error:** `Invalid scheme was accepted: 401 != 400` + +**Files to Check:** +- `e2e/tests/09_blocklists.robot` +- `backend/app/routers/blocklists.py` +- `backend/app/services/blocklist_service.py` + +**Reference Docs:** +- `Docs/Features.md` — Blocklist URL validation +- `Docs/Security.md` — SSRF prevention + +**Expected Behavior:** Creating a blocklist with an invalid scheme (ftp://, file://, etc.) should return 400 Bad Request. The 401 suggests the request never reached validation due to auth failure. + +--- + +## Task: 09 Blocklists — Blocklist Source Create Rejects Loopback URL + +**Test:** `Blocklist Source Create Rejects Loopback URL` +**Suite:** `09_blocklists.robot` + +**Step That Fails:** Loopback URL accepted (401 instead of 400). + +**Error:** `Loopback URL accepted: 401 != 400` + +**Files to Check:** +- `e2e/tests/09_blocklists.robot` +- `backend/app/routers/blocklists.py` +- `backend/app/services/blocklist_service.py` + +**Reference Docs:** +- `Docs/Features.md` — Blocklist URL validation +- `Docs/Security.md` — SSRF prevention + +**Expected Behavior:** Loopback URLs (127.0.0.1, localhost) should be rejected with 400. The 401 indicates auth failure before validation. + +--- + +## Task: 09 Blocklists — Blocklist Source Create Rejects Private IP URL + +**Test:** `Blocklist Source Create Rejects Private IP URL` +**Suite:** `09_blocklists.robot` + +**Step That Fails:** Private IP URL accepted (401 instead of 400). + +**Error:** `Private IP URL accepted: 401 != 400` + +**Files to Check:** +- `e2e/tests/09_blocklists.robot` +- `backend/app/routers/blocklists.py` +- `backend/app/services/blocklist_service.py` + +**Reference Docs:** +- `Docs/Features.md` — Blocklist URL validation +- `Docs/Security.md` — SSRF prevention + +**Expected Behavior:** Private IP URLs (10.x, 172.16-31.x, 192.168.x) should be rejected with 400. The 401 indicates auth failure before validation. + +--- + +## Task: 09 Blocklists — Blocklist Source Create Rejects Link Local URL + +**Test:** `Blocklist Source Create Rejects Link Local URL` +**Suite:** `09_blocklists.robot` + +**Step That Fails:** Link-local URL accepted (401 instead of 400). + +**Error:** `Link-local URL accepted: 401 != 400` + +**Files to Check:** +- `e2e/tests/09_blocklists.robot` +- `backend/app/routers/blocklists.py` +- `backend/app/services/blocklist_service.py` + +**Reference Docs:** +- `Docs/Features.md` — Blocklist URL validation +- `Docs/Security.md` — SSRF prevention + +**Expected Behavior:** Link-local URLs (169.254.x) should be rejected with 400. The 401 indicates auth failure before validation. + +--- + +## Task: 09 Blocklists — Blocklist Schedule Endpoint Returns Config + +**Test:** `Blocklist Schedule Endpoint Returns Config` +**Suite:** `09_blocklists.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/09_blocklists.robot` +- `backend/app/routers/blocklists.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Schedule endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 09 Blocklists — Blocklist Schedule Update Works + +**Test:** `Blocklist Schedule Update Works` +**Suite:** `09_blocklists.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/09_blocklists.robot` +- `backend/app/routers/blocklists.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Schedule update endpoint should return 200 or 204 when authenticated. + +--- + +## Task: 09 Blocklists — Blocklist Manual Import Endpoint Reachable + +**Test:** `Blocklist Manual Import Endpoint Reachable` +**Suite:** `09_blocklists.robot` + +**Step That Fails:** API returns 401. + +**Error:** `Unexpected import status: 401` + +**Files to Check:** +- `e2e/tests/09_blocklists.robot` +- `backend/app/routers/blocklists.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Manual import endpoint should return 200 when authenticated. + +--- + +## Task: 09 Blocklists — Blocklist Import Log Endpoint Returns Paginated Data + +**Test:** `Blocklist Import Log Endpoint Returns Paginated Data` +**Suite:** `09_blocklists.robot` + +**Step That Fails:** API returns 401. + +**Error:** `'401 in [200, 204]' should be true.` + +**Files to Check:** +- `e2e/tests/09_blocklists.robot` +- `backend/app/routers/blocklists.py` + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** Import log endpoint should return 200 or 204 with paginated data when authenticated. + +--- + +## Task: 09 Blocklists — Blocklist Delete Non Existent Returns 404 + +**Test:** `Blocklist Delete Non Existent Returns 404` +**Suite:** `09_blocklists.robot` + +**Step That Fails:** API returns 401 instead of 404. + +**Error:** `401 != 404` + +**Files to Check:** +- `e2e/tests/09_blocklists.robot` +- `backend/app/routers/blocklists.py` + +**Reference Docs:** +- `Docs/API-Reference.md` +- `Docs/API_STATUS_CODES.md` + +**Expected Behavior:** Deleting a non-existent blocklist should return 404 Not Found. The 401 indicates the request is not reaching the handler due to auth failure. + +--- + +## Meta Task: Fix Authentication in E2E Tests + +**Affected Tests:** ~40+ API tests across suites 03, 05, 06, 07, 08, 09 + +**Root Cause Pattern:** Most API tests return `401 Unauthorized`, indicating the test authentication/session setup is not working correctly. + +**Files to Check:** +- `e2e/resources/auth.resource` — `Login As Admin`, `Login Via HTTP` +- `e2e/resources/api.resource` — CSRF and cookie handling +- `e2e/resources/common.resource` — `Wait For Backend Health`, XFF headers +- `backend/app/routers/auth.py` — Login endpoint +- `backend/app/middleware/session.py` — Session validation + +**Reference Docs:** +- `e2e/Instructions.md` — Rate-limit workaround with XFF headers +- `Docs/Security.md` — Session handling +- `Docs/API_STATUS_CODES.md` + +**Expected Behavior:** +- `Login As Admin` keyword should successfully authenticate and persist session cookies. +- `Api Get/Post/Put/Delete` wrappers should inject the session cookie and CSRF token. +- Tests using `X-Forwarded-For` headers should bypass rate limits while maintaining auth. + +**Investigation Steps:** +1. Verify `Login As Admin` returns 200 and sets session cookie. +2. Check that subsequent API calls include the session cookie. +3. Verify CSRF token is extracted from login response and included in state-changing requests. +4. Check if `X-Forwarded-For` rotation is interfering with session stickiness. + +--- + +## Meta Task: Install Playwright Browsers for UI Tests + +**Affected Tests:** 6 tests in `02_login.robot` (browser launch failures) + +**Root Cause:** Playwright Chromium browser binary is not installed. + +**Error:** `browserType.launch: Executable doesn't exist at .../chromium_headless_shell` + +**Fix:** +```bash +cd /home/lukas/Volume/repo/BanGUI/e2e +npx playwright install chromium +# or +rfbrowser init +``` + +**Reference Docs:** +- `e2e/Instructions.md` — Setup section + +--- + +## Meta Task: Fix Setup Page Validation Alert Selectors + +**Affected Tests:** 4 tests in `01_setup_and_auth.robot` + +**Root Cause:** XPath selector `//*[@aria-label="..."]/ancestor::*[contains(@class,"field")]//*[@role="alert"]` times out waiting for validation alerts. + +**Possible Causes:** +1. Alerts are rendered outside the expected DOM hierarchy. +2. Alert role is not applied to error messages. +3. Validation is async and takes longer than 10 seconds. +4. The `field` CSS class is not present on the container. + +**Files to Check:** +- `frontend/src/pages/SetupPage.tsx` — Alert rendering and CSS classes +- `e2e/tests/01_setup_and_auth.robot` — XPath selectors + +**Reference Docs:** +- `Docs/Features.md` — Setup wizard validation +- `Docs/Testing-Requirements.md` — Accessibility requirements + +**Expected Behavior:** Form validation errors should be visible within 10 seconds and match the XPath selector structure. + +--- + +## Meta Task: Fix Dashboard and Map Data Source Badges + +**Affected Tests:** +- `03_dashboard.robot`: 24h, 7d presets +- `04_map.robot`: 24h, 7d presets + +**Root Cause:** Data-source badges ("Live" / "Archive") are not visible after selecting time-range presets. + +**Files to Check:** +- `frontend/src/pages/DashboardPage.tsx` +- `frontend/src/pages/MapPage.tsx` +- `frontend/src/components/DataSourceBadge.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Data source badges + +**Expected Behavior:** Time-range preset buttons should trigger a badge update showing the appropriate data source. + +--- + +## Meta Task: Fix Config Page Tab Content Visibility + +**Affected Tests:** 5 tests in `06_config_jails_filters_actions.robot` + +**Root Cause:** Tab content text (Actions, Active, Filter, Action, Server, Regex) is not found in the page body. + +**Files to Check:** +- `frontend/src/pages/ConfigPage.tsx` +- `frontend/src/components/Tabs.tsx` or tab component + +**Reference Docs:** +- `Docs/Features.md` — Configuration view tabs + +**Expected Behavior:** Each tab should render content with identifiable text matching the tab name. + +--- + +## Meta Task: Fix Server Settings Special Target Acceptance + +**Affected Tests:** 2 tests in `07_config_log_and_serversettings.robot` + +**Root Cause:** "STDOUT" and "SYSLOG" special log targets are rejected. + +**Files to Check:** +- `backend/app/routers/server.py` +- `backend/app/models/server_settings.py` +- `backend/app/schemas/server_settings.py` + +**Reference Docs:** +- `Docs/Features.md` — Log target configuration + +**Expected Behavior:** The server settings validator should accept "STDOUT" and "SYSLOG" as valid special log targets. + +--- + +## Meta Task: Fix History Page Source Badge + +**Affected Tests:** 1 test in `08_history.robot` + +**Root Cause:** Archive source badge not visible on history page by default. + +**Files to Check:** +- `frontend/src/pages/HistoryPage.tsx` +- `frontend/src/components/DataSourceBadge.tsx` + +**Reference Docs:** +- `Docs/Features.md` — History page defaults + +**Expected Behavior:** History page should show an "Archive" source badge on initial load. + +--- + +## Meta Task: Fix Ban Records Pipeline + +**Affected Tests:** 1 test in `02_ban_records.robot` + +**Root Cause:** Simulated failed logins do not produce ban records containing the expected IP. + +**Files to Check:** +- `e2e/tests/02_ban_records.robot` +- `e2e/proxy_server.py` +- `backend/app/services/ban_service.py` +- `backend/app/tasks/ban_sync.py` or equivalent +- `Docker/simulate_failed_logins.sh` + +**Reference Docs:** +- `Docs/Features.md` — Ban record pipeline +- `Docs/Architekture.md` — Data flow + +**Expected Behavior:** After simulating failed logins, the ban record should appear in the system with the test IP address. + +--- + +## Meta Task: Fix Config Regex Tester Endpoint + +**Affected Tests:** 1 test in `06_config_jails_filters_actions.robot` + +**Root Cause:** Regex tester API endpoint returns 404. + +**Files to Check:** +- `backend/app/routers/config.py` +- `backend/app/main.py` — Router registration + +**Reference Docs:** +- `Docs/API-Reference.md` + +**Expected Behavior:** The regex tester endpoint should be registered and return 200 for valid patterns, 400 for invalid ones. + +--- + +## Meta Task: Fix Jail Detail Page Variable Scope + +**Affected Tests:** 1 test in `05_jails.robot` + +**Root Cause:** `${BANNED_JAIL}` variable is not set or not accessible across test cases. + +**Files to Check:** +- `e2e/tests/05_jails.robot` +- `e2e/resources/data.resource` + +**Reference Docs:** +- `Docs/Testing-Requirements.md` — Test variable scoping + +**Expected Behavior:** Variables set in one test case should be available in subsequent test cases within the same suite, or use suite-level setup/teardown variables. + +--- + +## Meta Task: Fix Login Redirect Behavior + +**Affected Tests:** 2 tests in `02_login.robot` + +**Root Cause:** +1. After logout, protected pages redirect to `/` instead of `/login`. +2. `next=` parameter is not preserved in login URL after redirect from protected page. + +**Files to Check:** +- `frontend/src/router.tsx` +- `frontend/src/pages/LoginPage.tsx` +- `frontend/src/App.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Authentication flow + +**Expected Behavior:** +- Unauthenticated access to protected routes should redirect to `/login`. +- The original requested URL should be preserved in a `next=` query parameter. + +--- + +## Meta Task: Fix Dashboard Ban List Column Headers + +**Affected Tests:** 1 test in `03_dashboard.robot` + +**Root Cause:** The text "IP" is not found in the dashboard ban list. + +**Files to Check:** +- `frontend/src/pages/DashboardPage.tsx` +- `frontend/src/components/BanList.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Dashboard columns + +**Expected Behavior:** The ban list table should have a visible column header containing the text "IP". + +--- + +## Meta Task: Fix Map Zoom Controls + +**Affected Tests:** 1 test in `04_map.robot` + +**Root Cause:** Zoom controls are not found on the map page. + +**Files to Check:** +- `frontend/src/pages/MapPage.tsx` +- `frontend/src/components/WorldMap.tsx` + +**Reference Docs:** +- `Docs/Features.md` — Map controls + +**Expected Behavior:** The map should have visible zoom in, zoom out, and reset buttons. + +--- + +## Meta Task: Fix Logout API Response + +**Affected Tests:** 1 test in `02_login.robot` + +**Root Cause:** Logout endpoint returns 401 instead of 200. + +**Files to Check:** +- `backend/app/routers/auth.py` +- `backend/app/services/session_service.py` + +**Reference Docs:** +- `Docs/API-Reference.md` +- `Docs/API_STATUS_CODES.md` + +**Expected Behavior:** The logout endpoint should return 200 OK even if the session is already expired, or at minimum not return 401 for a valid logout request. + +--- + +## Meta Task: Fix Login Rate Limit Test + +**Affected Tests:** 1 test in `02_login.robot` + +**Root Cause:** Rate limit is not triggered after multiple failed logins. + +**Files to Check:** +- `e2e/tests/02_login.robot` +- `backend/app/routers/auth.py` +- `backend/app/middleware/rate_limit.py` + +**Reference Docs:** +- `Docs/Features.md` — Rate limiting +- `Docs/Security.md` + +**Expected Behavior:** After 5 failed login attempts from the same IP within 60 seconds, the 6th attempt should return HTTP 429. + +--- + +## Meta Task: Fix Config Edit Test Prerequisites + +**Affected Tests:** 1 skipped test in `04_config_edit.robot` + +**Root Cause:** Test requires at least one active jail but none are active. + +**Files to Check:** +- `e2e/tests/04_config_edit.robot` +- `Docker/simulate_failed_logins.sh` +- `backend/app/services/jail_service.py` + +**Reference Docs:** +- `Docs/Features.md` — Jail activation + +**Expected Behavior:** Either ensure a jail is active before running the test, or adjust the test to handle the empty-jail scenario. + +--- + +*End of tasks. Total: 84 failing tests documented across 13 test suites, plus 13 meta-tasks grouping common root causes.* diff --git a/Docs/runner.csx b/Docs/runner.csx index b4a6706..cdb5ba5 100644 --- a/Docs/runner.csx +++ b/Docs/runner.csx @@ -102,7 +102,7 @@ for (int i = 0; i < items.Count; i++) // Step 1 — run the task prompt await RunCopilot(Enumerable.Empty(), $"/caveman full"); - await RunCopilot(new[] { "--continue" }, $"read ./Docs/Instructions.md. fix the following test and only that one. Keep in mind that i did many refactorings and test may is obsolet or need to be changed. {item}"); + await RunCopilot(new[] { "--continue" }, $"read ./Docs/Instructions.md. fix the following test and only that one. {item}"); if (cts.IsCancellationRequested) break; // Step 2 — confirm completion in the same chat session diff --git a/e2e/tests/01_setup_and_auth.robot b/e2e/tests/01_setup_and_auth.robot index 7c3358d..d43a0be 100644 --- a/e2e/tests/01_setup_and_auth.robot +++ b/e2e/tests/01_setup_and_auth.robot @@ -65,8 +65,8 @@ Password Mismatch Shows Validation Error Fill Text css=input[aria-label="Confirm Password"] Different123! Click css=button[type="submit"] - Wait For Elements State css=[aria-label="Confirm Password"] attached timeout=5s - ${msg}= Get Text xpath=//*[@aria-label="Confirm Password"]/ancestor::*[contains(@class,"field")]//*[@role="alert"] + Wait For Elements State xpath=//*[@aria-label="Confirm Password"]/ancestor::*[contains(@class,"field")]//*[@role="alert"] visible timeout=10s + ${msg}= Get Text xpath=//*[@aria-label="Confirm Password"]/ancestor::*[contains(@class,"field")]//*[@role="alert"] timeout=10s Should Be Equal As Strings ${msg} Passwords do not match. Close Browser