Skip to content

Commit a3142a5

Browse files
committed
openscap: also importing description and rationale
1 parent 6b0f0c5 commit a3142a5

File tree

1 file changed

+32
-11
lines changed

1 file changed

+32
-11
lines changed

dojo/tools/openscap/parser.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import hashlib
22
import re
3+
import html2text
4+
import defusedxml.ElementTree as ET
35

4-
from defusedxml.ElementTree import parse
56
from django.core.exceptions import ValidationError
67
from django.core.validators import validate_ipv46_address
78

@@ -19,7 +20,7 @@ def get_description_for_scan_types(self, scan_type):
1920
return "Import Openscap Vulnerability Scan in XML formats."
2021

2122
def get_findings(self, file, test):
22-
tree = parse(file)
23+
tree = ET.parse(file)
2324
# get root of tree.
2425
root = tree.getroot()
2526
namespace = self.get_namespace(root)
@@ -35,8 +36,22 @@ def get_findings(self, file, test):
3536
# read rules
3637
rules = {}
3738
for rule in root.findall(f".//{namespace}Rule"):
39+
# get description and rationale (contains html codes)
40+
desc_elem = rule.find(f"./{namespace}description")
41+
rationale_elem = rule.find(f"./{namespace}rationale")
42+
description_html = ET.tostring(desc_elem, encoding='unicode', method='xml') if desc_elem is not None else "none"
43+
rationale_html = ET.tostring(rationale_elem, encoding='unicode', method='xml') if rationale_elem is not None else "none"
44+
# remove xml-html namespace
45+
description_html = re.sub(r'</?html:(\w+)', r'<\1', description_html)
46+
rationale_html = re.sub(r'</?html:(\w+)', r'<\1', rationale_html)
47+
# remove newlines (DefectDojo already breaks lines)
48+
description_html = re.sub(r'[\r\n]+', ' ', description_html)
49+
rationale_html = re.sub(r'[\r\n]+', ' ', rationale_html)
50+
3851
rules[rule.attrib["id"]] = {
3952
"title": rule.findtext(f"./{namespace}title"),
53+
"description": html2text.html2text(description_html),
54+
"rationale": html2text.html2text(rationale_html),
4055
}
4156
# go to test result
4257
test_result = tree.find(f"./{namespace}TestResult")
@@ -54,12 +69,19 @@ def get_findings(self, file, test):
5469
# find only failed report.
5570
if "fail" in result:
5671
# get rule corresponding to rule-result
57-
rule = rules[rule_result.attrib["idref"]]
72+
ruleid = rule_result.attrib["idref"]
73+
rule = rules[ruleid]
5874
title = rule["title"]
75+
desc = rule["description"]
76+
rat = rule["rationale"]
5977
description = "\n".join(
6078
[
61-
"**IdRef:** `" + rule_result.attrib["idref"] + "`",
79+
"**IdRef:** `" + ruleid + "`",
6280
"**Title:** `" + title + "`",
81+
"**Description:** ",
82+
desc,
83+
"**Rationale:** ",
84+
rat,
6385
],
6486
)
6587
vulnerability_ids = [vulnerability_id.text for vulnerability_id in rule_result.findall(
@@ -74,16 +96,15 @@ def get_findings(self, file, test):
7496
# according to the spec 'unknown' is a possible value
7597
if severity == "Unknown":
7698
severity = "Info"
77-
references = ""
7899
# get references.
79100
for check_content in rule_result.findall(
80101
f"./{namespace}check/{namespace}check-content-ref",
81102
):
82-
references += (
83-
"**name:** : " + check_content.attrib["name"] + "\n"
84-
)
85-
references += (
86-
"**href** : " + check_content.attrib["href"] + "\n"
103+
references = "\n".join(
104+
[
105+
"**name:** : " + check_content.attrib["name"],
106+
"**href** : " + check_content.attrib["href"],
107+
],
87108
)
88109

89110
finding = Finding(
@@ -93,7 +114,7 @@ def get_findings(self, file, test):
93114
references=references,
94115
dynamic_finding=True,
95116
static_finding=False,
96-
unique_id_from_tool=rule_result.attrib["idref"],
117+
unique_id_from_tool=ruleid,
97118
)
98119
if vulnerability_ids:
99120
finding.unsaved_vulnerability_ids = vulnerability_ids

0 commit comments

Comments
 (0)