1
1
import hashlib
2
2
import re
3
+ import html2text
4
+ import defusedxml .ElementTree as ElementTree
3
5
4
- from defusedxml .ElementTree import parse
5
6
from django .core .exceptions import ValidationError
6
7
from django .core .validators import validate_ipv46_address
7
8
@@ -19,7 +20,7 @@ def get_description_for_scan_types(self, scan_type):
19
20
return "Import Openscap Vulnerability Scan in XML formats."
20
21
21
22
def get_findings (self , file , test ):
22
- tree = parse (file )
23
+ tree = ElementTree . parse (file )
23
24
# get root of tree.
24
25
root = tree .getroot ()
25
26
namespace = self .get_namespace (root )
@@ -35,8 +36,22 @@ def get_findings(self, file, test):
35
36
# read rules
36
37
rules = {}
37
38
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 = ElementTree .tostring (desc_elem , encoding = "unicode" , method = "xml" ) if desc_elem is not None else "none"
43
+ rationale_html = ElementTree .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
+
38
51
rules [rule .attrib ["id" ]] = {
39
52
"title" : rule .findtext (f"./{ namespace } title" ),
53
+ "description" : html2text .html2text (description_html ),
54
+ "rationale" : html2text .html2text (rationale_html ),
40
55
}
41
56
# go to test result
42
57
test_result = tree .find (f"./{ namespace } TestResult" )
@@ -54,12 +69,19 @@ def get_findings(self, file, test):
54
69
# find only failed report.
55
70
if "fail" in result :
56
71
# get rule corresponding to rule-result
57
- rule = rules [rule_result .attrib ["idref" ]]
72
+ ruleid = rule_result .attrib ["idref" ]
73
+ rule = rules [ruleid ]
58
74
title = rule ["title" ]
75
+ desc = rule ["description" ]
76
+ rat = rule ["rationale" ]
59
77
description = "\n " .join (
60
78
[
61
- "**IdRef:** `" + rule_result . attrib [ "idref" ] + "`" ,
79
+ "**IdRef:** `" + ruleid + "`" ,
62
80
"**Title:** `" + title + "`" ,
81
+ "**Description:** " ,
82
+ desc ,
83
+ "**Rationale:** " ,
84
+ rat ,
63
85
],
64
86
)
65
87
vulnerability_ids = [vulnerability_id .text for vulnerability_id in rule_result .findall (
@@ -74,16 +96,15 @@ def get_findings(self, file, test):
74
96
# according to the spec 'unknown' is a possible value
75
97
if severity == "Unknown" :
76
98
severity = "Info"
77
- references = ""
78
99
# get references.
79
100
for check_content in rule_result .findall (
80
101
f"./{ namespace } check/{ namespace } check-content-ref" ,
81
102
):
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
+ ],
87
108
)
88
109
89
110
finding = Finding (
@@ -93,7 +114,7 @@ def get_findings(self, file, test):
93
114
references = references ,
94
115
dynamic_finding = True ,
95
116
static_finding = False ,
96
- unique_id_from_tool = rule_result . attrib [ "idref" ] ,
117
+ unique_id_from_tool = ruleid ,
97
118
)
98
119
if vulnerability_ids :
99
120
finding .unsaved_vulnerability_ids = vulnerability_ids
0 commit comments