Coverage for tests / test_openapi_cache_root_path.py: 100%
37 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +0000
1from fastapi import FastAPI 1qrst
2from fastapi.testclient import TestClient 1qrst
5def test_root_path_does_not_persist_across_requests(): 1qrst
6 app = FastAPI() 1abcd
8 @app.get("/") 1abcd
9 def read_root(): # pragma: no cover 1abcd
10 return {"ok": True}
12 # Attacker request with a spoofed root_path
13 attacker_client = TestClient(app, root_path="/evil-api") 1abcd
14 response1 = attacker_client.get("/openapi.json") 1abcd
15 data1 = response1.json() 1abcd
16 assert any(s.get("url") == "/evil-api" for s in data1.get("servers", [])) 1abcd
18 # Subsequent legitimate request with no root_path
19 clean_client = TestClient(app) 1abcd
20 response2 = clean_client.get("/openapi.json") 1abcd
21 data2 = response2.json() 1abcd
22 servers = [s.get("url") for s in data2.get("servers", [])] 1abcd
23 assert "/evil-api" not in servers 1abcd
26def test_multiple_different_root_paths_do_not_accumulate(): 1qrst
27 app = FastAPI() 1efgh
29 @app.get("/") 1efgh
30 def read_root(): # pragma: no cover 1efgh
31 return {"ok": True}
33 for prefix in ["/path-a", "/path-b", "/path-c"]: 1efgh
34 c = TestClient(app, root_path=prefix) 1efgh
35 c.get("/openapi.json") 1efgh
37 # A clean request should not have any of them
38 clean_client = TestClient(app) 1efgh
39 response = clean_client.get("/openapi.json") 1efgh
40 data = response.json() 1efgh
41 servers = [s.get("url") for s in data.get("servers", [])] 1efgh
42 for prefix in ["/path-a", "/path-b", "/path-c"]: 1efgh
43 assert prefix not in servers, ( 1efgh
44 f"root_path '{prefix}' leaked into clean request: {servers}"
45 )
48def test_legitimate_root_path_still_appears(): 1qrst
49 app = FastAPI() 1ijkl
51 @app.get("/") 1ijkl
52 def read_root(): # pragma: no cover 1ijkl
53 return {"ok": True}
55 client = TestClient(app, root_path="/api/v1") 1ijkl
56 response = client.get("/openapi.json") 1ijkl
57 data = response.json() 1ijkl
58 servers = [s.get("url") for s in data.get("servers", [])] 1ijkl
59 assert "/api/v1" in servers 1ijkl
62def test_configured_servers_not_mutated(): 1qrst
63 configured_servers = [{"url": "https://prod.example.com"}] 1mnop
64 app = FastAPI(servers=configured_servers) 1mnop
66 @app.get("/") 1mnop
67 def read_root(): # pragma: no cover 1mnop
68 return {"ok": True}
70 # Request with a rogue root_path
71 attacker_client = TestClient(app, root_path="/evil") 1mnop
72 attacker_client.get("/openapi.json") 1mnop
74 # The original servers list must be untouched
75 assert configured_servers == [{"url": "https://prod.example.com"}] 1mnop