From cc9d3220c9ac5273a1499a07441817835f6df06d Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 8 May 2026 08:11:08 +0200 Subject: [PATCH] docs(e2e): add debugging notes and fix incorrect login example Document lessons learned from debugging blocklist import tests: - RequestsLibrary vs Browser library auth isolation - CSRF header requirement - Robot variable type rules - network_mode: host implications - SSRF protection behavior - API response key discrepancies Also fix API login example: backend accepts plaintext passwords, not SHA256-hashed as previously documented. Co-Authored-By: Claude Opus 4.7 --- e2e/Instructions.md | 69 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/e2e/Instructions.md b/e2e/Instructions.md index b4406f4..a90c7fc 100644 --- a/e2e/Instructions.md +++ b/e2e/Instructions.md @@ -257,18 +257,71 @@ Backend: `http://127.0.0.1:8000` · Frontend (Vite proxy): `http://127.0.0.1:517 ### API login (dev) -The frontend SHA256-hashes the password before sending it to the API. -The initial setup password must be at least 8 characters long and include one uppercase letter, one number, and one special character from `!@#$%^&*()`. +The backend accepts **plaintext** passwords (no frontend hashing). The session cookie is named `bangui_session`. ```bash # Dev master password: Hallo123! -HASHED=$(echo -n "Hallo123!" | sha256sum | awk '{print $1}') TOKEN=$(curl -s -X POST http://127.0.0.1:8000/api/v1/auth/login \ -H 'Content-Type: application/json' \ - -d "{\"password\":\"$HASHED\"}" \ - | python3 -c 'import sys,json; print(json.load(sys.stdin)["token"])') - -# Use token in subsequent requests: -curl -H "Cookie: bangui_session=$TOKEN" http://127.0.0.1:8000/api/v1/dashboard/status + -d '{"password":"Hallo123!"}' \ + | python3 -c 'import sys,json; print(json.load(sys.stdin)["expires_at"])') +# Login sets bangui_session cookie automatically. +# Use the cookie in subsequent requests: +curl -b "bangui_session=$(cat ~/.bangui_session)" http://127.0.0.1:8000/api/v1/dashboard/status ``` + +--- + +## E2E Testing Notes + +Debugging failures: open `results/log.html` (not output.xml) for full request/response traces. + +### Auth (RequestsLibrary vs Browser) + +`Login As Admin` uses browser JavaScript (`Evaluate JavaScript`) — session cookie lives in the **browser context only**. +Any `RequestsLibrary` keyword (GET/POST to API) in the same test needs its own auth session. +Use `Login Via HTTP` from `auth.resource` to get a session cookie for RequestsLibrary calls. +RequestsLibrary and Browser library share no state. + +### CSRF Protection + +Backend enforces CSRF on all POST/PUT/DELETE via `X-BanGUI-Request: 1` header. +RequestsLibrary sessions must include this header on creation: +``` +Create Session bangsess ${BACKEND_URL} headers=${headers} # headers = {X-BanGUI-Request: 1} +``` +Then all requests on that session inherit it. + +### Robot Variable Type Rules + +Bare values in `Create Dictionary` are **strings**, not Python types: +- `enabled=true` → `"true"` (string) — backend Pydantic expects boolean → validation fails +- Fix: `enabled=${TRUE}` for booleans, `${60}` for integers +- `${NONE}` is Robot's null/None equivalent +- `${len(sources)}` is invalid — use `Get Length ${sources}` keyword instead + +### Network Mode (podman-compose) + +With `network_mode: host`, containers share the host network namespace. +- Backend can reach host's `127.0.0.1:PORT` — needed for mock HTTP servers +- Frontend must set `VITE_BACKEND_URL=http://localhost:8000` since `localhost` now resolves to host +- Vite proxy works when frontend also uses `network_mode: host` (same namespace) + +### SSRF Protection + +Blocklist source URLs are validated: hostname must resolve to a **public** IP. +- `127.0.0.1` and other loopback addresses are rejected +- In dev mode (`BANGUI_LOG_LEVEL=debug`), loopback is allowed for e2e testing +- For real e2e tests, use a public blocklist URL or ensure mock server is reachable + +### API Response Keys + +Always verify response shape in `results/log.html` — field names differ from expectations: +- Blocklist import log: `items` not `entries` +- Error responses: `{"code": "...", "detail": "..."}` + +### Process Library Teardown + +`Terminate Process` fails if the process alias doesn't exist (mock server not started). +Wrap in `Run Keyword And Return Status` to avoid teardown cascading failures.