/ tests / test_setup_info.py
test_setup_info.py
 1  """Tests for /setup (public) and /info (authenticated) response shapes.
 2  
 3  In particular: the admin-only `auth_secret_weak` security flag must
 4  NOT leak via the public /setup endpoint — that would let an
 5  unauthenticated attacker probe for weak-secret misconfigurations.
 6  """
 7  from __future__ import annotations
 8  
 9  import pytest
10  from fastapi.testclient import TestClient
11  
12  from restai.config import RESTAI_DEFAULT_PASSWORD
13  from restai.main import app
14  
15  
16  ADMIN = ("admin", RESTAI_DEFAULT_PASSWORD)
17  
18  
19  @pytest.fixture(scope="module")
20  def client():
21      with TestClient(app) as c:
22          yield c
23  
24  
25  def test_setup_is_public_and_omits_security_flags(client):
26      r = client.get("/setup")
27      assert r.status_code == 200
28      body = r.json()
29      # Must NOT carry the admin-only weak-secret signal.
30      assert "auth_secret_weak" not in body, (
31          "auth_secret_weak leaked via unauthenticated /setup"
32      )
33      # Sanity: the pre-login UI knobs are still here.
34      for k in ("app_name", "sso", "sso_provider_names", "mcp"):
35          assert k in body, f"expected {k} in /setup response"
36  
37  
38  def test_info_requires_auth(client):
39      r = client.get("/info")
40      assert r.status_code == 401
41  
42  
43  def test_info_exposes_auth_secret_weak_to_admin(client):
44      r = client.get("/info", auth=ADMIN)
45      assert r.status_code == 200
46      body = r.json()
47      # Field is always present for authenticated callers; value is
48      # environment-dependent.
49      assert "auth_secret_weak" in body
50      assert isinstance(body["auth_secret_weak"], bool)
51  
52  
53  def test_info_hides_auth_secret_weak_from_non_admin(client):
54      """Non-admin users get False regardless of actual state — the
55      signal is reconnaissance-relevant even for low-trust users."""
56      import random
57      username = f"info_viewer_{random.randint(0, 999999)}"
58      client.post("/users", json={"username": username, "password": "x"}, auth=ADMIN)
59      try:
60          r = client.get("/info", auth=(username, "x"))
61          assert r.status_code == 200
62          body = r.json()
63          assert body.get("auth_secret_weak") is False
64      finally:
65          client.delete(f"/users/{username}", auth=ADMIN)