Skip to content

Commit

Permalink
Mend SCA Parser update (#11395)
Browse files Browse the repository at this point in the history
* Add unit test json files for Mend Platform - SAST Findings

Code findings in API 3.0 / Platform for Mend, SAST respectively.

* Update test_mend_parser.py

* Fix newline eof

* Update parser.py

Remove locations / path from Description of SCA Platform output and instead implement locations in steps_to_reproduce.

* Update test_mend_parser.py

Updating value to a placeholder severityRating right now of 2.143.  Still working on this and the cvssv3 assertion values.

* Update test_mend_parser.py

* Refactoring this for SCA only and SAST will be an additional PR - need to restructure format slightly for SAST

* Update parser.py

* Update parser.py

* Update parser.py

* fix loc 399 to 3999 for locations + add steps_to_reproduce for SCA Platform similar to SCA Legacy so Findings can be structured similarly

* Fix spacing, remove trailing comma

* Fix space

* Removing redundancy

* Fix the join on locations for Platform SCA

* Removing redundancy component dependency type from description since it's in impact as well

Removing redundancy component dependency type from description since it's in impact as well

* Make Impact more readible

* Update parser.py

* Update format for unit test

* Fix case on unit test

* Remove duplicate join to fix steps_to_reproduce formatting

Remove duplicate join to fix steps_to_reproduce formatting

* Fix join for locations and steps_to_reproduce

* fix newline eof

* fix comma, remove redundant locations reference

* Update parser.py

* Fix eof

* Update parser.py

* fix ,

* Update parser.py

* Update parser.py

* edit steps_to_reproduce locations found

* Update parser.py

* fix 500 internal server error bug, add else None to impact for edge case

* fix typo

* adding cneil suggestion for truncating locations

adding cneil suggestion for truncating locations

* implement suggestion from Mend engineers

* fix new line

* Update parser.py

* Update parser.py

* fix indentation

* fix finding_info

* attempt to fix conditional logic for only getting ACTIVE findingInfo status

* attempt to fix cve and title for new component logic

* update unit test for new title check

* fix whitespace before comma

* add unit test case for legacy title

* fix duplicate conditional - add into tree_node logic

* add title logic back in

* add OPEN in addition to ACTIVE

* Update parser.py
  • Loading branch information
testaccount90009 authored Jan 23, 2025
1 parent 9d773a0 commit c2ed251
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 27 deletions.
61 changes: 37 additions & 24 deletions dojo/tools/mend/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def _build_common_output(node, lib_name=None):
description = "No Description Available"
cvss3_score = None
mitigation = "N/A"
locations = []
if "component" in node:
description = (
"**Vulnerability Description**: "
Expand All @@ -56,18 +57,19 @@ def _build_common_output(node, lib_name=None):
+ "**Library Type**: "
+ node["component"].get("libraryType", "")
+ "\n"
+ "**Location Found**: "
+ node["component"].get("path", "")
+ "\n"
+ "**Direct or Transitive Dependency**: "
+ node["component"].get("dependencyType", "")
+ "\n"
)
lib_name = node["component"].get("name")
component_name = node["component"].get("artifactId")
component_version = node["component"].get("version")
impact = node["component"].get("dependencyType")
impact = (
"**Direct or Transitive Vulnerability**: "
+ node["component"].get("dependencyType", "")
+ "\n"
)
cvss3_score = node["vulnerability"].get("score", None)
component_path = node["component"].get("path", None)
if component_path:
locations.append(component_path)
if "topFix" in node:
try:
topfix_node = node.get("topFix")
Expand All @@ -82,7 +84,6 @@ def _build_common_output(node, lib_name=None):
)
except Exception:
logger.exception("Error handling topFix node.")

elif "library" in node:
node.get("project")
description = (
Expand Down Expand Up @@ -136,18 +137,6 @@ def _build_common_output(node, lib_name=None):
)
cwe = 1035 # default OWASP a9 until the report actually has them

# comment out the below for now - working on adding this into the above conditional statements since format can be slightly different
# mitigation = "N/A"
# if "topFix" in node:
# try:
# topfix_node = node.get("topFix")
# mitigation = "**Resolution** ({}): {}\n".format(
# topfix_node.get("date"),
# topfix_node.get("fixResolution"),
# )
# except Exception:
# logger.exception("Error handling topFix node.")

filepaths = []
if "sourceFiles" in node:
try:
Expand All @@ -159,7 +148,6 @@ def _build_common_output(node, lib_name=None):
"Error handling local paths for vulnerability.",
)

locations = []
if "locations" in node:
try:
locations_node = node.get("locations", [])
Expand All @@ -171,8 +159,31 @@ def _build_common_output(node, lib_name=None):
logger.exception(
"Error handling local paths for vulnerability.",
)
if locations:
# Join the locations into a single string
joined_locations = ", ".join(locations)

# If the length exceeds 3999 characters, trim it
if len(joined_locations) > 3999:
# Iterate over the locations and trim until the total length is <= 3999
total_length = 0
truncated_locations = []

for loc in locations:
loc_length = len(loc)
# Check if adding this location will exceed the limit
if total_length + loc_length + len(truncated_locations) <= 3996: # 3999 - len("...") = 3996
truncated_locations.append(loc)
total_length += loc_length
else:
# Stop if adding the next location will exceed the limit
break

# Add ellipsis at the end to indicate truncation
locations = truncated_locations
locations.append("...") # Add the ellipsis to the end of the locations list

filepaths = locations or filepaths
filepaths = filepaths

new_finding = Finding(
title=title,
Expand All @@ -188,7 +199,8 @@ def _build_common_output(node, lib_name=None):
dynamic_finding=True,
cvssv3=cvss3_vector,
cvssv3_score=float(cvss3_score) if cvss3_score is not None else None,
impact=impact,
impact=impact if impact is not None else None,
steps_to_reproduce="**Locations Found**: " + ", ".join(locations) if locations is not None else None,
)
if cve:
new_finding.unsaved_vulnerability_ids = [cve]
Expand Down Expand Up @@ -238,7 +250,8 @@ def _build_common_output(node, lib_name=None):
tree_node = content["response"]
if tree_node:
for node in tree_node:
findings.append(_build_common_output(node))
if node.get("findingInfo", {}).get("status") == "ACTIVE":
findings.append(_build_common_output(node))

def create_finding_key(f: Finding) -> str:
# """Hashes the finding's description and title to retrieve a key for deduplication."""
Expand Down
8 changes: 5 additions & 3 deletions unittests/tools/test_mend_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ def test_parse_file_with_one_sca_vuln_finding(self):
findings = parser.get_findings(testfile, Test())
self.assertEqual(1, len(findings))
finding = list(findings)[0]
self.assertEqual("D:\\MendRepo\\test-product\\test-project\\test-project-subcomponent\\path\\to\\the\\Java\\commons-codec-1.6_donotuse.jar", finding.file_path)
self.assertEqual("**Locations Found**: D:\\MendRepo\\test-product\\test-project\\test-project-subcomponent\\path\\to\\the\\Java\\commons-codec-1.6_donotuse.jar", finding.steps_to_reproduce)
self.assertEqual("WS-2019-0379 | commons-codec-1.6.jar", finding.title)

def test_parse_file_with_no_vuln_has_no_findings_platform(self):
with open("unittests/scans/mend/mend-sca-platform-api3-no-findings.json", encoding="utf-8") as testfile:
Expand All @@ -60,9 +61,10 @@ def test_parse_file_with_one_vuln_has_one_findings_platform(self):
self.assertEqual("CVE-2024-51744", finding.unsaved_vulnerability_ids[0])
self.assertEqual("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N", finding.cvssv3)
self.assertEqual(3.1, finding.cvssv3_score)
self.assertEqual("CVE-2024-51744 | github.com/golang-JWT/jwt-v3.2.2+incompatible", finding.title)

def test_parse_file_with_multiple_vuln_has_multiple_finding_platform(self):
with open("unittests/scans/mend/mend-sca-platform-api3-eleven-findings.json", encoding="utf-8") as testfile:
with open("unittests/scans/mend/mend-sca-platform-api3-multiple-findings.json", encoding="utf-8") as testfile:
parser = MendParser()
findings = parser.get_findings(testfile, Test())
self.assertEqual(11, len(findings))
self.assertEqual(5, len(findings))

0 comments on commit c2ed251

Please sign in to comment.