Skip to content

Commit

Permalink
cli: update fixable summary for list command
Browse files Browse the repository at this point in the history
Update how we display the fixable vulnerabilities
for the pro vulnerability list command. We are now
directly showing the number of fixable vulnerabilities
separated by the pocket that provides it, Ubuntu Pro or
Ubuntu Security
  • Loading branch information
lucasmoura committed Sep 30, 2024
1 parent ead4570 commit 994f9a2
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 53 deletions.
6 changes: 3 additions & 3 deletions features/cli/vulnerability_list.feature
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Feature: CLI vulnerability list command
13 applied via Ubuntu Security (2 high, 6 medium, 5 low)
Vulnerabilities with fixes available:
10 vulnerabilities found (3 high, 4 medium, 2 low, 1 negligible)
10 fixable via Ubuntu Pro (3 high, 4 medium, 2 low, 1 negligible)
"""
When I run `pro vulnerability list --all --data-file=/tmp/security_issues_xenial --manifest-file=/tmp/manifest` as non-root
And I remove colors from output
Expand Down Expand Up @@ -73,7 +73,7 @@ Feature: CLI vulnerability list command
13 applied via Ubuntu Security (2 high, 6 medium, 5 low)
Vulnerabilities with fixes available:
10 vulnerabilities found (3 high, 4 medium, 2 low, 1 negligible)
10 fixable via Ubuntu Pro (3 high, 4 medium, 2 low, 1 negligible)
Vulnerabilities with no fixes available:
9 unfixable vulnerabilities found (7 medium, 2 low)
Expand Down Expand Up @@ -116,7 +116,7 @@ Feature: CLI vulnerability list command
1 applied via Ubuntu Security
Vulnerabilities with fixes available:
5 vulnerabilities found
5 fixable via Ubuntu Pro
"""
When I create the file `/tmp/manifest` with the following:
"""
Expand Down
143 changes: 94 additions & 49 deletions uaclient/cli/vulnerability/list.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Dict, NamedTuple
import re
from typing import Any, Dict # noqa: F401

from uaclient import config, exceptions, messages
from uaclient.api.u.pro.security.vulnerabilities.cve.v1 import (
Expand All @@ -17,11 +18,6 @@
from uaclient.cli.formatter import Table
from uaclient.cli.vulnerability import util as vuln_util

VulnerabilityCountInfo = NamedTuple(
"VulnerabilityCountInfo",
[("count", int), ("count_by_priority", Dict[str, int])],
)


def _create_usn_table(usns, num_rows=None):
usns_sorted_by_name = sorted(usns, key=lambda usn: usn.name)
Expand Down Expand Up @@ -91,12 +87,12 @@ def _create_cve_table(cves, num_rows=None):
)


def _get_info_from_vulnerabilities(vulnerabilities, fixable_vuln: bool):
def _get_unfixable_info_from_vulnerabilities(vulnerabilities):
count = 0
vulnerability_count_info = {} # type: Dict[str, int]

for vuln in vulnerabilities:
if (vuln.fixable == "yes") is fixable_vuln:
if vuln.fixable != "yes":
count += 1

if not getattr(vuln, "ubuntu_priority", None):
Expand All @@ -107,32 +103,71 @@ def _get_info_from_vulnerabilities(vulnerabilities, fixable_vuln: bool):
else:
vulnerability_count_info[vuln.ubuntu_priority] = 1

return VulnerabilityCountInfo(
count=count,
count_by_priority=vulnerability_count_info,
)
return (count, vulnerability_count_info)


def _get_info_from_vulnerabilities(vulnerabilities):
vulnerability_count_info = {
"ubuntu_security": {"count": 0, "info": {}},
"ubuntu_pro": {
"count": 0,
"info": {},
},
} # type: Dict[str, Dict[str, Any]]

for vuln in vulnerabilities:
if vuln.fixable == "yes":
pocket = (
"ubuntu_pro"
if any(
pkg
for pkg in vuln.affected_packages
if re.match(
r"^(esm|fips)", pkg.fix_available_from or "no-fix"
)
)
else "ubuntu_security"
)
vulnerability_count_info[pocket]["count"] += 1

if not getattr(vuln, "ubuntu_priority", None):
continue

if (
vuln.ubuntu_priority
in vulnerability_count_info[pocket]["info"]
):
vulnerability_count_info[pocket]["info"][
vuln.ubuntu_priority
] += 1
else:
vulnerability_count_info[pocket]["info"][
vuln.ubuntu_priority
] = 1

def _get_fixable_color_count(fixable_vulnerabilities_info):
if "critical" in fixable_vulnerabilities_info.count_by_priority:
return vulnerability_count_info


def _get_fixable_color_count(pocket_info):
if "critical" in pocket_info["info"]:
main_color = messages.TxtColor.FAIL
elif "high" in fixable_vulnerabilities_info.count_by_priority:
elif "high" in pocket_info["info"]:
main_color = messages.TxtColor.ORANGE
elif "medium" in fixable_vulnerabilities_info.count_by_priority:
elif "medium" in pocket_info["info"]:
main_color = messages.TxtColor.WARNINGYELLOW
elif "low" in fixable_vulnerabilities_info.count_by_priority:
elif "low" in pocket_info["info"]:
main_color = messages.TxtColor.INFOBLUE
else:
main_color = ""

if main_color:
return "{}{}{}".format(
main_color,
str(fixable_vulnerabilities_info.count),
str(pocket_info["count"]),
messages.TxtColor.ENDC,
)

return str(fixable_vulnerabilities_info.count)
return str(pocket_info["count"])


def _get_count_msg_by_priority(count_by_priority):
Expand All @@ -156,54 +191,64 @@ def _get_count_msg_by_priority(count_by_priority):
def _create_fixable_cves_count(vulnerabilities) -> str:
msg = messages.CLI_VULNERABILITY_LIST_FIXES_AVAILABLE_HEADER + "\n"
fixable_vulnerabilities_info = _get_info_from_vulnerabilities(
vulnerabilities, fixable_vuln=True
vulnerabilities
)
count_with_color = _get_fixable_color_count(fixable_vulnerabilities_info)
msg += (
" "
+ count_with_color
+ " "
+ messages.CLI_VULNERABILITY_LIST_FIXES_AVAILABLE_COUNT
+ " ("
+ _get_count_msg_by_priority(
fixable_vulnerabilities_info.count_by_priority

for pocket, pocket_info in fixable_vulnerabilities_info.items():
if not pocket_info["count"]:
continue

count_with_color = _get_fixable_color_count(pocket_info)
msg += (
" "
+ count_with_color
+ " "
+ messages.CLI_VULNERABILITY_LIST_FIXES_AVAILABLE_COUNT.format(
pocket=pocket.title().replace("_", " ")
)
+ " ("
+ _get_count_msg_by_priority(pocket_info["info"])
+ ")"
+ "\n"
)
+ ")"
+ "\n"
)

return msg


def _create_fixable_usns_count(vulnerabilities):
msg = messages.CLI_VULNERABILITY_LIST_FIXES_AVAILABLE_HEADER + "\n"
fixable_vulnerabilities_info = _get_info_from_vulnerabilities(
vulnerabilities, fixable_vuln=True
)
msg += (
" "
+ str(fixable_vulnerabilities_info.count)
+ " "
+ messages.CLI_VULNERABILITY_LIST_FIXES_AVAILABLE_COUNT
+ "\n"
vulnerabilities
)
for pocket, pocket_info in fixable_vulnerabilities_info.items():
if not pocket_info["count"]:
continue

msg += (
" "
+ str(pocket_info["count"])
+ " "
+ messages.CLI_VULNERABILITY_LIST_FIXES_AVAILABLE_COUNT.format(
pocket=pocket.title().replace("_", " ")
)
+ "\n"
)

return msg


def _create_unfixable_cves_count(vulnerabilities) -> str:
msg = messages.CLI_VULNERABILITY_LIST_UNFIXABLE_AVAILABLE_HEADER + "\n"
unfixable_vulnerabilities_info = _get_info_from_vulnerabilities(
vulnerabilities, fixable_vuln=False
count, unfixable_vulnerabilities_info = (
_get_unfixable_info_from_vulnerabilities(vulnerabilities) # noqa
)
msg += (
" "
+ str(unfixable_vulnerabilities_info.count)
+ str(count)
+ " "
+ messages.CLI_VULNERABILITY_LIST_UNFIXABLE_AVAILABLE_COUNT
+ " ("
+ _get_count_msg_by_priority(
unfixable_vulnerabilities_info.count_by_priority
)
+ _get_count_msg_by_priority(unfixable_vulnerabilities_info)
+ ")"
+ "\n"
)
Expand All @@ -213,12 +258,12 @@ def _create_unfixable_cves_count(vulnerabilities) -> str:

def _create_unfixable_usns_count(vulnerabilities):
msg = messages.CLI_VULNERABILITY_LIST_UNFIXABLE_AVAILABLE_HEADER + "\n"
unfixable_vulnerabilities_info = _get_info_from_vulnerabilities(
vulnerabilities, fixable_vuln=False
count, unfixable_vulnerabilities_info = (
_get_unfixable_info_from_vulnerabilities(vulnerabilities) # noqa
)
msg += (
" "
+ str(unfixable_vulnerabilities_info.count)
+ str(count)
+ " "
+ messages.CLI_VULNERABILITY_LIST_UNFIXABLE_AVAILABLE_COUNT
+ "\n"
Expand Down
2 changes: 1 addition & 1 deletion uaclient/messages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1343,7 +1343,7 @@ class TxtColor:
+ TxtColor.ENDC
)
CLI_VULNERABILITY_LIST_FIXES_AVAILABLE_COUNT = t.gettext(
"vulnerabilities found"
"fixable via {pocket}"
)
CLI_VULNERABILITY_LIST_UNFIXABLE_AVAILABLE_COUNT = t.gettext(
"unfixable vulnerabilities found"
Expand Down

0 comments on commit 994f9a2

Please sign in to comment.