Skip to content

Commit 53ef8bb

Browse files
committed
Add scanner name to Test name
1 parent fda154a commit 53ef8bb

File tree

2 files changed

+148
-2
lines changed

2 files changed

+148
-2
lines changed

dojo/tools/openreports/parser.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import logging
55

66
from dojo.models import Finding
7+
from dojo.tools.parser_test import ParserTest
78

89
logger = logging.getLogger(__name__)
910

@@ -72,6 +73,61 @@ def get_findings(self, scan_file, test):
7273

7374
return findings
7475

76+
def get_tests(self, scan_type, handle):
77+
try:
78+
data = json.load(handle)
79+
except Exception:
80+
handle.seek(0)
81+
scan_data = handle.read()
82+
try:
83+
data = json.loads(str(scan_data, "utf-8"))
84+
except Exception:
85+
data = json.loads(scan_data)
86+
87+
if data is None:
88+
return []
89+
90+
# Handle both single report and list of reports
91+
reports = []
92+
if isinstance(data, dict):
93+
if data.get("kind") == "List" and "items" in data:
94+
reports = data["items"]
95+
elif data.get("kind") == "Report":
96+
reports = [data]
97+
elif isinstance(data, list):
98+
reports = data
99+
100+
# Find all unique sources across all reports
101+
sources_found = set()
102+
for report in reports:
103+
if not isinstance(report, dict) or report.get("kind") != "Report":
104+
continue
105+
for result in report.get("results", []):
106+
source = result.get("source", "OpenReports")
107+
sources_found.add(source)
108+
109+
# Create a ParserTest for each source
110+
tests = []
111+
for source in sorted(sources_found):
112+
test = ParserTest(
113+
name=source,
114+
parser_type=source,
115+
version=None,
116+
)
117+
test.findings = []
118+
119+
# Parse all reports and filter findings by source
120+
for report in reports:
121+
if not isinstance(report, dict) or report.get("kind") != "Report":
122+
continue
123+
124+
findings = self._parse_report_for_source(test, report, source)
125+
test.findings.extend(findings)
126+
127+
tests.append(test)
128+
129+
return tests
130+
75131
def _parse_report(self, test, report):
76132
findings = []
77133

@@ -102,6 +158,41 @@ def _parse_report(self, test, report):
102158

103159
return findings
104160

161+
def _parse_report_for_source(self, test, report, source_filter):
162+
findings = []
163+
164+
# Extract metadata
165+
metadata = report.get("metadata", {})
166+
report_name = metadata.get("name", "")
167+
namespace = metadata.get("namespace", "")
168+
report_uid = metadata.get("uid", "")
169+
170+
# Extract scope information
171+
scope = report.get("scope", {})
172+
scope_kind = scope.get("kind", "")
173+
scope_name = scope.get("name", "")
174+
175+
# Create service identifier from scope and metadata
176+
service_name = f"{namespace}/{scope_kind}/{scope_name}" if namespace else f"{scope_kind}/{scope_name}"
177+
178+
# Extract results
179+
results = report.get("results", [])
180+
181+
for result in results:
182+
if not isinstance(result, dict):
183+
continue
184+
185+
# Filter by source
186+
result_source = result.get("source", "OpenReports")
187+
if result_source != source_filter:
188+
continue
189+
190+
finding = self._create_finding_from_result(None, result, service_name, report_name, report_uid)
191+
if finding:
192+
findings.append(finding)
193+
194+
return findings
195+
105196
def _create_finding_from_result(self, test, result, service_name, report_name, report_uid):
106197
try:
107198
# Extract basic fields

unittests/tools/test_openreports_parser.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ def test_single_report(self):
3535
self.assertEqual(1, len(finding1.unsaved_vulnerability_ids))
3636
self.assertEqual("CVE-2025-9232", finding1.unsaved_vulnerability_ids[0])
3737
self.assertEqual(
38-
"b1fcca57-2efd-44d3-89e9-949e29b61936:CVE-2025-9232:libcrypto3", finding1.unique_id_from_tool,
38+
"b1fcca57-2efd-44d3-89e9-949e29b61936:CVE-2025-9232:libcrypto3",
39+
finding1.unique_id_from_tool,
3940
)
4041
self.assertIn("vulnerability scan", finding1.tags)
4142
self.assertIn("image-scanner", finding1.tags)
@@ -72,7 +73,8 @@ def test_single_report(self):
7273
# Non-CVE policies should not have vulnerability IDs
7374
self.assertIsNone(finding3.unsaved_vulnerability_ids)
7475
self.assertEqual(
75-
"b1fcca57-2efd-44d3-89e9-949e29b61936:CIS-BENCH-001:web-server", finding3.unique_id_from_tool,
76+
"b1fcca57-2efd-44d3-89e9-949e29b61936:CIS-BENCH-001:web-server",
77+
finding3.unique_id_from_tool,
7678
)
7779
self.assertIn("compliance check", finding3.tags)
7880
self.assertIn("compliance-scanner", finding3.tags)
@@ -113,3 +115,56 @@ def test_parser_metadata(self):
113115

114116
description = parser.get_description_for_scan_types("OpenReports")
115117
self.assertEqual("Import OpenReports JSON report.", description)
118+
119+
def test_get_tests_single_source(self):
120+
with sample_path("openreports_single_report.json").open(encoding="utf-8") as test_file:
121+
parser = OpenreportsParser()
122+
tests = parser.get_tests("OpenReports", test_file)
123+
124+
# Should have two tests for the two sources
125+
self.assertEqual(len(tests), 2)
126+
127+
# Verify test names
128+
test_names = {test.name for test in tests}
129+
self.assertIn("image-scanner", test_names)
130+
self.assertIn("compliance-scanner", test_names)
131+
132+
# Find the image-scanner test
133+
image_scanner_test = next(t for t in tests if t.name == "image-scanner")
134+
self.assertEqual("image-scanner", image_scanner_test.type)
135+
self.assertIsNone(image_scanner_test.version)
136+
self.assertEqual(2, len(image_scanner_test.findings))
137+
138+
# Verify findings are properly created
139+
finding1 = image_scanner_test.findings[0]
140+
self.assertEqual("CVE-2025-9232 in libcrypto3", finding1.title)
141+
self.assertEqual("Low", finding1.severity)
142+
# Verify test is not set - check using hasattr to avoid RelatedObjectDoesNotExist
143+
self.assertFalse(hasattr(finding1, "test") and finding1.test is not None)
144+
145+
def test_get_tests_multiple_sources(self):
146+
with sample_path("openreports_list_format.json").open(encoding="utf-8") as test_file:
147+
parser = OpenreportsParser()
148+
tests = parser.get_tests("OpenReports", test_file)
149+
150+
# Should have two tests for the two different sources
151+
self.assertEqual(len(tests), 2)
152+
153+
# Verify test names
154+
test_names = {test.name for test in tests}
155+
self.assertIn("policy-scanner", test_names)
156+
self.assertIn("image-scanner", test_names)
157+
158+
# Find the image-scanner test
159+
image_scanner_test = next(t for t in tests if t.name == "image-scanner")
160+
self.assertEqual(2, len(image_scanner_test.findings))
161+
162+
# Find the policy-scanner test
163+
policy_scanner_test = next(t for t in tests if t.name == "policy-scanner")
164+
self.assertEqual(1, len(policy_scanner_test.findings))
165+
166+
# Verify findings have no test set
167+
for test in tests:
168+
for finding in test.findings:
169+
# Check using hasattr to avoid RelatedObjectDoesNotExist
170+
self.assertFalse(hasattr(finding, "test") and finding.test is not None)

0 commit comments

Comments
 (0)