Skip to content

Commit a098ef0

Browse files
authored
feat: include EPSS metrics in output PDF (#3213)
* feat: output PDF * feat: adding test case * fix: removing bug
1 parent 2757e66 commit a098ef0

File tree

2 files changed

+119
-1
lines changed

2 files changed

+119
-1
lines changed

cve_bin_tool/output_engine/__init__.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,74 @@ def output_pdf(
468468
"Applicationlist", widths=[3 * cm, 3 * cm, 2 * cm, 4 * cm, 3 * cm]
469469
)
470470

471+
pdfdoc.heading(1, "List of Vulnerabilities with different metric")
472+
pdfdoc.paragraph(
473+
"The table given below gives CVE found with there score on different metrics."
474+
)
475+
cve_by_metrics: defaultdict[Remarks, list[dict[str, str]]] = defaultdict(
476+
list
477+
)
478+
col_headings = [
479+
"CVE Number",
480+
"CVSS_version",
481+
"CVSS_score",
482+
"EPSS_propability",
483+
"EPSS_percentile",
484+
]
485+
# group cve_data by its remarks and separately by paths
486+
for product_info, cve_data in all_cve_data.items():
487+
for cve in cve_data["cves"]:
488+
propability = "-"
489+
percentile = "-"
490+
for metric, field in cve.metric.items():
491+
if metric == "EPSS":
492+
propability = round(field[0] * 100, 4)
493+
percentile = field[1]
494+
495+
cve_by_metrics[cve.remarks].append(
496+
{
497+
"cve_number": cve.cve_number,
498+
"cvss_version": str(cve.cvss_version),
499+
"cvss_score": str(cve.score),
500+
"epss_propability": str(propability),
501+
"epss_percentile": str(percentile),
502+
"severity": cve.severity,
503+
}
504+
)
505+
506+
for remarks in sorted(cve_by_metrics):
507+
pdfdoc.createtable(
508+
"cvemetric",
509+
col_headings,
510+
pdfdoc.tblStyle,
511+
)
512+
row = 1
513+
for cve in cve_by_metrics[remarks]:
514+
entry = [
515+
cve["cve_number"],
516+
cve["cvss_version"],
517+
str(cve["cvss_score"]),
518+
str(cve["epss_propability"]),
519+
str(cve["epss_percentile"]),
520+
]
521+
pdfdoc.addrow(
522+
"cvemetric",
523+
entry,
524+
[
525+
(
526+
"TEXTCOLOR",
527+
(0, row),
528+
(4, row),
529+
severity_colour[cve["severity"].split("-")[0].upper()],
530+
),
531+
("FONT", (0, row), (4, row), "Helvetica-Bold"),
532+
],
533+
)
534+
row += 1
535+
pdfdoc.showtable(
536+
"cvemetric", widths=[4 * cm, 4 * cm, 3 * cm, 4 * cm, 4 * cm]
537+
)
538+
471539
# List of scanned products with no identified vulnerabilities
472540
if all_product_data is not None:
473541
pdfdoc.heading(1, "No Identified Vulnerabilities")

test/test_output_engine.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ class TestOutputEngine(unittest.TestCase):
176176
cvss_version=2,
177177
cvss_vector="C:H",
178178
data_source="NVD",
179+
metric={
180+
"EPSS": [0.6932, "0.2938"],
181+
},
179182
),
180183
CVE(
181184
"CVE-1234-1234",
@@ -184,6 +187,9 @@ class TestOutputEngine(unittest.TestCase):
184187
cvss_version=2,
185188
cvss_vector="CVSS2.0/C:H",
186189
data_source="NVD",
190+
metric={
191+
"EPSS": [0.06084, "0.7936"],
192+
},
187193
),
188194
],
189195
paths={""},
@@ -198,7 +204,7 @@ class TestOutputEngine(unittest.TestCase):
198204
cvss_vector="CVSS3.0/C:H/I:L/A:M",
199205
data_source="NVD",
200206
metric={
201-
"EPSS": [0.0468, "0.34072"],
207+
"EPSS": [0.1646, "0.3955"],
202208
},
203209
)
204210
],
@@ -213,6 +219,7 @@ class TestOutputEngine(unittest.TestCase):
213219
cvss_version=2,
214220
cvss_vector="C:H/I:L/A:M",
215221
data_source="NVD",
222+
metric={"EPSS": [0.2059, "0.09260"]},
216223
)
217224
],
218225
paths={""},
@@ -665,6 +672,37 @@ class TestOutputEngine(unittest.TestCase):
665672
"Page 2"
666673
)
667674

675+
PDF_OUTPUT_2 = (
676+
"4. List of Vulnerabilities with different metric"
677+
"The table given below gives CVE found with there score on different metrics."
678+
"CVE Number"
679+
"CVSS_version"
680+
"CVSS_score"
681+
"EPSS_propability"
682+
"EPSS_percentile"
683+
"CVE-1234-1234"
684+
"2"
685+
"4.2"
686+
"69.32"
687+
"0.2938"
688+
"CVE-1234-1234"
689+
"2"
690+
"1.2"
691+
"6.084"
692+
"0.7936"
693+
"CVE-1234-1234"
694+
"3"
695+
"2.5"
696+
"16.46"
697+
"0.3955"
698+
"CVE-1234-1234"
699+
"2"
700+
"7.5"
701+
"20.59"
702+
"0.09260"
703+
"Page 3"
704+
)
705+
668706
VEX_FORMATTED_OUTPUT = [
669707
{
670708
"bomFormat": "CycloneDX",
@@ -864,6 +902,7 @@ def test_output_pdf(self):
864902
# Only interested in section 3 of the report which contains table of CVEs. This is on the second page
865903
page = pdf[1]
866904
# Find start of section 3 header
905+
867906
section2_start = page.find("3. List of Identified Vulnerabilities")
868907
self.assertEqual(
869908
page[section2_start:]
@@ -874,6 +913,17 @@ def test_output_pdf(self):
874913
self.PDF_OUTPUT.replace(" ", ""),
875914
)
876915

916+
page = pdf[2]
917+
section2_start = page.find("4. List of Vulnerabilities with different metric")
918+
self.assertEqual(
919+
page[section2_start:]
920+
.replace(" ", "")
921+
.replace("\r", "")
922+
.replace("\n", "")
923+
.strip(),
924+
self.PDF_OUTPUT_2.replace(" ", ""),
925+
)
926+
877927
def test_output_console(self):
878928
"""Test Formatting Output as console"""
879929

0 commit comments

Comments
 (0)