From 79e91d1a4d671376ec7defd50a0f0f24a8662c40 Mon Sep 17 00:00:00 2001 From: ved pawar <85354558+vedpawar2254@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:55:42 +0530 Subject: [PATCH 1/4] Fixes #4578 ([CVEDB] Why does the function metric_finder returns unknown or a metrics_id) --- cve_bin_tool/cvedb.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/cve_bin_tool/cvedb.py b/cve_bin_tool/cvedb.py index e8e4fde342..ba9627de71 100644 --- a/cve_bin_tool/cvedb.py +++ b/cve_bin_tool/cvedb.py @@ -45,6 +45,7 @@ DBNAME = "cve.db" OLD_CACHE_DIR = Path("~") / ".cache" / "cvedb" +UNKNOWN_METRIC_ID = 0 EPSS_METRIC_ID = 1 CVSS_2_METRIC_ID = 2 CVSS_3_METRIC_ID = 3 @@ -416,6 +417,9 @@ def init_database(self) -> None: for table in self.TABLE_SCHEMAS: cursor.execute(self.TABLE_SCHEMAS[table]) + # Ensure the UNKNOWN metric exists + self.ensure_unknown_metric(cursor) + # add indexes for index in self.INDEXES: cursor.execute(self.INDEXES[index]) @@ -619,6 +623,7 @@ def populate_metrics(self): # Insert a row without specifying cve_metrics_id insert_metrics = self.INSERT_QUERIES["insert_metrics"] data = [ + (UNKNOWN_METRIC_ID, "UNKNOWN"), (EPSS_METRIC_ID, "EPSS"), (CVSS_2_METRIC_ID, "CVSS-2"), (CVSS_3_METRIC_ID, "CVSS-3"), @@ -632,7 +637,7 @@ def populate_metrics(self): def metric_finder(self, cursor, cve): """ SQL query to retrieve the metrics_name based on the metrics_id - currently cve["CVSS_version"] return 2,3 based on there version and they are mapped accordingly to there metrics name in metrics table. + currently cve["CVSS_version"] return 2,3 based on their version and they are mapped accordingly to their metrics name in metrics table. """ query = """ SELECT metrics_id FROM metrics @@ -640,7 +645,7 @@ def metric_finder(self, cursor, cve): """ metric = None if cve["CVSS_version"] == "unknown": - metric = "unknown" + metric = 0 else: cursor.execute(query, [cve.get("CVSS_version")]) # Fetch all the results of the query and use 'map' to extract only the 'metrics_name' from the result @@ -1173,8 +1178,18 @@ def fetch_from_mirror(self, mirror, pubkey, ignore_signature, log_signature_erro @contextlib.contextmanager def with_cursor(self): + """Context manager for database cursor.""" cursor = self.db_open_and_get_cursor() try: yield cursor finally: self.db_close() + + def ensure_unknown_metric(self, cursor): + """Ensure that the UNKNOWN metric exists in the metrics table.""" + insert_metrics = self.INSERT_QUERIES["insert_metrics"] + try: + cursor.execute(insert_metrics, (UNKNOWN_METRIC_ID, "UNKNOWN")) + except sqlite3.IntegrityError: + # The metric already exists, no action needed + pass From b7369fe2750f05019e308b5b8bce331aa22b087d Mon Sep 17 00:00:00 2001 From: ved pawar <85354558+vedpawar2254@users.noreply.github.com> Date: Fri, 10 Jan 2025 23:31:38 +0530 Subject: [PATCH 2/4] Update cvedb.py --- cve_bin_tool/cvedb.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cve_bin_tool/cvedb.py b/cve_bin_tool/cvedb.py index ba9627de71..f1040b3cb1 100644 --- a/cve_bin_tool/cvedb.py +++ b/cve_bin_tool/cvedb.py @@ -419,7 +419,6 @@ def init_database(self) -> None: # Ensure the UNKNOWN metric exists self.ensure_unknown_metric(cursor) - # add indexes for index in self.INDEXES: cursor.execute(self.INDEXES[index]) From 168d40e3b8532804d203476340beffb905281fde Mon Sep 17 00:00:00 2001 From: ved pawar <85354558+vedpawar2254@users.noreply.github.com> Date: Fri, 7 Feb 2025 13:56:28 +0530 Subject: [PATCH 3/4] changed metric from 0 to UNKNOWN_METRIC_ID --- cve_bin_tool/cvedb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cve_bin_tool/cvedb.py b/cve_bin_tool/cvedb.py index f1040b3cb1..0f770f3bc0 100644 --- a/cve_bin_tool/cvedb.py +++ b/cve_bin_tool/cvedb.py @@ -644,7 +644,7 @@ def metric_finder(self, cursor, cve): """ metric = None if cve["CVSS_version"] == "unknown": - metric = 0 + metric = UNKNOWN_METRIC_ID else: cursor.execute(query, [cve.get("CVSS_version")]) # Fetch all the results of the query and use 'map' to extract only the 'metrics_name' from the result From 678d1fe3c49340f0c44986176f1e2ce34f544fed Mon Sep 17 00:00:00 2001 From: Ved Date: Wed, 12 Mar 2025 13:25:49 +0530 Subject: [PATCH 4/4] removed python3.8 support --- .pre-commit-config.yaml | 106 ++++++++++++++++++------------------ cve_bin_tool/cli.py | 2 +- cve_bin_tool/csv2cve.py | 2 +- cve_bin_tool/cve_scanner.py | 19 ++++--- cve_bin_tool/util.py | 7 ++- dev-requirements.txt | 5 -- doc/MANUAL.md | 2 +- setup.py | 2 +- test/README.md | 8 +-- 9 files changed, 75 insertions(+), 78 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0eaae60cba..672372ad18 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ repos: -- repo: https://github.com/econchick/interrogate + - repo: https://github.com/econchick/interrogate rev: 1.7.0 hooks: - id: interrogate @@ -8,76 +8,74 @@ repos: args: ["-vv", "-i", "-I", "-M", "-C", "-n", "-p", "-f", "60.0"] # args for cut and paste: interrogate -vv -i -I -M -C -n -p -f 60.0 -- repo: https://github.com/pycqa/isort + - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: - - id: isort - exclude: ^fuzz/generated/ + - id: isort + exclude: ^fuzz/generated/ -- repo: https://github.com/psf/black-pre-commit-mirror + - repo: https://github.com/psf/black-pre-commit-mirror rev: 24.10.0 hooks: - - id: black - exclude: ^fuzz/generated/ + - id: black + exclude: ^fuzz/generated/ -- repo: https://github.com/asottile/pyupgrade + - repo: https://github.com/asottile/pyupgrade rev: v3.19.1 hooks: - - id: pyupgrade - exclude: ^fuzz/generated/ - args: ["--py38-plus"] + - id: pyupgrade + exclude: ^fuzz/generated/ + args: ["--py312-plus"] -- repo: https://github.com/pycqa/flake8 + - repo: https://github.com/pycqa/flake8 rev: 7.1.1 hooks: - - id: flake8 - exclude: ^fuzz/generated/|bandit\.conf$ + - id: flake8 + exclude: ^fuzz/generated/|bandit\.conf$ -- repo: https://github.com/PyCQA/bandit + - repo: https://github.com/PyCQA/bandit rev: 1.8.0 hooks: - - id: bandit - exclude: ^fuzz/generated/ - args: ["-c", "bandit.conf"] + - id: bandit + exclude: ^fuzz/generated/ + args: ["-c", "bandit.conf"] -- repo: https://github.com/jorisroovers/gitlint + - repo: https://github.com/jorisroovers/gitlint rev: v0.19.1 hooks: - - id: gitlint + - id: gitlint -- repo: https://github.com/pre-commit/mirrors-mypy + - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.14.1 hooks: - - id: mypy - additional_dependencies: - - types-beautifulsoup4 - - types-jsonschema - - types-PyYAML - - types-requests - - types-setuptools - - types-toml - files: | - (?x)^( - cve_bin_tool/parsers/.*| - cve_bin_tool/__init__.py| - cve_bin_tool/async_utils.py| - cve_bin_tool/file.py| - cve_bin_tool/linkify.py| - cve_bin_tool/log.py| - cve_bin_tool/strings.py| - cve_bin_tool/theme.py| - cve_bin_tool/util.py| - cve_bin_tool/validator.py| - cve_bin_tool/version.py| - doc/.*| - test/test_data/.*| - test/__init__.py| - test/test_file.py|s - test/test_requirements.py| - test/test_strings.py| - test/test_triage.py| - test/test_version.py| - test/utils.py| - )$ - - + - id: mypy + additional_dependencies: + - types-beautifulsoup4 + - types-jsonschema + - types-PyYAML + - types-requests + - types-setuptools + - types-toml + files: | + (?x)^( + cve_bin_tool/parsers/.*| + cve_bin_tool/__init__.py| + cve_bin_tool/async_utils.py| + cve_bin_tool/file.py| + cve_bin_tool/linkify.py| + cve_bin_tool/log.py| + cve_bin_tool/strings.py| + cve_bin_tool/theme.py| + cve_bin_tool/util.py| + cve_bin_tool/validator.py| + cve_bin_tool/version.py| + doc/.*| + test/test_data/.*| + test/__init__.py| + test/test_file.py|s + test/test_requirements.py| + test/test_strings.py| + test/test_triage.py| + test/test_version.py| + test/utils.py| + )$ diff --git a/cve_bin_tool/cli.py b/cve_bin_tool/cli.py index ff50d8a9c2..2888276519 100644 --- a/cve_bin_tool/cli.py +++ b/cve_bin_tool/cli.py @@ -96,7 +96,7 @@ def main(argv=None): """Scan a binary file for certain open source libraries that may have CVEs""" if sys.version_info < (3, 8): raise OSError( - "Python no longer provides security updates for version 3.7 as of June 2023. Please upgrade to python 3.8+ to use CVE Binary Tool." + "Python no longer provides security updates for version 3.8 as of October 2024. Please upgrade to Python 3.9+ to use CVE Binary Tool." ) argv = argv or sys.argv diff --git a/cve_bin_tool/csv2cve.py b/cve_bin_tool/csv2cve.py index dee8ef1a90..7c591fa080 100644 --- a/cve_bin_tool/csv2cve.py +++ b/cve_bin_tool/csv2cve.py @@ -18,7 +18,7 @@ def main(argv: list[str] | None = None): """Used to scan a .csv file that lists the dependencies.""" if sys.version_info < (3, 8): raise OSError( - "Python no longer provides security updates for version 3.7 as of June 2023. Please upgrade to python 3.8+ to use CVE Binary Tool." + "Python no longer provides security updates for version 3.8 as of October 2024. Please upgrade to Python 3.9+ to use CVE Binary Tool." ) logger: logging.Logger = LOGGER.getChild("CSV2CVE") argv = argv or sys.argv diff --git a/cve_bin_tool/cve_scanner.py b/cve_bin_tool/cve_scanner.py index 6eab229d02..3d27c51467 100644 --- a/cve_bin_tool/cve_scanner.py +++ b/cve_bin_tool/cve_scanner.py @@ -7,7 +7,6 @@ from logging import Logger from pathlib import Path from string import ascii_lowercase -from typing import DefaultDict, Dict, List from rich.console import Console @@ -19,6 +18,8 @@ from cve_bin_tool.util import CVE, CVEData, ProductInfo, Remarks, VersionInfo from cve_bin_tool.version_compare import Version +# from typing import Dict, List + class CVEScanner: """ @@ -27,13 +28,13 @@ class CVEScanner: products_with_cve: int products_without_cve: int - all_cve_data: DefaultDict[ProductInfo, CVEData] - all_cve_version_info: Dict[str, VersionInfo] + all_cve_data: defaultdict[ProductInfo, CVEData] + all_cve_version_info: dict[str, VersionInfo] RANGE_UNSET: str = "" dbname: str = str(Path(DISK_LOCATION_DEFAULT) / DBNAME) CONSOLE: Console = Console(file=sys.stderr, theme=cve_theme) - ALPHA_TO_NUM: Dict[str, int] = dict(zip(ascii_lowercase, range(26))) + ALPHA_TO_NUM: dict[str, int] = dict(zip(ascii_lowercase, range(26))) def __init__( self, @@ -44,8 +45,8 @@ def __init__( logger: Logger = None, error_mode: ErrorMode = ErrorMode.TruncTrace, check_exploits: bool = False, - exploits_list: List[str] = [], - disabled_sources: List[str] = [], + exploits_list: list[str] = [], + disabled_sources: list[str] = [], ): self.logger = logger or LOGGER.getChild(self.__class__.__name__) self.error_mode = error_mode @@ -211,10 +212,10 @@ def get_cves(self, product_info: ProductInfo, triage_data: TriageData): ) product_info_data: CVEData | None = self.all_cve_data.get(product_info) - prev_cves: List[CVE] = ( + prev_cves: list[CVE] = ( product_info_data.get("cves", []) if product_info_data is not None else [] # type: ignore ) - cves: List[CVE] = [] + cves: list[CVE] = [] # Go through and get all the severities if cve_list: @@ -385,7 +386,7 @@ def filter_triage_data(self): Filter out triage data that is not relevant to the CVEs found, specifically those marked as NotAffected or FalsePositives. """ - to_delete: List[ProductInfo] = [] + to_delete: list[ProductInfo] = [] for product_info, cve_data in self.all_cve_data.items(): original_cves = cve_data["cves"] diff --git a/cve_bin_tool/util.py b/cve_bin_tool/util.py index 1c25b273ae..3867ed731b 100644 --- a/cve_bin_tool/util.py +++ b/cve_bin_tool/util.py @@ -9,9 +9,12 @@ import os import re import sys +from collections import defaultdict +from collections.abc import Iterator from enum import Enum from pathlib import Path -from typing import DefaultDict, Iterator, List, NamedTuple, Pattern, Set, Union +from re import Pattern +from typing import NamedTuple, Union import requests from packageurl import PackageURL @@ -212,7 +215,7 @@ class VersionInfo(NamedTuple): end_excluding: str -class CVEData(DefaultDict[str, Union[List[CVE], Set[str]]]): +class CVEData(defaultdict[str, Union[list[CVE], set[str]]]): """ A Class representing a dictionary of CVEs and paths """ diff --git a/dev-requirements.txt b/dev-requirements.txt index a9b08615f9..59a1bde5a6 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,12 +1,7 @@ black==24.10.0; python_version > "3.8" -black==24.8.0; python_version <= "3.8" -isort; python_version < "3.8" isort==5.13.2; python_version >= "3.8" -pre-commit; python_version <= "3.8" pre-commit==4.0.1; python_version > "3.8" -flake8; python_version < "3.8" flake8==7.1.1; python_version >= "3.8" -bandit==1.7.10; python_version <= "3.8" bandit==1.8.0; python_version > "3.8" gitlint==v0.19.1 interrogate diff --git a/doc/MANUAL.md b/doc/MANUAL.md index ba1915269c..253c7b5534 100644 --- a/doc/MANUAL.md +++ b/doc/MANUAL.md @@ -530,7 +530,7 @@ This data source provides the CVEs for the CURL product. ## Limitations The last release of this tool to support python 2.7 is 0.3.1. Please use -python 3.8+ for development and future versions. Linux and Windows are +python 3.10+ for development and future versions. Linux and Windows are supported, as is usage within cygwin on windows. This tool does not scan for all possible known public vulnerabilities, it only diff --git a/setup.py b/setup.py index 54c18248d5..ad7bae29f2 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ url="https://github.com/intel/cve-bin-tool", license="GPL-3.0-or-later", keywords=["security", "tools", "CVE"], - python_requires=">=3.8", + python_requires=">=3.10", classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", diff --git a/test/README.md b/test/README.md index 702f5ee7d2..f9bc743754 100644 --- a/test/README.md +++ b/test/README.md @@ -75,14 +75,14 @@ The recommended way to do this yourself is to use python's `virtualenv` You can set up virtualenv for all these environments: ```console -virtualenv -p python3.8 venv3.8 -virtualenv -p python3.9 venv3.9 +virtualenv -p python3.11 venv3.11 +virtualenv -p python3.12 venv3.12 ``` -To activate one of these (the example uses 3.8), run the tests, and deactivate: +To activate one of these (the example uses 3.11), run the tests, and deactivate: ```console -source venv3.8/bin/activate +source venv3.11/bin/activate pytest deactivate