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
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-18 23:20 -0400
1"""Integration tests for the ssrf-api.
3Verifies that GraphQLer's SSRF detector correctly flags the intentionally
4vulnerable endpoints exposed by tests/test-apis/ssrf-api/.
6Detectors exercised:
7 - SSRF Injection (fetchUrl / pingEndpoint / registerWebhook — raw outbound
8 HTTP requests whose connection-error messages are reflected back verbatim)
9"""
11import os
12import shutil
13import unittest
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)
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
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
37 parsed = __main__.parse_config(cls.CONFIG_PATH)
38 __main__.set_config(parsed)
40 wait_for_server(cls.URL, timeout=30)
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)
50 # ── Compilation ──────────────────────────────────────────────────────────
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)
58 # ── Fuzzing ──────────────────────────────────────────────────────────────
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)
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)
74 # ── SSRF detection ────────────────────────────────────────────────────────
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)
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 )