Skip to content

Commit

Permalink
Fix formatting to flake8 standards
Browse files Browse the repository at this point in the history
  • Loading branch information
Hydragyrum committed Oct 10, 2024
1 parent ee604ab commit fae4b81
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 54 deletions.
16 changes: 11 additions & 5 deletions dojo/tools/ptart/assessment_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ def __init__(self):
self.cvss_type = None

def get_test_data(self, tree):
# Check that the report is valid, If we have no assessments, then return an empty list
# Check that the report is valid, If we have no assessments, then
# return an empty list
if "assessments" not in tree:
return []

self.cvss_type = tree.get("cvss_type", None)
assessments = tree["assessments"]
return [finding for assessment in assessments for finding in self.parse_assessment(assessment)]
return [finding for assessment in assessments
for finding in self.parse_assessment(assessment)]

def parse_assessment(self, assessment):
hits = assessment.get("hits", [])
Expand All @@ -23,7 +25,9 @@ def get_finding(self, assessment, hit):
finding = Finding(
title=ptart_tools.parse_title_from_hit(hit),
severity=ptart_tools.parse_ptart_severity(hit.get("severity", 5)),
effort_for_fixing=ptart_tools.parse_ptart_fix_effort(hit.get("fix_complexity", 3)),
effort_for_fixing=ptart_tools.parse_ptart_fix_effort(
hit.get("fix_complexity", 3)
),
component_name=assessment.get("title", "Unknown Component"),
date=ptart_tools.parse_date_added_from_hit(hit),
)
Expand All @@ -48,8 +52,10 @@ def get_finding(self, assessment, hit):

finding.unsaved_endpoints = ptart_tools.parse_endpoints_from_hit(hit)

# Add screenshots to files, and add other attachments to the files as well.
# Add screenshots to files, and add other attachments as well.
finding.unsaved_files = ptart_tools.parse_screenshots_from_hit(hit)
finding.unsaved_files.extend(ptart_tools.parse_attachment_from_hit(hit))
finding.unsaved_files.extend(
ptart_tools.parse_attachment_from_hit(hit)
)

return finding
23 changes: 15 additions & 8 deletions dojo/tools/ptart/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

class PTARTParser(object):
"""
Imports JSON reports from the PTART (https://github.com/certmichelin/PTART) reporting tool
Imports JSON reports from the PTART reporting tool
(https://github.com/certmichelin/PTART)
"""

def get_scan_types(self):
Expand All @@ -29,14 +30,15 @@ def get_tests(self, scan_type, scan):
version="",
)

# We set both to the same value for now, setting just the name doesn't seem to display when imported.
# This may cause issues with the UI in the future, but there's not much (read no) documentation on this.
# We set both to the same value for now, setting just the name doesn't
# seem to display when imported. This may cause issues with the UI in
# the future, but there's not much (read no) documentation on this.
if "name" in data:
test.name = data["name"] + " Report"
test.type = data["name"] + " Report"

# Generate a description from the various fields in the report data
description = ptart_tools.generate_test_description_from_report_base(data)
description = ptart_tools.generate_test_description_from_report(data)

# Check that the fields are filled, otherwise don't set the description
if description:
Expand All @@ -45,10 +47,14 @@ def get_tests(self, scan_type, scan):
# Setting the dates doesn't seem to want to work in reality :(
# Perhaps in a future version of DefectDojo?
if "start_date" in data:
test.target_start = ptart_tools.parse_date(data["start_date"], "%Y-%m-%d")
test.target_start = ptart_tools.parse_date(
data["start_date"],
"%Y-%m-%d"
)

if "end_date" in data:
test.target_end = ptart_tools.parse_date(data["end_date"], "%Y-%m-%d")
test.target_end = ptart_tools.parse_date(data["end_date"],
"%Y-%m-%d")

findings = self.get_items(data)
test.findings = findings
Expand All @@ -59,8 +65,9 @@ def get_findings(self, file, test):
return self.get_items(data)

def get_items(self, data):
# We have several main sections in the report json: Assessments and Retest Campaigns.
# I haven't been able to create multiple tests for each section, so we'll just merge them for now.
# We have several main sections in the report json: Assessments and
# Retest Campaigns. I haven't been able to create multiple tests for
# each section, so we'll just merge them for now.
findings = PTARTAssessmentParser().get_test_data(data)
findings.extend(PTARTRetestParser().get_test_data(data))
return findings
Expand Down
26 changes: 18 additions & 8 deletions dojo/tools/ptart/ptart_parser_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def parse_cvss_vector(hit, cvss_type):
return None


def parse_retest_fix_status(status):
def parse_retest_status(status):
fix_status_mapping = {
"F": "Fixed",
"NF": "Not Fixed",
Expand All @@ -75,7 +75,8 @@ def parse_retest_fix_status(status):
def parse_screenshots_from_hit(hit):
if "screenshots" not in hit:
return []
screenshots = [parse_screenshot_data(screenshot) for screenshot in hit["screenshots"]]
screenshots = [parse_screenshot_data(screenshot)
for screenshot in hit["screenshots"]]
return [ss for ss in screenshots if ss is not None]


Expand All @@ -100,21 +101,25 @@ def get_screenshot_title(screenshot):


def get_screenshot_data(screenshot):
if "screenshot" not in screenshot or "data" not in screenshot["screenshot"] or not screenshot["screenshot"]["data"]:
if ("screenshot" not in screenshot
or "data" not in screenshot["screenshot"]
or not screenshot["screenshot"]["data"]):
raise ValueError("Screenshot data not found")
return screenshot["screenshot"]["data"]


def get_file_suffix_from_screenshot(screenshot):
return pathlib.Path(screenshot['screenshot']['filename']).suffix \
if "screenshot" in screenshot and "filename" in screenshot['screenshot'] \
if ("screenshot" in screenshot
and "filename" in screenshot['screenshot']) \
else ""


def parse_attachment_from_hit(hit):
if "attachments" not in hit:
return []
files = [parse_attachment_data(attachment) for attachment in hit["attachments"]]
files = [parse_attachment_data(attachment)
for attachment in hit["attachments"]]
return [f for f in files if f is not None]


Expand All @@ -138,7 +143,9 @@ def get_attachment_data(attachment):


def get_attachement_title(attachment):
return attachment.get("title", "attachment") if "title" in attachment and attachment["title"] else "attachment"
return attachment.get("title", "attachment") \
if "title" in attachment and attachment["title"] \
else "attachment"


def parse_endpoints_from_hit(hit):
Expand All @@ -148,7 +155,10 @@ def parse_endpoints_from_hit(hit):
return [endpoint]


def generate_test_description_from_report_base(data):
def generate_test_description_from_report(data):
keys = ["executive_summary", "engagement_overview", "conclusion"]
description = "\n\n".join(data[key] for key in keys if key in data and data[key])
description = "\n\n".join(data[key]
for key in keys
if key in data and data[key]
)
return description if description else None
44 changes: 30 additions & 14 deletions dojo/tools/ptart/retest_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def generate_retest_hit_title(hit, original_hit):
title = original_hit.get("title", "")
hit_id = hit.get("id", None)
if "status" in hit:
title = f"{title} ({ptart_tools.parse_retest_fix_status(hit['status'])})"
title = f"{title} ({ptart_tools.parse_retest_status(hit['status'])})"
fake_retest_hit = {
"title": title,
"id": hit_id,
Expand All @@ -28,7 +28,8 @@ def get_test_data(self, tree):
else:
return []

return [finding for retest in retests for finding in self.parse_retest(retest)]
return [finding for retest in retests
for finding in self.parse_retest(retest)]

def parse_retest(self, retest):
hits = retest.get("hits", [])
Expand All @@ -39,26 +40,35 @@ def parse_retest(self, retest):

def get_finding(self, retest, hit):

# The negatives are a bit confusing, but we want to skip hits that don't have an original hit.
# Hit is invalid in a retest if not linked to an original.
# The negatives are a bit confusing, but we want to skip hits that
# don't have an original hit. Hit is invalid in a retest if not linked
# to an original.
if "original_hit" not in hit or not hit["original_hit"]:
return None

# Get the original hit from the retest
original_hit = hit["original_hit"]

# Set the Finding title to the original hit title with the retest status if available
# We don't really have any other places to set this field.
# Set the Finding title to the original hit title with the retest
# status if available. We don't really have any other places to set
# this field.
finding_title = generate_retest_hit_title(hit, original_hit)

# As the retest hit doesn't have a date added, use the start of the retest campaign as something that's
# close enough.
# As the retest hit doesn't have a date added, use the start of the
# retest campaign as something that's close enough.
finding = Finding(
title=finding_title,
severity=ptart_tools.parse_ptart_severity(original_hit.get("severity", 5)),
effort_for_fixing=ptart_tools.parse_ptart_fix_effort(original_hit.get("fix_complexity", 3)),
severity=ptart_tools.parse_ptart_severity(
original_hit.get("severity")
),
effort_for_fixing=ptart_tools.parse_ptart_fix_effort(
original_hit.get("fix_complexity")
),
component_name=f"Retest: {retest.get('name', 'Retest')}",
date=ptart_tools.parse_date(retest.get("start_date"), "%Y-%m-%d"),
date=ptart_tools.parse_date(
retest.get("start_date"),
"%Y-%m-%d"
),
)

# Don't add the fields if they are blank.
Expand All @@ -71,16 +81,22 @@ def get_finding(self, retest, hit):
if "id" in hit and hit["id"]:
finding.unique_id_from_tool = hit.get("id")

cvss_vector = ptart_tools.parse_cvss_vector(original_hit, self.cvss_type)
cvss_vector = ptart_tools.parse_cvss_vector(
original_hit,
self.cvss_type
)
if cvss_vector:
finding.cvssv3 = cvss_vector

if "labels" in original_hit:
finding.unsaved_tags = original_hit["labels"]

finding.unsaved_endpoints = ptart_tools.parse_endpoints_from_hit(original_hit)
finding.unsaved_endpoints = ptart_tools.parse_endpoints_from_hit(
original_hit
)

# We only have screenshots in a retest. Refer to the original hit for the attachments.
# We only have screenshots in a retest. Refer to the original hit for
# the attachments.
finding.unsaved_files = ptart_tools.parse_screenshots_from_hit(hit)

return finding
38 changes: 19 additions & 19 deletions unittests/tools/test_ptart_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,21 @@ def test_ptart_parser_tools_cvss_vector_acquisition(self):
self.assertEqual(None, parse_cvss_vector(hit, 3))

def test_ptart_parser_tools_retest_fix_status_parse(self):
from dojo.tools.ptart.ptart_parser_tools import parse_retest_fix_status
from dojo.tools.ptart.ptart_parser_tools import parse_retest_status
with self.subTest("Fixed"):
self.assertEqual("Fixed", parse_retest_fix_status("F"))
self.assertEqual("Fixed", parse_retest_status("F"))
with self.subTest("Not Fixed"):
self.assertEqual("Not Fixed", parse_retest_fix_status("NF"))
self.assertEqual("Not Fixed", parse_retest_status("NF"))
with self.subTest("Partially Fixed"):
self.assertEqual("Partially Fixed", parse_retest_fix_status("PF"))
self.assertEqual("Partially Fixed", parse_retest_status("PF"))
with self.subTest("Not Applicable"):
self.assertEqual("Not Applicable", parse_retest_fix_status("NA"))
self.assertEqual("Not Applicable", parse_retest_status("NA"))
with self.subTest("Not Tested"):
self.assertEqual("Not Tested", parse_retest_fix_status("NT"))
self.assertEqual("Not Tested", parse_retest_status("NT"))
with self.subTest("Unknown"):
self.assertEqual(None, parse_retest_fix_status("U"))
self.assertEqual(None, parse_retest_status("U"))
with self.subTest("Empty"):
self.assertEqual(None, parse_retest_fix_status(""))
self.assertEqual(None, parse_retest_status(""))

def test_ptart_parser_tools_parse_screenshots_from_hit(self):
from dojo.tools.ptart.ptart_parser_tools import parse_screenshots_from_hit
Expand Down Expand Up @@ -290,68 +290,68 @@ def test_ptart_parser_tools_parse_attachment_from_hit(self):
self.assertTrue(attachment["data"] == "TUlUIExpY2Vuc2UKCkNvcHl", "Invalid Attachment Data")

def test_ptart_parser_tools_get_description_from_report_base(self):
from dojo.tools.ptart.ptart_parser_tools import generate_test_description_from_report_base
from dojo.tools.ptart.ptart_parser_tools import generate_test_description_from_report
with self.subTest("No Description"):
data = {}
self.assertEqual(None, generate_test_description_from_report_base(data))
self.assertEqual(None, generate_test_description_from_report(data))
with self.subTest("Description from Executive Summary Only"):
data = {
"executive_summary": "This is a summary"
}
self.assertEqual("This is a summary", generate_test_description_from_report_base(data))
self.assertEqual("This is a summary", generate_test_description_from_report(data))
with self.subTest("Description from Engagement Overview Only"):
data = {
"engagement_overview": "This is an overview"
}
self.assertEqual("This is an overview", generate_test_description_from_report_base(data))
self.assertEqual("This is an overview", generate_test_description_from_report(data))
with self.subTest("Description from Conclusion Only"):
data = {
"conclusion": "This is a conclusion"
}
self.assertEqual("This is a conclusion", generate_test_description_from_report_base(data))
self.assertEqual("This is a conclusion", generate_test_description_from_report(data))
with self.subTest("Description from All Sections"):
data = {
"executive_summary": "This is a summary",
"engagement_overview": "This is an overview",
"conclusion": "This is a conclusion"
}
self.assertEqual("This is a summary\n\nThis is an overview\n\nThis is a conclusion",
generate_test_description_from_report_base(data))
generate_test_description_from_report(data))
with self.subTest("Description from Executive Summary and Conclusion"):
data = {
"executive_summary": "This is a summary",
"conclusion": "This is a conclusion"
}
self.assertEqual("This is a summary\n\nThis is a conclusion",
generate_test_description_from_report_base(data))
generate_test_description_from_report(data))
with self.subTest("Description from Executive Summary and Engagement Overview"):
data = {
"executive_summary": "This is a summary",
"engagement_overview": "This is an overview"
}
self.assertEqual("This is a summary\n\nThis is an overview",
generate_test_description_from_report_base(data))
generate_test_description_from_report(data))
with self.subTest("Description from Engagement Overview and Conclusion"):
data = {
"engagement_overview": "This is an overview",
"conclusion": "This is a conclusion"
}
self.assertEqual("This is an overview\n\nThis is a conclusion",
generate_test_description_from_report_base(data))
generate_test_description_from_report(data))
with self.subTest("Description from All Sections with Empty Strings"):
data = {
"executive_summary": "",
"engagement_overview": "",
"conclusion": ""
}
self.assertEqual(None, generate_test_description_from_report_base(data))
self.assertEqual(None, generate_test_description_from_report(data))
with self.subTest("Description with Some Blank Strings"):
data = {
"executive_summary": "",
"engagement_overview": "This is an overview",
"conclusion": ""
}
self.assertEqual("This is an overview", generate_test_description_from_report_base(data))
self.assertEqual("This is an overview", generate_test_description_from_report(data))

def test_ptart_parser_with_empty_json_throws_error(self):
with open("unittests/scans/ptart/empty_with_error.json") as testfile:
Expand Down

0 comments on commit fae4b81

Please sign in to comment.