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

1from fastapi import FastAPI 1qrst

2from fastapi.testclient import TestClient 1qrst

3 

4 

5def test_root_path_does_not_persist_across_requests(): 1qrst

6 app = FastAPI() 1abcd

7 

8 @app.get("/") 1abcd

9 def read_root(): # pragma: no cover 1abcd

10 return {"ok": True} 

11 

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

17 

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

24 

25 

26def test_multiple_different_root_paths_do_not_accumulate(): 1qrst

27 app = FastAPI() 1efgh

28 

29 @app.get("/") 1efgh

30 def read_root(): # pragma: no cover 1efgh

31 return {"ok": True} 

32 

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

36 

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 ) 

46 

47 

48def test_legitimate_root_path_still_appears(): 1qrst

49 app = FastAPI() 1ijkl

50 

51 @app.get("/") 1ijkl

52 def read_root(): # pragma: no cover 1ijkl

53 return {"ok": True} 

54 

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

60 

61 

62def test_configured_servers_not_mutated(): 1qrst

63 configured_servers = [{"url": "https://prod.example.com"}] 1mnop

64 app = FastAPI(servers=configured_servers) 1mnop

65 

66 @app.get("/") 1mnop

67 def read_root(): # pragma: no cover 1mnop

68 return {"ok": True} 

69 

70 # Request with a rogue root_path 

71 attacker_client = TestClient(app, root_path="/evil") 1mnop

72 attacker_client.get("/openapi.json") 1mnop

73 

74 # The original servers list must be untouched 

75 assert configured_servers == [{"url": "https://prod.example.com"}] 1mnop