def test_csv(): sr = filter_scan_results_by_cve_ids( ["CVE-2020-1000", "CVE-2020-1001", "CVE-2020-1005"]) opt = MockOpt() opt.priority = "all" opt.unresolved = True formatter = CSVOutputFormatter(opt, null_logger()) (results_msg, return_code) = formatter.format_output(sr, MockSysInfo()) expected_csv_results = "CVE ID,PRIORITY,PACKAGE,FIXED_VERSION,REPOSITORY" expected_csv_results += "\nCVE-2020-1000,low,pkg3,," expected_csv_results += ( "\nCVE-2020-1001,high,pkg1,1:1.2.3-4+deb9u2ubuntu0.2,Ubuntu Archive") expected_csv_results += ( "\nCVE-2020-1001,high,pkg2,1:1.2.3-4+deb9u2ubuntu0.2,Ubuntu Archive") expected_csv_results += ("\nCVE-2020-1005,low,pkg1,1:1.2.3-4+deb9u3,%s" % const.UA_APPS) expected_csv_results += ("\nCVE-2020-1005,low,pkg2,1:1.2.3-4+deb9u3,%s" % const.UA_APPS) expected_csv_results += ("\nCVE-2020-1005,low,pkg3,10.2.3-2ubuntu0.1,%s" % const.UA_INFRA) assert results_msg == expected_csv_results
def test_no_patch_available_infra_experimental(cve_output_formatter): sr = filter_scan_results_by_cve_ids(["CVE-2020-1001", "CVE-2020-1003"]) sr.append(ScanResult("CVE-2020-1000", "low", "pkg3", "1.2.3-4", const.UA_INFRA),) cve_output_formatter.opt.experimental_mode = False msg, rc = cve_output_formatter.format_output(sr, MockSysInfo()) assert msg == "Vulnerable to CVE-2020-1000. There is no fix available, yet." assert rc == 3
def test_no_tty_no_color(monkeypatch, table_only_cli_output_formatter): monkeypatch.setattr(sys.stdout, "isatty", lambda: False) sr = filter_scan_results_by_cve_ids(["CVE-2020-1001"]) (results_msg, return_code) = table_only_cli_output_formatter.format_output( sr, MockSysInfo()) assert "\u001b" not in results_msg
def test_summary_priority_all(monkeypatch, summary_only_cli_output_formatter): monkeypatch.setattr(sys.stdout, "isatty", lambda: False) cof = summary_only_cli_output_formatter sr = filter_scan_results_by_cve_ids(["CVE-2020-1001"]) (results_msg, return_code) = cof.format_output(sr, MockSysInfo()) assert re.search(r"CVE Priority\s+All", results_msg)
def test_vulnerable_patch_available_infra(cve_output_formatter): sr = filter_scan_results_by_cve_ids(["CVE-2020-1001", "CVE-2020-1003"]) sr.append(ScanResult("CVE-2020-1000", "low", "pkg3", "1.2.3-4", const.UA_INFRA),) msg, rc = cve_output_formatter.format_output(sr, MockSysInfo()) assert ( msg == f"Vulnerable to CVE-2020-1000, but fixes are available from {const.UA_INFRA}." )
def test_ua_infra_unknown_text(monkeypatch, table_only_cli_output_formatter): sysinfo = MockSysInfo() sysinfo.esm_infra_enabled = None sr = filter_scan_results_by_cve_ids("CVE-2020-1010") (results_msg, return_code) = table_only_cli_output_formatter.format_output(sr, sysinfo) assert "(disabled)" not in results_msg
def test_ua_apps_disabled_text(monkeypatch, table_only_cli_output_formatter): sysinfo = MockSysInfo() sysinfo.esm_apps_enabled = False sysinfo.esm_infra_enabled = True sr = filter_scan_results_by_cve_ids("CVE-2020-1009") (results_msg, return_code) = table_only_cli_output_formatter.format_output(sr, sysinfo) assert "(disabled)" in results_msg
def test_always_show_links(): sr = filter_scan_results_by_cve_ids(["CVE-2020-1004", "CVE-2020-1005"]) opt = MockOpt() opt.unresolved = True opt.show_links = False formatter = JSONOutputFormatter(opt, null_logger()) (results_msg, return_code) = formatter.format_output(sr, MockSysInfo()) assert const.UCT_URL % "CVE-2020-1004" in results_msg assert const.UCT_URL % "CVE-2020-1005" in results_msg
def test_vulnerable_patch_available_repository(cve_output_formatter): sr = filter_scan_results_by_cve_ids(["CVE-2020-1001", "CVE-2020-1003"]) sr.append( ScanResult("CVE-2020-1000", "low", "pkg3", "1.2.3-4", const.UBUNTU_ARCHIVE), ) msg, rc = cve_output_formatter.format_output(sr, MockSysInfo()) expected_msg = ( "Vulnerable to CVE-2020-1000, but fixes are available from " "the Ubuntu Archive." ) assert msg == expected_msg assert rc == 4
def run_json_format_test(indent): sr = filter_scan_results_by_cve_ids( ["CVE-2020-1000", "CVE-2020-1001", "CVE-2020-1005"]) opt = MockOpt() opt.priority = "all" opt.unresolved = True formatter = JSONOutputFormatter(opt, null_logger(), indent=indent) (results_msg, return_code) = formatter.format_output(sr, MockSysInfo()) expected_output = json.dumps(sample_output, indent=indent, sort_keys=False) assert results_msg == expected_output
def test_no_results_no_header(monkeypatch): header_regex = r"CVE ID\s+PRIORITY\s+PACKAGE\s+FIXED VERSION\s+REPOSITORY" monkeypatch.setattr(sys.stdout, "isatty", lambda: False) cof = CLIOutputFormatter(MockOpt(), null_logger()) sysinfo = MockSysInfo() cof.opt.experimental_mode = True cof.opt.unresolved = False sr = filter_scan_results_by_cve_ids(["CVE-2020-1003"]) (results_msg, return_code) = cof.format_output(sr, sysinfo) assert not re.search(header_regex, results_msg)
def run_color_test(monkeypatch, table_only_cli_output_formatter, sysinfo, cve_id, color_code): monkeypatch.setattr(sys.stdout, "isatty", lambda: True) if color_code is None: expected_color = "" else: expected_color = "38;5;%dm" % color_code table_only_cli_output_formatter.opt.unresolved = True sr = filter_scan_results_by_cve_ids([cve_id]) (results_msg, return_code) = table_only_cli_output_formatter.format_output(sr, sysinfo) assert expected_color in results_msg
def test_vulnerable_patch_available_apps_infra(cve_output_formatter): sr = filter_scan_results_by_cve_ids(["CVE-2020-1001", "CVE-2020-1003"]) sr = sr + [ ScanResult("CVE-2020-1000", "low", "pkg4", "1.2.3-4", const.UA_INFRA), ScanResult("CVE-2020-1000", "low", "pkg5", "1.2.3-4", const.UA_APPS), ] msg, rc = cve_output_formatter.format_output(sr, MockSysInfo()) expected_msg = ( "Vulnerable to CVE-2020-1000, but fixes are available from " f"{const.UA_APPS} and {const.UA_INFRA}." ) assert msg == expected_msg assert rc == 4
def test_vulnerable_patch_available_infra_repository_duplicates(cve_output_formatter): sr = filter_scan_results_by_cve_ids(["CVE-2020-1001", "CVE-2020-1003"]) sr = sr + [ ScanResult("CVE-2020-1000", "low", "pkg3", "1.2.3-4", const.UBUNTU_ARCHIVE), ScanResult("CVE-2020-1000", "low", "pkg5", "1.2.3-4", const.UA_INFRA), ScanResult("CVE-2020-1000", "low", "pkg6", "1.2.3-4", const.UA_INFRA), ] msg, rc = cve_output_formatter.format_output(sr, MockSysInfo()) expected_msg = ( "Vulnerable to CVE-2020-1000, but fixes are available from " f"{const.UA_INFRA} and the Ubuntu Archive." ) assert msg == expected_msg assert rc == 4
def test_suggestions_empty_no_experimental_infra_enabled( monkeypatch, suggestions_only_cli_output_formatter): cof = suggestions_only_cli_output_formatter cof.opt.priority = const.LOW cof.opt.experimental_mode = False sysinfo = MockSysInfo() sysinfo.esm_apps_enabled = False sysinfo.esm_infra_enabled = True sr = filter_scan_results_by_cve_ids(["CVE-2020-1001", "CVE-2020-1010"]) (results_msg, return_code) = cof.format_output(sr, sysinfo) assert ( "additional security patch(es) are available if ESM for Infrastructure is enabled with\nUbuntu Advantage." not in results_msg)
def test_summary_experimental_filter(monkeypatch, summary_only_cli_output_formatter): monkeypatch.setattr(sys.stdout, "isatty", lambda: False) cof = summary_only_cli_output_formatter sysinfo = MockSysInfo() sysinfo.esm_apps_enabled = False sysinfo.esm_infra_enabled = True cof.opt.experimental_mode = False sr = filter_scan_results_by_cve_ids(["CVE-2020-1001"]) (results_msg, return_code) = cof.format_output(sr, sysinfo) assert "Vulnerabilities Fixable by ESM" not in results_msg # Disable this test for now # assert "UA Apps Enabled" not in results_msg # assert "UA Infra Enabled" not in results_msg assert "Available Fixes Not Applied" not in results_msg
def run_esm_color_code_test(monkeypatch, output_formatter, sysinfo, repository_color_code, yn): monkeypatch.setattr(sys.stdout, "isatty", lambda: True) sr = filter_scan_results_by_cve_ids(["CVE-2020-1005"]) (results_msg, return_code) = output_formatter.format_output(sr, sysinfo) if yn == "Unknown": fixable_color_code = "" else: fixable_color_code = r"\u001b\[38;5;%dm" % repository_color_code assert re.search( r"Vulnerabilities Fixable by %s\s+%s2" % (const.UA_APPS, fixable_color_code), results_msg, ) assert re.search( r"Vulnerabilities Fixable by %s\s+%s1" % (const.UA_INFRA, fixable_color_code), results_msg, )
def run_fixes_not_applied_color_code_test( monkeypatch, output_formatter, sysinfo, repository_color_code, num_fixes, unknown=False, ): monkeypatch.setattr(sys.stdout, "isatty", lambda: True) sr = filter_scan_results_by_cve_ids(["CVE-2020-1005"]) (results_msg, return_code) = output_formatter.format_output(sr, sysinfo) fixable_color_code = "" if num_fixes != 0 and not unknown: fixable_color_code = r"\u001b\[38;5;%dm" % repository_color_code assert re.search( r"Available Fixes Not Applied by `apt-get upgrade`\s+%s%d" % (fixable_color_code, num_fixes), results_msg, )
def test_summary_nounresolved(monkeypatch, summary_only_cli_output_formatter): monkeypatch.setattr(sys.stdout, "isatty", lambda: False) cof = summary_only_cli_output_formatter cof.opt.priority = const.LOW cof.opt.unresolved = False sysinfo = MockSysInfo() sysinfo.esm_apps_enabled = False sysinfo.esm_infra_enabled = False sr = filter_scan_results_by_cve_ids([ "CVE-2020-1001", "CVE-2020-1002", "CVE-2020-1003", "CVE-2020-1005", "CVE-2020-1009", "CVE-2020-1010", ]) (results_msg, return_code) = cof.format_output(sr, sysinfo) assert re.search(r"Ubuntu Release\s+bionic", results_msg) assert re.search(r"Installed Packages\s+100", results_msg) assert re.search(r"CVE Priority\s+low or higher", results_msg) assert re.search(r"Unique Packages Fixable by Patching\s+6", results_msg) assert re.search(r"Unique CVEs Fixable by Patching\s+5", results_msg) assert re.search(r"Vulnerabilities Fixable by Patching\s+10", results_msg) assert re.search(r"Vulnerabilities Fixable by %s\s+6" % const.UA_APPS, results_msg) assert re.search(r"Vulnerabilities Fixable by %s\s+2" % const.UA_INFRA, results_msg) # Disabling for now # assert re.search(r"UA Apps Enabled\s+No", results_msg) # assert re.search(r"UA Infra Enabled\s+No", results_msg) assert re.search(r"Fixes Available by `apt-get upgrade`\s+2", results_msg) assert re.search(r"Available Fixes Not Applied by `apt-get upgrade`\s+8", results_msg)
def test_vulnerable_no_patch(cve_output_formatter): sr = filter_scan_results_by_cve_ids(["CVE-2020-1000", "CVE-2020-1003"]) msg, rc = cve_output_formatter.format_output(sr, MockSysInfo()) assert msg == "Vulnerable to CVE-2020-1000. There is no fix available, yet." assert rc == 3
def test_json_format(): sr = filter_scan_results_by_cve_ids( ["CVE-2020-1000", "CVE-2020-1001", "CVE-2020-1005"]) opt = MockOpt() opt.priority = "all" opt.unresolved = True formatter = JSONOutputFormatter(opt, null_logger()) (results_msg, return_code) = formatter.format_output(sr, MockSysInfo()) expected_output = json.dumps( { "summary": { "ubuntu_release": "bionic", "num_installed_packages": 100, "num_cves": 2, "num_affected_packages": 3, "num_patchable_vulnerabilities": 5, }, "cves": { "CVE-2020-1000": { "url": "https://people.canonical.com/~ubuntu-security/cve/CVE-2020-1000", "packages": { "pkg3": { "priority": "low", "fixed_version": "", "repository": "", } }, }, "CVE-2020-1001": { "url": "https://people.canonical.com/~ubuntu-security/cve/CVE-2020-1001", "packages": { "pkg1": { "priority": "high", "fixed_version": "1:1.2.3-4+deb9u2ubuntu0.2", "repository": "Ubuntu Archive", }, "pkg2": { "priority": "high", "fixed_version": "1:1.2.3-4+deb9u2ubuntu0.2", "repository": "Ubuntu Archive", }, }, }, "CVE-2020-1005": { "url": "https://people.canonical.com/~ubuntu-security/cve/CVE-2020-1005", "packages": { "pkg1": { "priority": "low", "fixed_version": "1:1.2.3-4+deb9u3", "repository": const.UA_APPS, }, "pkg2": { "priority": "low", "fixed_version": "1:1.2.3-4+deb9u3", "repository": const.UA_APPS, }, "pkg3": { "priority": "low", "fixed_version": "10.2.3-2ubuntu0.1", "repository": const.UA_INFRA, }, }, }, }, }, indent=4, sort_keys=False, ) assert results_msg == expected_output
def test_not_vulnerable(cve_output_formatter): sr = filter_scan_results_by_cve_ids(["CVE-2020-1001", "CVE-2020-1003"]) msg, rc = cve_output_formatter.format_output(sr, MockSysInfo()) assert msg == "Not affected by CVE-2020-1000." assert rc == 0