def test_update_flags(self): self.assertNotEqual( main(["cve-bin-tool", "-x", "-u", "never", self.tempdir]), 0) self.assertNotEqual( main(["cve-bin-tool", "-x", "--update", "daily", self.tempdir]), 0) self.assertNotEqual( main(["cve-bin-tool", "-x", "-u", "now", self.tempdir]), 0) with self.assertRaises(SystemExit) as exit: main(["cve-bin-tool", "-u", "whatever", self.tempdir]) self.assertEqual(exit.exception.code, -2)
def test_runs(self): logger = logging.getLogger() test_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "csv") runs = ["expat", "libgcrypt", "openssl", "sqlite"] skip_checkers = ["systemd", "xerces", "xml2", "kerberos"] with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", test_path, "-r", ",".join(runs)]) self.check_checkers_log(cm, skip_checkers, runs) runs, skip_checkers = skip_checkers, runs with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", test_path, "-r", ",".join(runs)]) self.check_checkers_log(cm, skip_checkers, runs)
def test_update(self): logger = logging.getLogger() test_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "csv") with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", "-u", "never", test_path]) self.assertTrue( "INFO:cve_bin_tool.CVEDB:Updating CVE data. This will take a few minutes." not in cm.output) with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", "-u", "daily", test_path]) self.assertTrue(( "INFO:cve_bin_tool.CVEDB:Using cached CVE data (<24h old). Use -u now to update immediately." in cm.output ) or ( "INFO:cve_bin_tool.CVEDB:Updating CVE data. This will take a few minutes." in cm.output)) with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", "-u", "now", test_path]) db_path = os.path.join(os.path.expanduser("~"), ".cache", "cvedb") self.assertTrue( ("WARNING:cve_bin_tool.CVEDB:Deleting cachedir " + db_path in cm.output) and ("INFO:cve_bin_tool.CVEDB:Updating CVE data. This will take a few minutes." in cm.output)) with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", "-u", "latest", test_path]) self.assertTrue( "INFO:cve_bin_tool.CVEDB:Updating CVE data. This will take a few minutes." in cm.output)
def test_runs(self, caplog): test_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "csv") runs = ["expat", "libgcrypt", "openssl", "sqlite"] skip_checkers = ["systemd", "xerces", "xml2", "kerberos"] with caplog.at_level(logging.INFO): main(["cve-bin-tool", test_path, "-r", ",".join(runs)]) self.check_checkers_log(caplog, skip_checkers, runs) runs, skip_checkers = skip_checkers, runs with caplog.at_level(logging.INFO): main(["cve-bin-tool", test_path, "-r", ",".join(runs)]) self.check_checkers_log(caplog, skip_checkers, runs)
def test_extract_bad_zip_messages(self, caplog): """Test that bad zip files are logged as extraction failed, but bad exe files produce no such message""" bad_exe_file = os.path.join(self.tempdir, "empty-file.exe") # creates an empty, invalid .exe test file open(bad_exe_file, "w").close() with caplog.at_level(logging.WARNING): main(["cve-bin-tool", bad_exe_file]) assert "Failure extracting" not in caplog.text bad_zip_file = os.path.join(self.tempdir, "empty-file.zip") open(bad_zip_file, "w").close() with caplog.at_level(logging.WARNING): main(["cve-bin-tool", bad_zip_file]) assert "Failure extracting" in caplog.text
def test_quiet_mode(self): """ Test that an quite mode isn't generating any output """ logger = logging.getLogger() # build the test file in test/binaries binaries_path = os.path.join( os.path.abspath(os.path.dirname(__file__)), "binaries") filename = "test-python-3.7.1.out" subprocess.call(["make", filename], cwd=binaries_path) with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", "-q", os.path.join(binaries_path, filename)]) logger.info("test") self.assertEqual(["INFO:root:test"], cm.output)
def test_update_flags(self): assert (main([ "cve-bin-tool", "-x", "-u", "never", "-n", "json", self.tempdir ]) != 0) assert (main([ "cve-bin-tool", "-x", "--update", "daily", "-n", "json", self.tempdir ]) != 0) assert (main([ "cve-bin-tool", "-x", "-u", "now", "-n", "json", self.tempdir ]) != 0) with pytest.raises(SystemExit) as e: main( ["cve-bin-tool", "-u", "whatever", "-n", "json", self.tempdir]) assert e.value.args[0] == ERROR_CODES[SystemExit]
def test_update(self, caplog): test_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "csv") with caplog.at_level(logging.INFO): main(["cve-bin-tool", "-u", "never", "-n", "json", test_path]) assert ( "cve_bin_tool", logging.WARNING, "Not verifying CVE DB cache", ) in caplog.record_tuples caplog.clear() with caplog.at_level(logging.DEBUG): main([ "cve-bin-tool", "-l", "debug", "-u", "daily", "-n", "json", test_path ]) assert ( "cve_bin_tool.CVEDB", logging.INFO, "Using cached CVE data (<24h old). Use -u now to update immediately.", ) in caplog.record_tuples or ( "cve_bin_tool.CVEDB", logging.DEBUG, "Updating CVE data. This will take a few minutes.", ) in caplog.record_tuples caplog.clear() with caplog.at_level(logging.DEBUG): main([ "cve-bin-tool", "-l", "debug", "-u", "now", "-n", "json", test_path ]) db_path = DISK_LOCATION_DEFAULT assert ( "cve_bin_tool.CVEDB", logging.WARNING, f"Updating cachedir {db_path}", ) in caplog.record_tuples and ( "cve_bin_tool.CVEDB", logging.DEBUG, "Updating CVE data. This will take a few minutes.", ) in caplog.record_tuples caplog.clear() with caplog.at_level(logging.DEBUG): main([ "cve-bin-tool", "-l", "debug", "-u", "latest", "-n", "json", test_path ]) assert ( "cve_bin_tool.CVEDB", logging.DEBUG, "Updating CVE data. This will take a few minutes.", ) in caplog.record_tuples caplog.clear()
def test_binary_curl_7_20_0(self): """ Extracting from rpm and scanning curl-7.20.0 """ with Extractor()() as ectx: extracted_path = ectx.extract(os.path.join(self.tempdir, CURL_7_20_0_RPM)) self.assertNotEqual(main(['cve-bin-tool', '-l', 'debug', os.path.join(extracted_path, 'usr', 'bin', 'curl')]), 0)
def test_skips(self): """Tests the skips option""" logger = logging.getLogger() test_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "csv") skip_checkers = ["systemd", "xerces", "xml2", "kerberos"] include_checkers = ["expat", "libgcrypt", "openssl", "sqlite"] with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", test_path, "-s", ",".join(skip_checkers)]) # The final log has all the checkers detected final_log = [i for i in cm.output if "Checkers:" in i] self.assertTrue( len(final_log) > 0, "Could not find checkers line in log") final_log = final_log[0] for checker in skip_checkers: self.assertTrue(checker not in final_log, "found skipped checker {}".format(checker)) for checker in include_checkers: self.assertTrue( checker in final_log, "could not find expected checker {}".format(checker), ) # swap skip_checkers and include_checkers include_checkers, skip_checkers = skip_checkers, include_checkers with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", test_path, "-s", ",".join(skip_checkers)]) final_log = [i for i in cm.output if "Checkers:" in i] self.assertTrue( len(final_log) > 0, "Could not find checkers line in log") final_log = final_log[0] for checker in skip_checkers: self.assertTrue(checker not in final_log, "found skipped checker {}".format(checker)) for checker in include_checkers: self.assertTrue( checker in final_log, "could not find expected checker {}".format(checker), )
def test_skips(self, caplog): """Tests the skips option""" test_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "csv") skip_checkers = ["systemd", "xerces", "xml2", "kerberos"] include_checkers = ["expat", "libgcrypt", "openssl", "sqlite"] with caplog.at_level(logging.INFO): main(["cve-bin-tool", test_path, "-s", ",".join(skip_checkers)]) self.check_checkers_log(caplog, skip_checkers, include_checkers) # swap skip_checkers and include_checkers include_checkers, skip_checkers = skip_checkers, include_checkers with caplog.at_level(logging.INFO): main(["cve-bin-tool", test_path, "-s", ",".join(skip_checkers)]) self.check_checkers_log(caplog, skip_checkers, include_checkers)
def test_SBOM(self, caplog): # check sbom file option SBOM_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)), "sbom") with caplog.at_level(logging.INFO): main([ "cve-bin-tool", "--sbom", "spdx", "--sbom-file", os.path.join(SBOM_PATH, "spdx_test.spdx"), ]) # Verify that one product detected assert ( "cve_bin_tool", logging.INFO, "There are 1 products with known CVEs detected", ) in caplog.record_tuples
def test_unknown_warning(self): """ Test that an "UNKNOWN" file generates a warning """ logger = logging.getLogger() # build the unknown test file in test/binaries binaries_path = os.path.join( os.path.abspath(os.path.dirname(__file__)), "binaries") unknown_filename = "test-png-unknown.out" subprocess.call(["make", unknown_filename], cwd=binaries_path) # Run against the "unknown" file with self.assertLogs(logger, logging.INFO) as cm: main([ "cve-bin-tool", os.path.join(binaries_path, unknown_filename) ]) warnings = [i for i in cm.output if "WARNING" in i] self.assertTrue(len(warnings) > 0) self.assertTrue("was detected with version UNKNOWN" in warnings[0])
def test_binary_curl_7_20_0(self): """ Extracting from rpm and scanning curl-7.20.0 """ with Extractor() as ectx: extracted_path = ectx.extract( os.path.join(self.tempdir, CURL_7_20_0_RPM)) assert (main([ "cve-bin-tool", "-l", "debug", os.path.join(extracted_path, "usr", "bin", "curl"), ]) != 0)
def test_skips(self): """Tests the skips option""" logger = logging.getLogger() test_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "csv") skip_checkers = ["systemd", "xerces", "xml2", "kerberos"] include_checkers = ["expat", "libgcrypt", "openssl", "sqlite"] with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", test_path, "-s", ",".join(skip_checkers)]) self.check_checkers_log(cm, skip_checkers, include_checkers) # swap skip_checkers and include_checkers include_checkers, skip_checkers = skip_checkers, include_checkers with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", test_path, "-s", ",".join(skip_checkers)]) self.check_checkers_log(cm, skip_checkers, include_checkers)
def test_quiet_mode(self): """ Test that an quite mode isn't generating any output """ logger = logging.getLogger() with tempfile.NamedTemporaryFile("w+b", suffix="strong-swan-4.6.3.out", delete=False) as f: signatures = [ b"\x7f\x45\x4c\x46\x02\x01\x01\x03\n", b"strongSwan 4.6.3" ] f.writelines(signatures) filename = f.name with self.assertLogs(logger, logging.INFO) as cm: main(["cve-bin-tool", "-q", filename]) logger.info("test") self.assertEqual(["INFO:root:test"], cm.output) # clean up temporary file. os.remove(filename)
def test_severity(self, capsys, caplog): # scan with severity setting to ensure only CVEs above severity threshold are reported # Check command line parameters - wrong case with pytest.raises(SystemExit) as e: main(["cve-bin-tool", "-S", "HIGH", self.tempdir]) assert e.value.args[0] == -2 # Check command line parameters - wrong option with pytest.raises(SystemExit) as e: main(["cve-bin-tool", "-S", "ALL", self.tempdir]) assert e.value.args[0] == -2 my_test_filename = "sevtest.csv" if os.path.exists(my_test_filename): os.remove(my_test_filename) with caplog.at_level(logging.DEBUG): main([ "cve-bin-tool", "-x", "-f", "csv", "-o", my_test_filename, "-S", "high", os.path.join(self.tempdir, CURL_7_20_0_RPM), ]) # Verify that no CVEs with a severity of Medium are reported assert not self.check_string_in_file(my_test_filename, "MEDIUM") # Verify that CVEs with a higher severity are reported assert self.check_string_in_file(my_test_filename, "HIGH") caplog.clear() if os.path.exists(my_test_filename): os.remove(my_test_filename)
def test_quiet_mode(self, capsys, caplog): """ Test that an quite mode isn't generating any output """ with tempfile.NamedTemporaryFile("w+b", suffix="strong-swan-4.6.3.out", delete=False) as f: signatures = [ b"\x7f\x45\x4c\x46\x02\x01\x01\x03\n", b"strongSwan 4.6.3" ] f.writelines(signatures) filename = f.name main(["cve-bin-tool", "-q", filename, "-u", "now"]) # clean up temporary file. os.remove(filename) # Make sure log is empty assert not caplog.records # Make sure nothing is getting printed on stdout or stderr captured = capsys.readouterr() assert not (captured.out or captured.err)
def main(argv=None): logger = LOGGER.getChild("CSV2CVE") argv = argv or sys.argv if len(argv) < 2: with ErrorHandler(logger=logger): raise InsufficientArgs("csv file required") flag = False for idx, arg in enumerate(argv): if arg.endswith(".csv"): argv[idx] = f"-i={arg}" flag = True if flag: return cli.main(argv) else: with ErrorHandler(logger=logger): raise InsufficientArgs("csv file required")
def test_invalid_parameter(self): """ Test that invalid parmeters exit with expected error code. ArgParse calls sys.exit(2) for all errors, we've overwritten to -2 """ # no directory specified with self.assertRaises(SystemExit) as exit: main(["cve-bin-tool", "--bad-param"]) self.assertEqual(exit.exception.code, -2) # bad parameter (but good directory) with self.assertRaises(SystemExit) as exit: main(["cve-bin-tool", "--bad-param", self.tempdir]) self.assertEqual(exit.exception.code, -2) # worse parameter with self.assertRaises(SystemExit) as exit: main(["cve-bin-tool", "--bad-param && cat hi", self.tempdir]) self.assertEqual(exit.exception.code, -2) # bad parameter after directory with self.assertRaises(SystemExit) as exit: main(["cve-bin-tool", self.tempdir, "--bad-param;cat hi"]) self.assertEqual(exit.exception.code, -2)
def test_invalid_parameter(self): """Test that invalid parmeters exit with expected error code. ArgParse calls sys.exit(2) for all errors, we've overwritten to -2""" # no directory specified with pytest.raises(SystemExit) as e: main(["cve-bin-tool", "--bad-param"]) assert e.value.args[0] == -2 # bad parameter (but good directory) with pytest.raises(SystemExit) as e: main(["cve-bin-tool", "--bad-param", self.tempdir]) assert e.value.args[0] == -2 # worse parameter with pytest.raises(SystemExit) as e: main(["cve-bin-tool", "--bad-param && cat hi", self.tempdir]) assert e.value.args[0] == -2 # bad parameter after directory with pytest.raises(SystemExit) as e: main(["cve-bin-tool", self.tempdir, "--bad-param;cat hi"]) assert e.value.args[0] == -2
def test_config_file(self, caplog, filename): # scan with config file and overwrite output format assert main(["cve-bin-tool", "-C", filename, "-l", "info"]) != 0 # assert only checkers for binutils and curl get to run assert ( "cve_bin_tool.VersionScanner", logging.INFO, "Checkers: binutils, curl", ) in caplog.record_tuples # assert only CVEs of curl get reflected. Because other are skipped assert ( "cve_bin_tool", logging.INFO, "There are 1 products with known CVEs detected", ) in caplog.record_tuples for record in caplog.record_tuples: if record[1] < 20: pytest.fail( msg= "cli option should override logging level specified in config file" )
def test_invalid_file_or_directory(self): """ Test behaviour with an invalid file/directory """ self.assertEqual(main(["cve-bin-tool", "non-existant"]), -1)
def test_usage(self): """ Test that the usage returns 0 """ self.assertEqual(main(["cve-bin-tool"]), 0)
def test_no_extraction(self): """ Test scanner against curl-7.20.0 rpm with extraction turned off """ self.assertEqual( main(["cve-bin-tool", os.path.join(self.tempdir, CURL_7_20_0_RPM)]), 0)
def test_extract_curl_7_20_0(self): """Scanning curl-7.20.0""" self.assertNotEqual( main(["cve-bin-tool", "-l", "debug", "-x", self.tempdir]), 0)
def test_invalid_file_or_directory(self): """ Test behaviour with an invalid file/directory """ with pytest.raises(SystemExit) as e: main(["cve-bin-tool", "non-existant"]) assert e.value.args[0] == -3
def test_usage(self): """ Test that the usage returns 0 """ with pytest.raises(SystemExit) as e: main(["cve-bin-tool"]) assert e.value.args[0] == -6
def test_multithread(self): """ Test Multithread mode """ self.assertNotEqual( main(["cve-bin-tool", "-l", "debug", "-m", "-x", self.tempdir]), 0)
def test_CVSS_score(self, capsys, caplog): # scan with severity score to ensure only CVEs above score threshold are reported my_test_filename = "sevtest.csv" # Check command line parameters. Less than 0 result in default behaviour. if os.path.exists(my_test_filename): os.remove(my_test_filename) with caplog.at_level(logging.DEBUG): main([ "cve-bin-tool", "-x", "-c", "-1", "-f", "csv", "-o", my_test_filename, os.path.join(self.tempdir, CURL_7_20_0_RPM), ]) # Verify that some CVEs with a severity of Medium are reported assert self.check_string_in_file(my_test_filename, "MEDIUM") caplog.clear() # Check command line parameters. >10 results in no CVEs being reported (Maximum CVSS score is 10) if os.path.exists(my_test_filename): os.remove(my_test_filename) with caplog.at_level(logging.DEBUG): main([ "cve-bin-tool", "-x", "-c", "11", "-f", "csv", "-o", my_test_filename, os.path.join(self.tempdir, CURL_7_20_0_RPM), ]) # Verify that no CVEs are reported (no file is created) assert not os.path.exists(my_test_filename) caplog.clear() with caplog.at_level(logging.DEBUG): main([ "cve-bin-tool", "-x", "-f", "csv", "-o", my_test_filename, os.path.join(self.tempdir, CURL_7_20_0_RPM), ]) # Verify that CVEs with a severity of Medium are reported assert self.check_string_in_file(my_test_filename, "MEDIUM") caplog.clear() if os.path.exists(my_test_filename): os.remove(my_test_filename) # Now check subset with caplog.at_level(logging.DEBUG): main([ "cve-bin-tool", "-x", "-c", "7", "-f", "csv", "-o", my_test_filename, os.path.join(self.tempdir, CURL_7_20_0_RPM), ]) # Verify that no CVEs with a severity of Medium are reported assert not self.check_string_in_file(my_test_filename, "MEDIUM") if os.path.exists(my_test_filename): os.remove(my_test_filename) caplog.clear()