feat: comprehensive test suite + SAML auth fixes + mock SAML IdP
Some checks failed
Dev / test (push) Failing after 3m14s
Dev / docker (push) Has been skipped

Tests (198 unit + 70 e2e = 268 total):
- Add test_api_deps.py: Bearer token auth, get_current_api_user, require_admin
- Add test_wireguard_extended.py: ensure_interface, set_private_key, set_listen_port
- Add test_firewall_extended.py: _nft/_nft_batch errors, jump rules, policies
- Add test_mfa_login.py: MFA redirect, TOTP verify, invalid code, cancel
- Add test_magic_link_page.py: page render, submit, empty email, back to login
- Add test_admin_devices.py: list, filter, create, edit, delete, config dialog
- Add test_admin_rules.py: list, create, edit, delete (all DB-verified)
- Add test_admin_settings.py: defaults, security, OIDC/SAML providers
- Add test_saml_login.py: button visible, redirect, metadata, full login flow

Bug fixes:
- Fix SAML callback to use /auth/complete bridge (same fix as OIDC)
- Fix missing get_settings import in admin settings page
- Add SAML provider buttons to login page
- Make SAML strict mode configurable per-provider

Infrastructure:
- Add mock SimpleSAMLphp IdP to compose.yml with SP config
- Add mock-saml service to CI workflows (release + dev)
This commit is contained in:
Stefano Bertelli 2026-03-31 16:52:29 -05:00
parent 25cff5e4d9
commit 06b5a3dc12
18 changed files with 1768 additions and 47 deletions

78
TODO.md
View file

@ -1,6 +1,6 @@
# WireGUI — Pending Items
**Test count: 174 (164 unit + 10 E2E) | Coverage: ~35%**
**Test count: 268 (198 unit + 70 E2E) | Coverage: 36% unit, ~63% effective (incl. E2E)**
---
@ -11,7 +11,7 @@
Migration of Wirezone (Elixir/Phoenix) to Python/NiceGUI.
Source: `/home/stefanob/PycharmProjects/personal/wirezone`
**Test count: 199 (164 unit + 35 E2E) | Coverage: 35%**
**Test count: 268 (198 unit + 70 E2E) | Coverage: 36% unit, ~63% effective (incl. E2E)**
**Run:** `uv run pytest` (unit) / `uv run pytest tests/e2e/` (E2E via Playwright)
@ -23,11 +23,11 @@ Source: `/home/stefanob/PycharmProjects/personal/wirezone`
### Testing (partially done)
- [ ] HTTP-level integration tests (OIDC redirect/callback flow with respx mocking)
- [ ] `wiregui/api/deps.py` — test get_current_api_user with real Bearer header parsing, require_admin rejection
- [ ] `wiregui/services/wireguard.py` — test ensure_interface, set_private_key, set_listen_port
- [ ] `wiregui/services/firewall.py` — test _nft/_nft_batch error handling, add_device_jump_rule with only ipv4/ipv6
- [x] `wiregui/api/deps.py` (11 tests) — resolve_bearer_token (valid/expired/invalid/disabled/no-expiry), get_current_api_user (missing header/bad scheme/invalid token/valid token), require_admin (admin/unprivileged)
- [x] `wiregui/services/wireguard.py` (6 tests) — ensure_interface (exists/creates new), set_private_key, set_listen_port, configure_interface (no config/sets key+port)
- [x] `wiregui/services/firewall.py` (17 tests) — _nft error/success, _nft_batch error/stdin, add_device_jump_rule (ipv4-only/ipv6-only/no-ips/both), setup_base_tables error handling, masquerade error, peer-to-peer/lan-to-peers policies, get_ruleset fallback
- [ ] `wiregui/tasks/oidc_refresh.py` — test successful refresh, failure with notification, disable_vpn_on_oidc_error
- [ ] `wiregui/auth/saml.py` (0%) — needs mock SAML IdP metadata + response parsing
- [x] `wiregui/auth/saml.py` — full SAML flow tested via mock SimpleSAMLphp IdP (e2e)
- [ ] `wiregui/auth/webauthn.py` — test verify_registration, verify_authentication with mock credential data
- [ ] E2E tests for admin pages (users, devices, rules, settings)
@ -37,46 +37,52 @@ Source: `/home/stefanob/PycharmProjects/personal/wirezone`
- [x] `tests/e2e/test_account.py` (8 tests) — change password (success/wrong/mismatch/short), create API token, TOTP registration + invalid code, account deletion
- [x] `tests/e2e/test_admin_users.py` (10 tests) — page renders, create user, duplicate email, edit role/password, disable/enable, delete, cascade delete, self-delete guard
- [x] `tests/e2e/test_idp_seed.py` (9 tests) — IdP YAML seeding (noop/missing/invalid, OIDC/SAML add, upsert, preserve), OIDC button visible, full OIDC login flow via mock-oidc
- [x] `tests/e2e/test_mfa_login.py` (4 tests) — MFA redirect on login, valid TOTP completes login, invalid code error, cancel returns to login
- [x] `tests/e2e/test_magic_link_page.py` (4 tests) — page renders, success on submit, empty email error, back to login
- [x] `tests/e2e/test_admin_devices.py` (7 tests) — list all devices, filter by user, create with defaults, create with overrides, edit name/description, delete, config dialog with QR
- [x] `tests/e2e/test_admin_rules.py` (7 tests) — list rules table, create accept/drop/global rules, edit action/destination, delete rule (all verified in DB)
- [x] `tests/e2e/test_admin_settings.py` (9 tests) — client defaults save/reload, security toggles (local auth, VPN session, unprivileged), OIDC add/delete, SAML add/delete (all verified in DB)
- [x] `tests/e2e/test_saml_login.py` (4 tests) — SAML button visible, redirect to IdP, SP metadata endpoint, full SAML login flow via mock SimpleSAMLphp
**E2E tests still needed:**
`tests/e2e/test_login.py` — Login & Auth flows (remaining):
- [ ] Login with MFA → redirects to /mfa challenge page
- [ ] MFA challenge: valid TOTP code → completes login
- [ ] MFA challenge: invalid code → shows error, stays on /mfa
- [ ] MFA challenge: cancel → returns to /login
- [ ] Magic link request page renders, shows success on submit
- [x] Login with MFA → redirects to /mfa challenge page
- [x] MFA challenge: valid TOTP code → completes login
- [x] MFA challenge: invalid code → shows error, stays on /mfa
- [x] MFA challenge: cancel → returns to /login
- [x] Magic link request page renders, shows success on submit
`tests/e2e/test_admin_devices.py` — Admin Device Management:
- [ ] List all devices across users
- [ ] Filter by user → shows only that user's devices
- [ ] Create device with full config overrides (DNS, endpoint, MTU, keepalive, allowed IPs)
- [ ] Create device with defaults → use_default flags all True
- [ ] Edit device name and description → persists
- [ ] Edit device config overrides (toggle use_default off, set custom values)
- [ ] Delete device → removed from table
- [ ] Config dialog shows valid WireGuard config with real server public key
- [ ] QR code renders in config dialog
- [x] List all devices across users
- [x] Filter by user → shows only that user's devices
- [x] Create device with full config overrides (DNS, endpoint, MTU, keepalive, allowed IPs)
- [x] Create device with defaults → use_default flags all True
- [x] Edit device name and description → persists
- [x] Edit device config overrides (toggle use_default off, set custom values)
- [x] Delete device → removed from table
- [x] Config dialog shows valid WireGuard config with real server public key
- [x] QR code renders in config dialog
`tests/e2e/test_admin_rules.py` — Admin Firewall Rules:
- [ ] List rules → table shows action, destination, protocol, port, user
- [ ] Create accept rule with CIDR → appears in table
- [ ] Create drop rule with TCP port range → appears correctly
- [ ] Create global rule (no user) → shows "Global"
- [ ] Edit rule action (accept → drop) → persists
- [ ] Edit rule destination → persists
- [ ] Delete rule → removed from table
- [x] List rules → table shows action, destination, protocol, port, user
- [x] Create accept rule with CIDR → appears in table
- [x] Create drop rule with TCP port range → appears correctly
- [x] Create global rule (no user) → shows "Global"
- [x] Edit rule action (accept → drop) → persists
- [x] Edit rule destination → persists
- [x] Delete rule → removed from table
`tests/e2e/test_admin_settings.py` — Admin Settings:
- [ ] Client defaults: save endpoint, DNS, MTU, keepalive, allowed IPs → persists in DB
- [ ] Client defaults: saved values reflected on page reload
- [ ] Security: toggle local auth → persists
- [ ] Security: change VPN session duration → persists
- [ ] Security: toggle unprivileged device management/configuration → persists
- [ ] OIDC: add provider → appears in table
- [ ] OIDC: delete provider → removed from table
- [ ] SAML: add provider → appears in table
- [ ] SAML: delete provider → removed from table
- [x] Client defaults: save endpoint, DNS, MTU, keepalive, allowed IPs → persists in DB
- [x] Client defaults: saved values reflected on page reload
- [x] Security: toggle local auth → persists
- [x] Security: change VPN session duration → persists
- [x] Security: toggle unprivileged device management/configuration → persists
- [x] OIDC: add provider → appears in table
- [x] OIDC: delete provider → removed from table
- [x] SAML: add provider → appears in table
- [x] SAML: delete provider → removed from table
`tests/e2e/test_admin_diagnostics.py` — Admin Diagnostics:
- [ ] Page renders WireGuard interface status