Improve recipe advisory coverage and report non-CVE fixes
This commit is contained in:
@@ -52,7 +52,7 @@ def vendor(url, cves=(), status="ok"):
|
||||
|
||||
|
||||
def run_scan(gh_entries=(), vendor_entries=(), tag_dates=None, *, v_from=None, v_to=None,
|
||||
images=None, recipe="fixture", urls=None, releases=None):
|
||||
images=None, recipe="fixture", urls=None, releases=None, image_sources=None):
|
||||
"""scan() with every network call replaced by fixtures.
|
||||
|
||||
`releases` maps CVE id -> tags whose release notes name it (the third, release-note method)."""
|
||||
@@ -62,6 +62,7 @@ def run_scan(gh_entries=(), vendor_entries=(), tag_dates=None, *, v_from=None, v
|
||||
with unittest.mock.patch.object(A, "registry_urls", lambda r, d: (list(urls), "/fake/reg.md")), \
|
||||
unittest.mock.patch.object(A, "github_advisories", lambda u: list(gh_entries)), \
|
||||
unittest.mock.patch.object(A, "vendor_pages", lambda u: list(vendor_entries)), \
|
||||
unittest.mock.patch.object(A, "registry_image_sources", lambda r, d: image_sources or {}), \
|
||||
unittest.mock.patch.object(A, "osv", lambda r, v: None), \
|
||||
unittest.mock.patch.object(A, "_tag_date", lambda o, r, v: tag_dates.get(v)), \
|
||||
unittest.mock.patch.object(A, "release_fix_versions", lambda src, cve: list(releases.get(cve, []))):
|
||||
@@ -157,9 +158,23 @@ class TestRegistryUrls(unittest.TestCase):
|
||||
def test_prose_ellipsis_is_not_a_security_source(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
urls, _ = self._write(directory,
|
||||
"https://github.com/cryptpad/cryptpad and example `https://…` URLs")
|
||||
"https://github.com/cryptpad/cryptpad and example `https://…` URLs "
|
||||
"http://docspec:3000/conversion http://127.0.0.1:3000/health")
|
||||
self.assertEqual(urls, ["https://github.com/cryptpad/cryptpad"])
|
||||
|
||||
def test_image_source_table_maps_monorepo_images(self):
|
||||
mapping = A.registry_image_sources("lasuite-drive", str(HERE / "upstream"))
|
||||
self.assertIn("github-advisories:suitenumerique/drive", mapping["drive-backend"])
|
||||
self.assertIn("github-advisories:CollaboraOnline/online", mapping["code"])
|
||||
|
||||
def test_common_database_cpes_follow_registry_images(self):
|
||||
self.assertIn(("postgres", A.COMMON_IMAGE_CPES["postgres"]),
|
||||
A.registry_cpes("immich", str(HERE / "upstream")))
|
||||
self.assertIn(("mariadb", A.COMMON_IMAGE_CPES["mariadb"]),
|
||||
A.registry_cpes("gitea", str(HERE / "upstream")))
|
||||
self.assertIn(("rustdesk-server", "cpe:2.3:a:rustdesk:rustdesk_server:*:*:*:*:oss:*:*:*"),
|
||||
A.registry_cpes("rustdesk-server", str(HERE / "upstream")))
|
||||
|
||||
def test_strips_trailing_markdown_punctuation(self):
|
||||
# Production defect: a captured backtick 404'd the fetch and rendered n8n/immich as '?'.
|
||||
import tempfile
|
||||
@@ -181,6 +196,25 @@ class TestRegistryUrls(unittest.TestCase):
|
||||
self.assertEqual((urls, path), ([], None))
|
||||
|
||||
|
||||
class TestNvdCompleteness(unittest.TestCase):
|
||||
def test_truncated_results_are_not_a_clean_zero(self):
|
||||
payload = json.dumps({"totalResults": 2, "vulnerabilities": [{"cve": {"id": "CVE-2026-0001"}}]})
|
||||
with unittest.mock.patch.object(A, "_fetch", return_value=payload):
|
||||
row = A.nvd_advisories("cpe:2.3:a:example:server:*:*:*:*:*:*:*:*", "server")
|
||||
self.assertEqual(row["status"], "error: NVD result set truncated")
|
||||
self.assertEqual(row["advisories"], [])
|
||||
|
||||
def test_database_backport_is_not_credited_again_on_major_upgrade(self):
|
||||
ranges = [
|
||||
{"version": "*", "versionStartIncluding": "15.0", "versionEndExcluding": "15.14"},
|
||||
{"version": "*", "versionStartIncluding": "16.0", "versionEndExcluding": "16.5"},
|
||||
]
|
||||
self.assertIs(A._nvd_affects("15.13", ranges), True)
|
||||
self.assertIs(A._nvd_affects("15.19", ranges), False)
|
||||
self.assertIs(A._nvd_affects("18.6", ranges), False)
|
||||
self.assertIsNone(A._nvd_affects("15-alpine", ranges))
|
||||
|
||||
|
||||
# ── C. --image argument parsing ───────────────────────────────────────────────────────────────────
|
||||
|
||||
class TestImageArgParsing(unittest.TestCase):
|
||||
@@ -306,6 +340,24 @@ class TestPerImageWindows(unittest.TestCase):
|
||||
self.assertEqual(rep["unmatched_image_windows"], ["nosuchimage"])
|
||||
self.assertIsNone(rep["cve_count_fixed"])
|
||||
|
||||
def test_registry_maps_image_to_differently_named_source(self):
|
||||
rep = run_scan([self.APP, gh("suitenumerique/drive", [adv("CVE-DRIVE-1", patched="0.25.3")])],
|
||||
v_from="3.5.3", v_to="3.5.4", images=[("drive-backend", "0.22.0", "0.25.3")],
|
||||
urls=self.URLS,
|
||||
image_sources={"drive-backend": {"github-advisories:suitenumerique/drive"}})
|
||||
self.assertEqual(rep.get("unmatched_image_windows"), None)
|
||||
self.assertIn("CVE-DRIVE-1", rep["fixed_by_this_upgrade"])
|
||||
|
||||
def test_monorepo_images_share_identical_window(self):
|
||||
source = "github-advisories:suitenumerique/drive"
|
||||
rep = run_scan([gh("suitenumerique/drive", [adv("CVE-DRIVE-1", patched="0.25.3")])],
|
||||
v_from="0.22.0", v_to="0.25.3",
|
||||
images=[("drive-backend", "0.22.0", "0.25.3")],
|
||||
image_sources={"drive-backend": {source}})
|
||||
self.assertTrue(rep["count_known"])
|
||||
self.assertEqual(rep.get("unmatched_image_windows"), None)
|
||||
self.assertEqual(rep["cve_count_fixed"], 1)
|
||||
|
||||
|
||||
class TestSchemeChangeDateFallback(unittest.TestCase):
|
||||
DATES = {"3.5.3": "2025-12-30T00:00:00Z", "2026.7.1": "2026-07-31T00:00:00Z"}
|
||||
@@ -367,6 +419,15 @@ class TestCountGuarantees(unittest.TestCase):
|
||||
self.assertTrue(rep["count_known"])
|
||||
self.assertIn("0 identified", A.markdown(rep))
|
||||
|
||||
def test_ghsa_without_cve_is_preserved_as_security_advisory(self):
|
||||
entry = {"cve": None, "ghsa": "GHSA-aaaa-bbbb-cccc", "severity": "low",
|
||||
"patched": "1.1", "summary": "security fix", "published_at": None}
|
||||
rep = run_scan([gh("app/app", [entry])], v_from="1.0", v_to="1.1")
|
||||
self.assertTrue(rep["count_known"])
|
||||
self.assertEqual(rep["cve_count_fixed"], 0)
|
||||
self.assertEqual(rep["fixed_non_cve_advisories"], ["GHSA-aaaa-bbbb-cccc"])
|
||||
self.assertIn("use YES", A.markdown(rep))
|
||||
|
||||
def test_404_advisory_feed_is_benign_not_a_failure(self):
|
||||
rep = run_scan([gh("app/app", [adv("CVE-1", patched="1.1")]),
|
||||
gh("side/car", [], status="no-advisories-published")],
|
||||
|
||||
Reference in New Issue
Block a user