fix(auth): expose /api/v1/system/appliance through the auth middleware allowlist

The /system/appliance endpoint is fetched by the SPA's i18n bootstrap on
  mount to seed locale, hostname, timezone, and the chrony NTP-gate state
  BEFORE any login state exists. The route handler itself has no auth
  dependency and the test_route_auth_coverage allowlist correctly marks it
  public, but the global auth_middleware in main.py — which short-circuits
  every /api/ path not in PUBLIC_API_ROUTES — was never told about it.
  Result: every browser session on an auth-enabled install logged a 401
  on the appliance endpoint before login.

  Added /api/v1/system/appliance to PUBLIC_API_ROUTES with a comment
  pointing at the dual-list pattern so this doesn't drift again, and a
  regression test in TestAuthMiddlewarePublicRoutes that posts /auth/setup
  to turn auth on, then asserts the endpoint returns 200 with the
  documented shape (hostname / timezone / locale / time_synced fields all
  present).
This commit is contained in:
maziggy
2026-06-25 15:19:28 +02:00
parent 70857af393
commit c236fdc650
3 changed files with 39 additions and 6 deletions
@@ -854,6 +854,25 @@ class TestAuthMiddlewarePublicRoutes:
assert response.status_code == 200
assert "auth_enabled" in response.json()
@pytest.mark.asyncio
@pytest.mark.integration
async def test_system_appliance_is_public(self, async_client: AsyncClient, enabled_auth):
"""Verify /api/v1/system/appliance is reachable without a JWT.
The SPA's i18n bootstrap fetches this BEFORE login to seed locale,
hostname, timezone, and NTP-gate state. The route handler has no
auth dependency, but the global auth_middleware blocks every
/api/ path not in PUBLIC_API_ROUTES — so without an explicit
allowlist entry the user sees a 401 in the browser console on
every page load.
"""
response = await async_client.get("/api/v1/system/appliance")
assert response.status_code == 200, response.text
body = response.json()
# Shape contract (no-auth surface):
for key in ("hostname", "timezone", "locale", "time_synced"):
assert key in body
@pytest.mark.asyncio
@pytest.mark.integration
async def test_auth_login_is_public(self, async_client: AsyncClient, enabled_auth):