139 lines
3.8 KiB
Python
139 lines
3.8 KiB
Python
import sys
|
|
|
|
from uaclient import exceptions, messages
|
|
from uaclient.api.u.pro.security.cves.v1 import CVEsOptions, _cves
|
|
from uaclient.cli import cli_util
|
|
from uaclient.cli.commands import ProArgument, ProArgumentGroup, ProCommand
|
|
from uaclient.cli.formatter import Table, create_link
|
|
from uaclient.cli.parser import HelpCategory
|
|
from uaclient.config import UAConfig
|
|
|
|
|
|
@cli_util.with_spinner(msg=messages.CLI_CVES_SPINNER_MSG)
|
|
def _get_cve_vulnerabilities(args, *, cfg: UAConfig, **kwargs):
|
|
cve_options = CVEsOptions(
|
|
fixable=args.fixable,
|
|
unfixable=args.unfixable,
|
|
)
|
|
|
|
try:
|
|
result = _cves(options=cve_options, cfg=cfg)
|
|
except exceptions.VulnerabilityDataNotFound:
|
|
result = None
|
|
|
|
return result
|
|
|
|
|
|
def _get_cve_table_rows(cve_vulnerabilities):
|
|
rows = []
|
|
|
|
for package_name, package_info in cve_vulnerabilities.packages.items():
|
|
for cve in package_info.cves:
|
|
cve_info = cve_vulnerabilities.cves.get(cve.name)
|
|
|
|
if cve_info:
|
|
rows.append(
|
|
(
|
|
package_name,
|
|
cve_info.priority,
|
|
cve.fix_origin or "-",
|
|
cve.name,
|
|
)
|
|
)
|
|
|
|
return rows
|
|
|
|
|
|
def _format_cve_rows(cve_rows):
|
|
formatted_rows = []
|
|
for row in sorted(
|
|
cve_rows,
|
|
key=lambda row: (
|
|
row[0],
|
|
("critical", "high", "medium", "low", "negligible").index(row[1]),
|
|
),
|
|
):
|
|
formatted_rows.append(
|
|
(
|
|
row[0],
|
|
cli_util.colorize_priority(row[1]),
|
|
row[2],
|
|
create_link(
|
|
text=row[3],
|
|
url="https://ubuntu.com/security/{}".format(row[3]),
|
|
),
|
|
)
|
|
)
|
|
|
|
return formatted_rows
|
|
|
|
|
|
def _list_cves(args, cfg: UAConfig):
|
|
cve_vulnerabilities = _get_cve_vulnerabilities(args, cfg=cfg)
|
|
|
|
if not cve_vulnerabilities:
|
|
raise exceptions.VulnerabilityDataNotFound()
|
|
|
|
if cve_vulnerabilities.packages:
|
|
rows = _format_cve_rows(_get_cve_table_rows(cve_vulnerabilities))
|
|
|
|
if rows:
|
|
print(
|
|
Table(
|
|
headers=["Package", "Priority", "Origin", "Vulnerability"],
|
|
rows=rows,
|
|
)
|
|
)
|
|
else:
|
|
if args.unfixable:
|
|
print(messages.CLI_UNFIXABLE_CVES_NOT_AFFECTED)
|
|
elif args.fixable:
|
|
print(messages.CLI_FIXABLE_CVES_NOT_AFFECTED)
|
|
else:
|
|
print(messages.CLI_CVES_NOT_AFFECTED)
|
|
else:
|
|
if args.unfixable:
|
|
print(messages.CLI_UNFIXABLE_CVES_NOT_AFFECTED)
|
|
elif args.fixable:
|
|
print(messages.CLI_FIXABLE_CVES_NOT_AFFECTED)
|
|
else:
|
|
print(messages.CLI_CVES_NOT_AFFECTED)
|
|
|
|
|
|
def action_cves(args, *, cfg: UAConfig, **kwargs):
|
|
if args.unfixable and args.fixable:
|
|
raise exceptions.InvalidOptionCombination(
|
|
option1="unfixable", option2="fixable"
|
|
)
|
|
|
|
try:
|
|
_list_cves(args=args, cfg=cfg)
|
|
except BrokenPipeError:
|
|
sys.stderr.close()
|
|
|
|
|
|
cves_command = ProCommand(
|
|
"cves",
|
|
help=messages.CLI_CVES,
|
|
description=messages.CLI_CVES_DESC,
|
|
action=action_cves,
|
|
help_category=HelpCategory.SECURITY,
|
|
preserve_description=True,
|
|
argument_groups=[
|
|
ProArgumentGroup(
|
|
arguments=[
|
|
ProArgument(
|
|
"--unfixable",
|
|
help=messages.CLI_CVES_UNFIXABLE,
|
|
action="store_true",
|
|
),
|
|
ProArgument(
|
|
"--fixable",
|
|
help=messages.CLI_CVES_FIXABLE,
|
|
action="store_true",
|
|
),
|
|
]
|
|
)
|
|
],
|
|
)
|