Skip to content

Commit 8940cc8

Browse files
authored
Bug Fix: improve Kiuwan SCA parser to support multi component findings (#12753)
* fix(Kiuwan Sca Scan): improve Kiuwan SCA parser to support multi-component findings * test: update unit tests according to correct logic * refactor: use better unique id from tool * fix unit tests * refactor: back to using unique id from tool like supposed to be * fix: lint * fix: tests * refactor: update logic to set finding title * refactor: use debug instead of warning for log output * refactor: use vuln_id_from_tool instead of unique_id_from_tool
1 parent 832a0f1 commit 8940cc8

2 files changed

Lines changed: 62 additions & 50 deletions

File tree

dojo/tools/kiuwan_sca/parser.py

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import hashlib
22
import json
3+
import logging
34

45
from dojo.models import Finding
56

7+
logger = logging.getLogger(__name__)
8+
69
__author__ = "mwager"
710

811

@@ -37,50 +40,59 @@ def get_findings(self, filename, test):
3740
if row["muted"] is True:
3841
continue
3942

40-
finding = Finding(test=test)
41-
finding.unique_id_from_tool = row["id"]
42-
finding.cve = row["cve"]
43-
finding.description = row["description"]
44-
finding.severity = self.SEVERITY[row["securityRisk"]]
45-
46-
if "components" in row and len(row["components"]) > 0:
47-
finding.component_name = row["components"][0]["artifact"]
48-
finding.component_version = row["components"][0]["version"]
49-
finding.title = finding.component_name + " v" + str(finding.component_version)
50-
51-
if not finding.title:
52-
finding.title = row["cve"]
53-
54-
if "cwe" in row and "CWE-" in row["cwe"]:
55-
finding.cwe = int(row["cwe"].replace("CWE-", ""))
56-
57-
if "epss_score" in row:
58-
finding.epss_score = row["epss_score"]
59-
if "epss_percentile" in row:
60-
finding.epss_percentile = row["epss_percentile"]
61-
62-
if "cVSSv3BaseScore" in row:
63-
finding.cvssv3_score = float(row["cVSSv3BaseScore"])
64-
65-
finding.references = "See Kiuwan Web UI"
66-
finding.mitigation = "See Kiuwan Web UI"
67-
finding.static_finding = True
68-
69-
key = hashlib.sha256(
70-
(
71-
finding.description
72-
+ "|"
73-
+ finding.severity
74-
+ "|"
75-
+ finding.component_name
76-
+ "|"
77-
+ finding.component_version
78-
+ "|"
79-
+ str(finding.cwe)
80-
).encode("utf-8"),
81-
).hexdigest()
82-
83-
if key not in dupes:
84-
dupes[key] = finding
43+
components = row.get("components", [])
44+
if not components:
45+
logger.debug("Insights Finding from Kiuwan does not have a related component - Skipping.")
46+
continue
47+
48+
# We want one unique finding in DD for each component affected:
49+
for component in components:
50+
finding = Finding(test=test)
51+
finding.vuln_id_from_tool = str(row["id"])
52+
finding.cve = row["cve"]
53+
finding.description = row["description"]
54+
finding.severity = self.SEVERITY[row["securityRisk"]]
55+
56+
if "artifact" in component:
57+
finding.component_name = component["artifact"]
58+
if "version" in component:
59+
finding.component_version = component["version"]
60+
61+
if finding.component_name and finding.component_version:
62+
finding.title = f"{finding.component_name} v{finding.component_version}"
63+
else:
64+
finding.title = finding.cve or "Unnamed Finding"
65+
66+
if "cwe" in row and "CWE-" in row["cwe"]:
67+
finding.cwe = int(row["cwe"].replace("CWE-", ""))
68+
69+
if "epss_score" in row:
70+
finding.epss_score = row["epss_score"]
71+
if "epss_percentile" in row:
72+
finding.epss_percentile = row["epss_percentile"]
73+
74+
if "cVSSv3BaseScore" in row:
75+
finding.cvssv3_score = float(row["cVSSv3BaseScore"])
76+
77+
finding.references = "See Kiuwan Web UI"
78+
finding.mitigation = "See Kiuwan Web UI"
79+
finding.static_finding = True
80+
81+
key = hashlib.sha256(
82+
(
83+
finding.description
84+
+ "|"
85+
+ finding.severity
86+
+ "|"
87+
+ finding.component_name
88+
+ "|"
89+
+ finding.component_version
90+
+ "|"
91+
+ str(finding.cwe or "")
92+
).encode("utf-8"),
93+
).hexdigest()
94+
95+
if key not in dupes:
96+
dupes[key] = finding
8597

8698
return list(dupes.values())

unittests/tools/test_kiuwan_sca_parser.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ def test_parse_file_with_two_vuln_has_two_findings(self):
1515
with (get_unit_tests_scans_path("kiuwan_sca") / "kiuwan_sca_two_vuln.json").open(encoding="utf-8") as testfile:
1616
parser = KiuwanSCAParser()
1717
findings = parser.get_findings(testfile, Test())
18-
# file contains 3, but we only get 2 as "muted" ones are ignored:
19-
self.assertEqual(2, len(findings))
18+
# file contains 3 cves, one of them is muted. so we have 2 cves with a total of 5 components
19+
self.assertEqual(5, len(findings))
2020

2121
def test_parse_file_with_multiple_vuln_has_multiple_finding(self):
2222
with (get_unit_tests_scans_path("kiuwan_sca") / "kiuwan_sca_many_vuln.json").open(encoding="utf-8") as testfile:
2323
parser = KiuwanSCAParser()
2424
findings = parser.get_findings(testfile, Test())
25-
# also tests deduplication as there are 28 findings in the file:
26-
self.assertEqual(27, len(findings))
25+
# also tests deduplication as there are 28 cves in the file (but some including >1 components!):
26+
self.assertEqual(45, len(findings))
2727

2828
def test_correct_mapping(self):
2929
with (get_unit_tests_scans_path("kiuwan_sca") / "kiuwan_sca_two_vuln.json").open(encoding="utf-8") as testfile:
@@ -37,7 +37,7 @@ def test_correct_mapping(self):
3737
self.assertEqual(finding1.component_name, "org.apache.cxf:cxf-rt-ws-policy")
3838
self.assertEqual(finding1.component_version, "3.3.5")
3939
self.assertEqual(finding1.cwe, 835)
40-
self.assertEqual(finding1.unique_id_from_tool, 158713)
40+
self.assertEqual(finding1.vuln_id_from_tool, "158713")
4141
self.assertEqual(finding1.cvssv3_score, 7.5)
4242
self.assertEqual(finding1.epss_score, 0.1)
4343
self.assertEqual(finding1.epss_percentile, 0.2)

0 commit comments

Comments
 (0)