Skip to content

Updated Pre-Commit Hooks Configuration #4943

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 4 additions & 97 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,99 +1,6 @@
repos:
- repo: https://github.com/econchick/interrogate
rev: 1.7.0
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.44.0 # Use the latest stable version
hooks:
- id: interrogate
verbose: True
exclude: ^(locales|presentation|fuzz/generated|test|cve_bin_tool/checkers|build)
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
rev: 6.0.1
hooks:
- id: isort
stages: [pre-commit, pre-merge-commit]
exclude: ^fuzz/generated/

- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.10.0
hooks:
- id: black
exclude: ^fuzz/generated/

- repo: https://github.com/asottile/pyupgrade
rev: v3.19.1
hooks:
- id: pyupgrade
exclude: ^fuzz/generated/
args: ["--py38-plus"]

- repo: https://github.com/pycqa/flake8
rev: 7.1.2
hooks:
- id: flake8
exclude: ^fuzz/generated/|bandit\.conf$

- repo: https://github.com/PyCQA/bandit
rev: 1.8.3
hooks:
- id: bandit
exclude: ^fuzz/generated/
args: ["-c", "bandit.conf"]

- repo: https://github.com/jorisroovers/gitlint
rev: v0.19.1
hooks:
- id: gitlint

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.15.0
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|
)$

- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
- id: codespell
name: codespell
description: Checks for common misspellings in text files.
args:
[
"-I",
".github/actions/spelling/allow.txt",
".github/actions/spelling/only.txt",
".github/actions/spelling/expect.txt",
".github/actions/spelling/excludes.txt",
]
language: python
types: [text]
- id: markdownlint
args: ["--disable", "MD013", "MD033"] # Disable long lines & inline HTML rules
133 changes: 98 additions & 35 deletions test/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ def test_runs(self, caplog):
main(["cve-bin-tool", test_path, "-r", ",".join(runs)])
self.check_checkers_log(caplog, skip_checkers, runs)

import pytest
import logging

@pytest.mark.timeout(60) # Test fails if it runs longer than 60 seconds
@pytest.mark.skipif(not LONG_TESTS(), reason="Update flag tests are long tests")
def test_update(self, caplog):
test_path = str(Path(__file__).parent.resolve() / "csv")
Expand Down Expand Up @@ -275,6 +279,17 @@ def test_update(self, caplog):
) 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_unknown_warning(self, caplog):
"""Test that an "UNKNOWN" file generates a log (only in debug mode)"""

Expand Down Expand Up @@ -376,45 +391,93 @@ def check_string_in_file(filename, string_to_find):
if string_to_find in line:
return True
return False

import pytest
import requests
import logging
import time
from pathlib import Path
from cve_bin_tool.cli import main # Ensure this import matches your project structure


def is_nvd_reachable(retries=3, delay=5):
"""Check if the NVD API is reachable, with retries in case of errors."""
url = "https://services.nvd.nist.gov/rest/json/cves/1.0"
for attempt in range(retries):
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
return True
except requests.exceptions.ChunkedEncodingError:
if attempt < retries - 1:
print(f"⚠️ NVD API response broken. Retrying in {delay} seconds...")
time.sleep(delay)
else:
print("🚨 NVD API is unreachable after multiple attempts.")
return False
except requests.RequestException:
return False
return False


def check_string_in_file(file_path, search_string):
"""Check if a specific string is present in a file."""
with open(file_path, "r") as f:
return search_string in f.read()


def test_severity(capsys, caplog, tmp_path):
if not is_nvd_reachable():
pytest.skip("Skipping test_severity because the NVD API is unreachable.")

tempdir = tmp_path / "test_dir"
tempdir.mkdir()

# Check command line parameters - wrong case
with pytest.raises(SystemExit) as e:
main(["cve-bin-tool", "-S", "HIGH", str(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", str(tempdir)])
assert e.value.args[0] == 2

my_test_filename = "sevtest.csv"
my_test_filename_path = Path(my_test_filename)

# Remove the file if it already exists
if my_test_filename_path.exists():
my_test_filename_path.unlink()

# Run the scan and capture logs
with caplog.at_level(logging.DEBUG):
main(
[
"cve-bin-tool",
"-x",
"-f",
"csv",
"-o",
my_test_filename,
"-S",
"high",
str(tempdir), # Removed `self.tempdir`, now using `tempdir`
]
)

def test_severity(self, capsys, caplog):
# scan with severity setting to ensure only CVEs above severity threshold are reported
# Verify that no CVEs with a severity of Medium are reported
assert not check_string_in_file(my_test_filename, "MEDIUM"), "❌ MEDIUM severity CVEs should not be present!"

# 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
# Verify that CVEs with a higher severity are reported
assert check_string_in_file(my_test_filename, "HIGH"), "❌ HIGH severity CVEs not found!"

my_test_filename = "sevtest.csv"
my_test_filename_pathlib = Path(my_test_filename)
caplog.clear()

# Clean up after test
if my_test_filename_path.exists():
my_test_filename_path.unlink()

if my_test_filename_pathlib.exists():
my_test_filename_pathlib.unlink()
with caplog.at_level(logging.DEBUG):
main(
[
"cve-bin-tool",
"-x",
"-f",
"csv",
"-o",
my_test_filename,
"-S",
"high",
str(Path(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 my_test_filename_pathlib.exists():
my_test_filename_pathlib.unlink()

def test_CVSS_score(self, capsys, caplog):
# scan with severity score to ensure only CVEs above score threshold are reported
Expand Down