Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add affected-versions to all formats (#1342) #1667

Merged
merged 23 commits into from
Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ffba885
Updated spelling.yml
XDRAGON2002 Dec 29, 2021
c191f20
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Dec 30, 2021
576871b
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Jan 6, 2022
5707392
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Jan 7, 2022
63981f0
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Jan 26, 2022
ad0032f
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Jan 27, 2022
a38777e
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Jan 29, 2022
db3e815
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Feb 7, 2022
e3d5602
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Mar 1, 2022
eadbc73
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Mar 6, 2022
a23f5c3
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Mar 12, 2022
2b5759a
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Mar 16, 2022
8723ee4
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Mar 18, 2022
dd8c8d3
Merge branch 'main' of https://github.com/intel/cve-bin-tool into main
XDRAGON2002 Mar 26, 2022
abdaa33
Merge branch 'main' of https://github.com/intel/cve-bin-tool into iss…
XDRAGON2002 May 10, 2022
a854b62
feat: add affected-versions to all formats
XDRAGON2002 May 13, 2022
4a9fd30
test: update tests
XDRAGON2002 Jun 15, 2022
617c844
Merge branch 'main' into issue_1342
XDRAGON2002 Jun 15, 2022
2fac01e
"test: update tests"
XDRAGON2002 Jun 15, 2022
21444db
Merge branch 'main' into issue_1342
terriko Jun 16, 2022
e5fd70e
fix: output_pdf
XDRAGON2002 Jun 27, 2022
9bc5756
fix: resolve merge conflict
XDRAGON2002 Jun 27, 2022
cd33adb
fix: resolve merge conflict
XDRAGON2002 Jun 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cve_bin_tool/available_fix/debian_cve_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def cve_info(
):
"""Produces the Backported fixes' info"""

cve_data = format_output(all_cve_data)
cve_data = format_output(all_cve_data, None)
json_data = self.get_data()
for cve in cve_data:
try:
Expand Down
2 changes: 1 addition & 1 deletion cve_bin_tool/available_fix/redhat_cve_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def cve_info(
):
"""Produces the available fixes' info"""

cve_data = format_output(all_cve_data)
cve_data = format_output(all_cve_data, None)
for cve in cve_data:
if cve["cve_number"] != "UNKNOWN":
json_data = self.get_data(cve["cve_number"], cve["product"])
Expand Down
73 changes: 60 additions & 13 deletions cve_bin_tool/output_engine/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,38 @@
import time
from datetime import datetime
from logging import Logger
from typing import IO, Dict, List, Union
from typing import IO, Dict, List, Optional, Union

from ..cve_scanner import CVEData
from ..cvedb import CVEDB
from ..error_handler import ErrorHandler, ErrorMode
from ..log import LOGGER
from ..util import ProductInfo, Remarks
from ..util import ProductInfo, Remarks, VersionInfo
from ..version import VERSION
from .console import output_console
from .html import output_html
from .util import (
add_extension_if_not,
format_output,
format_path,
format_version_range,
generate_filename,
get_cve_summary,
intermediate_output,
)


def output_json(
all_cve_data: Dict[ProductInfo, CVEData], outfile: IO, detailed: bool = False
all_cve_data: Dict[ProductInfo, CVEData],
all_cve_version_info: Optional[Dict[str, VersionInfo]],
outfile: IO,
detailed: bool = False,
affected_versions: int = 0,
):
"""Output a JSON of CVEs"""
formatted_output = format_output(all_cve_data, detailed)
formatted_output = format_output(
all_cve_data, all_cve_version_info, detailed, affected_versions
)
json.dump(formatted_output, outfile, indent=" ")


Expand Down Expand Up @@ -59,10 +66,16 @@ def save_intermediate(


def output_csv(
all_cve_data: Dict[ProductInfo, CVEData], outfile, detailed: bool = False
all_cve_data: Dict[ProductInfo, CVEData],
all_cve_version_info: Optional[Dict[str, VersionInfo]],
outfile,
detailed: bool = False,
affected_versions: int = 0,
):
"""Output a CSV of CVEs"""
formatted_output = format_output(all_cve_data, detailed)
formatted_output = format_output(
all_cve_data, all_cve_version_info, detailed, affected_versions
)

# Trim any leading -, =, +, @, tab or CR to avoid excel macros
for cve_entry in formatted_output:
Expand All @@ -87,6 +100,8 @@ def output_csv(
)
if detailed:
writer.fieldnames.append("description")
if affected_versions != 0:
writer.fieldnames.append("affected_versions")
writer.writeheader()
writer.writerows(formatted_output)

Expand All @@ -100,8 +115,10 @@ def output_pdf(
all_cve_data: Dict[ProductInfo, CVEData],
is_report,
products_with_cve,
all_cve_version_info,
outfile,
merge_report,
affected_versions: int = 0,
exploits: bool = False,
):
"""Output a PDF of CVEs"""
Expand Down Expand Up @@ -255,11 +272,16 @@ def output_pdf(
pdfdoc.paragraph(
"The following vulnerabilities are reported against the identified versions of the libraries."
)
col_headings = ["Vendor", "Product", "Version", "CVE Number", "Severity"]
col_dist = [10, 10, None, None, None]
if affected_versions != 0:
col_headings.append("Affected Versions")
col_dist.append(None)
pdfdoc.createtable(
"Productlist",
["Vendor", "Product", "Version", "CVE Number", "Severity"],
col_headings,
pdfdoc.tblStyle,
[10, 10, None, None, None],
col_dist,
)
row = 1
star_warn = False
Expand All @@ -275,6 +297,12 @@ def output_pdf(
cve.cve_number,
cve.severity,
]
if affected_versions != 0:
try:
version_info = all_cve_version_info[cve.cve_number]
except KeyError: # TODO: handle 'UNKNOWN' and some cves more cleanly
version_info = VersionInfo("", "", "", "")
entry.append(format_version_range(version_info))
pdfdoc.addrow(
"Productlist",
entry,
Expand All @@ -297,9 +325,10 @@ def output_pdf(
)
row += 1

pdfdoc.showtable(
"Productlist", widths=[3 * cm, 3 * cm, 2 * cm, 4 * cm, 5 * cm]
)
widths = [3 * cm, 3 * cm, 2 * cm, 4 * cm, 5 * cm]
if affected_versions != 0:
widths.append(4 * cm)
pdfdoc.showtable("Productlist", widths=widths)
pdfdoc.paragraph("* vendors guessed by the tool") if star_warn else None

pdfdoc.heading(1, "List of Vulnerabilities mapped to Components")
Expand Down Expand Up @@ -369,8 +398,10 @@ def output_pdf(
all_cve_data: Dict[ProductInfo, CVEData],
is_report,
products_with_cve,
all_cve_version_info,
outfile,
merge_report,
affected_versions,
exploits: bool = False,
):
LOGGER.warning("PDF output requires install of reportlab")
Expand Down Expand Up @@ -423,21 +454,36 @@ def output_cves(self, outfile, output_type="console"):
to other formats like CSV or JSON
"""
if output_type == "json":
output_json(self.all_cve_data, outfile, self.detailed)
output_json(
self.all_cve_data,
self.all_cve_version_info,
outfile,
self.detailed,
self.affected_versions,
)
elif output_type == "csv":
output_csv(self.all_cve_data, outfile, self.detailed)
output_csv(
self.all_cve_data,
self.all_cve_version_info,
outfile,
self.detailed,
self.affected_versions,
)
elif output_type == "pdf":
output_pdf(
self.all_cve_data,
self.is_report,
self.products_with_cve,
self.all_cve_version_info,
outfile,
self.merge_report,
self.affected_versions,
self.exploits,
)
elif output_type == "html":
output_html(
self.all_cve_data,
self.all_cve_version_info,
self.scanned_dir,
self.filename,
self.themes_dir,
Expand All @@ -447,6 +493,7 @@ def output_cves(self, outfile, output_type="console"):
self.merge_report,
self.logger,
outfile,
self.affected_versions,
)
else: # console, or anything else that is unrecognised
output_console(
Expand Down
42 changes: 1 addition & 41 deletions cve_bin_tool/output_engine/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,47 +18,7 @@
from ..theme import cve_theme
from ..util import ProductInfo, VersionInfo
from ..version import VERSION
from .util import format_path, get_cve_summary


def format_version_range(version_info: VersionInfo) -> str:
"""
Format version info to desirable output

Example:
```
format_version_range('', '', '', '') => "-"
format_version_range('2.2.8', '', '2.2.11', '') => "[2.2.8 - 2.2.11]"
format_version_range('2.2.8', '', '', '2.2.11') => "[2.2.8 - 2.2.11)"
format_version_range('', '2.2.8', '2.2.11', '') => "(2.2.8 - 2.2.11]"
format_version_range('', '2.2.8', '', '2.2.11') => "(2.2.8 - 2.2.11])"
format_version_range('2.2.8', '', '', '') => ">= 2.2.8"
format_version_range('', '2.2.8', '', '') => "> 2.2.8"
format_version_range('', '', '2.2.11', '') => "<= 2.2.11"
format_version_range('', '', '', '2.2.11') => "< 2.2.11"
```

Reference for Interval terminologies: https://en.wikipedia.org/wiki/Interval_(mathematics)
"""

(start_including, start_excluding, end_including, end_excluding) = version_info
if start_including and end_including:
return f"[{start_including} - {end_including}]"
if start_including and end_excluding:
return f"[{start_including} - {end_excluding})"
if start_excluding and end_including:
return f"({start_excluding} - {end_including}]"
if start_excluding and end_excluding:
return f"({start_excluding} - {end_excluding})"
if start_including:
return f">= {start_including}"
if start_excluding:
return f"> {start_excluding}"
if end_including:
return f"<= {end_including}"
if end_excluding:
return f"< {end_excluding}"
return "-"
from .util import format_path, format_version_range, get_cve_summary


def output_console(*args: Any):
Expand Down
8 changes: 6 additions & 2 deletions cve_bin_tool/output_engine/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
from collections import Counter, defaultdict
from datetime import datetime
from typing import Dict, List, Union
from typing import Dict, List, Optional, Union

import plotly.graph_objects as go
from jinja2 import Environment, FileSystemLoader, select_autoescape
Expand All @@ -13,7 +13,7 @@
from cve_bin_tool.merge import MergeReports

from ..log import LOGGER
from ..util import CVEData, ProductInfo, Remarks
from ..util import CVEData, ProductInfo, Remarks, VersionInfo
from ..version import VERSION
from .print_mode import html_print_mode
from .util import group_cve_by_remark
Expand Down Expand Up @@ -59,6 +59,7 @@ def render_cves(

def output_html(
all_cve_data: Dict[ProductInfo, CVEData],
all_cve_version_info: Optional[Dict[str, VersionInfo]],
scanned_dir: str,
filename: str,
theme_dir: str,
Expand All @@ -68,6 +69,7 @@ def output_html(
merge_report: Union[None, MergeReports],
logger: LOGGER,
outfile,
affected_versions: int = 0,
):
"""Returns a HTML report for CVE's"""

Expand Down Expand Up @@ -347,6 +349,7 @@ def output_html(
all_paths=all_paths,
print_mode=html_print_mode(
all_cve_data,
all_cve_version_info,
scanned_dir,
products_with_cve,
products_without_cve,
Expand All @@ -355,6 +358,7 @@ def output_html(
merge_report,
version=VERSION,
full_html=False,
affected_versions=affected_versions,
),
products_found="".join(products_found),
version=VERSION,
Expand Down
15 changes: 12 additions & 3 deletions cve_bin_tool/output_engine/print_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@

import os
from datetime import datetime
from typing import Union
from typing import Dict, Optional, Union

from jinja2 import Environment, FileSystemLoader, select_autoescape

from cve_bin_tool.merge import MergeReports

from ..util import CVEData
from ..util import CVEData, VersionInfo
from .util import format_version_range


def html_print_mode(
all_cve_data: CVEData,
all_cve_version_info: Optional[Dict[str, VersionInfo]],
directory: str,
products_with_cve: int,
products_without_cve: int,
Expand All @@ -22,6 +24,7 @@ def html_print_mode(
merge_report: Union[None, MergeReports],
version: str,
full_html: bool = True,
affected_versions: int = 0,
) -> str:

root = os.path.dirname(os.path.abspath(__file__))
Expand Down Expand Up @@ -61,7 +64,13 @@ def html_print_mode(
)
rendered_report.append(
content.render(
all_cve_data=all_cve_data, directory=directory, star_warn=star_warn
all_cve_data=all_cve_data,
all_cve_version_info=all_cve_version_info,
directory=directory,
star_warn=star_warn,
affected_versions=affected_versions,
format_version_range=format_version_range,
VersionInfo=VersionInfo,
)
)

Expand Down
6 changes: 6 additions & 0 deletions cve_bin_tool/output_engine/print_mode/templates/content.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,19 @@
<th>Description</th>
<th>Severity</th>
<th>Remarks</th>
{% if affected_versions != 0 %}
<th>Affected Versions</th>
{% endif %}
</tr>
{% for cve in cve_data['cves'] %}
<tr>
<td>{{ cve.cve_number }}</td>
<td>{{ cve.description }}</td>
<td>{{ cve.severity }}</td>
<td>{{ cve.remarks }}</td>
{% if affected_versions != 0 %}
<td>{{ format_version_range(all_cve_version_info[cve.cve_number] if cve.cve_number in all_cve_version_info else VersionInfo("", "", "", "")) }}</td>
{% endif %}
</tr>
{% endfor %}
</table>
Expand Down
Loading