Files
pic/tests/e2e/ui/test_peer_acl.py
roof 7d2979b8af fix: integration and E2E test correctness after auth enforcement
config_manager: make per-file copy errors non-fatal during restore
  (resolves test failures when /app/config/* is not writable by test runner)
test_live_api.py: fix NameError (_req.Session not requests.Session)
test_negative_scenarios.py: replace raw requests.* with authenticated _S.*
  (all endpoints now require auth; unauthenticated calls return 401)
wg/conftest.py: fix wg_server_info — public key is at /api/wireguard/keys
test_admin_navigation.py, test_peer_acl.py: add .first to ambiguous locators
  to avoid Playwright strict-mode errors when desktop+mobile nav both mount

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 18:14:38 -04:00

116 lines
3.7 KiB
Python

"""
Peer access-control tests (scenarios 14 & 15).
PrivateRoute.jsx (confirmed):
- Unauthenticated users → <Navigate to="/login" />
- Authenticated user with wrong role → <Navigate to="/" />
A peer (role='peer') visiting an admin-only route must be redirected to '/'.
A peer must NOT see admin sidebar links (Peers, Settings, WireGuard, etc.).
"""
import pytest
pytestmark = pytest.mark.ui
# All routes that require role='admin' (from App.jsx Routes).
ADMIN_ONLY_ROUTES = [
'/peers',
'/network',
'/wireguard',
'/email',
'/calendar',
'/files',
'/routing',
'/vault',
'/containers',
'/cell-network',
'/logs',
'/settings',
]
# Admin-only sidebar link names (from App.jsx adminNavigation).
ADMIN_ONLY_NAV_LINKS = [
'Peers',
'Network Services',
'WireGuard',
'Email',
'Calendar',
'Files',
'Routing',
'Vault',
'Containers',
'Cell Network',
'Logs',
'Settings',
]
# ── Scenario 14: peer redirected from admin routes ───────────────────────────
@pytest.mark.parametrize('admin_route', ADMIN_ONLY_ROUTES)
def test_peer_redirected_from_admin_route(peer_page, webui_base, admin_route):
"""
A peer navigating to an admin-only route must NOT land on that route.
PrivateRoute redirects them to '/' instead.
"""
page, _ = peer_page
page.goto(f"{webui_base}{admin_route}")
page.wait_for_load_state('networkidle')
current_path = page.url.replace(webui_base, '')
assert current_path.rstrip('/') not in [admin_route.rstrip('/')], (
f"Peer was allowed to reach admin-only route '{admin_route}'. "
f"Expected redirect to '/'. Got: {page.url}"
)
# Must not have been sent to /login either — peer IS authenticated.
assert '/login' not in page.url, (
f"Peer was unexpectedly redirected to /login from '{admin_route}'. "
"PrivateRoute should redirect role-mismatches to '/', not /login."
)
# ── Scenario 15: peer sidebar lacks admin links ──────────────────────────────
def test_peer_nav_does_not_show_admin_only_links(peer_page, webui_base):
"""
The peer sidebar (peerNavigation in App.jsx) only contains Dashboard,
My Services, and Account. Admin-only links must be absent.
"""
page, _ = peer_page
# Navigate to root so the sidebar is fully rendered.
page.goto(f"{webui_base}/")
page.wait_for_load_state('networkidle')
for link_name in ADMIN_ONLY_NAV_LINKS:
assert not page.get_by_role('link', name=link_name).first.is_visible(), (
f"Admin-only sidebar link '{link_name}' should NOT be visible to a peer"
)
def test_peer_nav_shows_allowed_links(peer_page, webui_base):
"""
The peer sidebar must contain exactly the three peer navigation items:
Dashboard, My Services, Account.
"""
page, _ = peer_page
page.goto(f"{webui_base}/")
page.wait_for_load_state('networkidle')
# Use .first to avoid strict-mode errors when desktop + mobile nav are both mounted.
for link_name in ('Dashboard', 'My Services', 'Account'):
assert page.get_by_role('link', name=link_name).first.is_visible(), (
f"Peer sidebar should show link '{link_name}'"
)
def test_peer_my_services_is_accessible(peer_page, webui_base):
"""
/my-services is restricted to role='peer' (requireRole="peer" in App.jsx).
A logged-in peer must be able to reach it.
"""
page, _ = peer_page
page.goto(f"{webui_base}/my-services")
page.wait_for_load_state('networkidle')
assert '/login' not in page.url
assert '/my-services' in page.url