Coverage for tests / integration / test_ssrf_api.py: 0%

52 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-18 23:20 -0400

1"""Integration tests for the ssrf-api. 

2 

3Verifies that GraphQLer's SSRF detector correctly flags the intentionally 

4vulnerable endpoints exposed by tests/test-apis/ssrf-api/. 

5 

6Detectors exercised: 

7 - SSRF Injection (fetchUrl / pingEndpoint / registerWebhook — raw outbound 

8 HTTP requests whose connection-error messages are reflected back verbatim) 

9""" 

10 

11import os 

12import shutil 

13import unittest 

14 

15from graphqler import __main__, config 

16from tests.integration.utils.run_api import run_node_project, wait_for_server 

17from tests.integration.utils.stats import ( 

18 get_vulnerabilities_from_stats, 

19 is_detection_flagged, 

20) 

21 

22 

23class TestSSRFAPI(unittest.TestCase): 

24 PORT = 4003 

25 URL = f"http://localhost:{PORT}/graphql" 

26 PATH = "ci-test-ssrf-api/" 

27 API_PATH = "tests/test-apis/ssrf-api" 

28 CONFIG_PATH = "tests/test-apis/test_configs/ssrf_api_config.toml" 

29 process = None 

30 process_pid = None 

31 

32 @classmethod 

33 def setUpClass(cls): 

34 cls.process = run_node_project(cls.API_PATH, [], str(cls.PORT)) 

35 cls.process_pid = cls.process.pid 

36 

37 parsed = __main__.parse_config(cls.CONFIG_PATH) 

38 __main__.set_config(parsed) 

39 

40 wait_for_server(cls.URL, timeout=30) 

41 

42 @classmethod 

43 def tearDownClass(cls): 

44 if cls.process and cls.process.pid == cls.process_pid: 

45 cls.process.kill() 

46 cls.process.wait() 

47 if os.path.exists(cls.PATH): 

48 shutil.rmtree(cls.PATH) 

49 

50 # ── Compilation ────────────────────────────────────────────────────────── 

51 

52 def test_compile_generates_introspection_file(self): 

53 __main__.run_compile_mode(self.PATH, self.URL) 

54 introspection_path = os.path.join(self.PATH, config.INTROSPECTION_RESULT_FILE_NAME) 

55 self.assertTrue(os.path.exists(introspection_path)) 

56 self.assertGreater(os.path.getsize(introspection_path), 0) 

57 

58 # ── Fuzzing ────────────────────────────────────────────────────────────── 

59 

60 def test_fuzz_generates_stats_file(self): 

61 __main__.run_compile_mode(self.PATH, self.URL) 

62 __main__.run_fuzz_mode(self.PATH, self.URL) 

63 stats_path = os.path.join(self.PATH, config.STATS_FILE_NAME) 

64 self.assertTrue(os.path.exists(stats_path)) 

65 self.assertGreater(os.path.getsize(stats_path), 0) 

66 

67 def test_fuzz_generates_json_stats_file(self): 

68 __main__.run_compile_mode(self.PATH, self.URL) 

69 __main__.run_fuzz_mode(self.PATH, self.URL) 

70 json_path = os.path.join(self.PATH, "stats.json") 

71 self.assertTrue(os.path.exists(json_path)) 

72 self.assertGreater(os.path.getsize(json_path), 0) 

73 

74 # ── SSRF detection ──────────────────────────────────────────────────────── 

75 

76 def _run_and_get_vulns(self): 

77 __main__.run_compile_mode(self.PATH, self.URL) 

78 __main__.run_fuzz_mode(self.PATH, self.URL) 

79 return get_vulnerabilities_from_stats(self.PATH) 

80 

81 def test_ssrf_injection_detected(self): 

82 vulns = self._run_and_get_vulns() 

83 self.assertTrue( 

84 is_detection_flagged(vulns, "SSRF Injection"), 

85 f"Expected SSRF to be flagged. Got: {vulns}", 

86 )