This commit is contained in:
David Duran Rosich committed 2026-10-25 11:44:58 +01:00
1 parent 77d064627a
commit 0fe06f2ba5
3 files changed
+68 -22

No files matched your search

+48 -15
View File
@@ -9,6 +9,7 @@ from __future__ import annotations
import io
import json
import os
import re
import shutil
import socketserver
import subprocess
@@ -85,6 +86,11 @@ def container(
return entry
def table_row_pattern(cells: list[str]) -> str:
"""Regex matching a table row regardless of column padding."""
return r"\|\s*" + r"\s*\|\s*".join(re.escape(cell) for cell in cells) + r"\s*\|"
class DockerDiscoveryTests(unittest.TestCase):
def test_images_in_use_returns_running_images(self) -> None:
with FakeDocker([container("a" * 64, "testphp-php"), container("b" * 64, "redis:7")]) as docker:
@@ -489,9 +495,9 @@ class ReportTests(unittest.TestCase):
body = scan.build_important_body(
"web", target, result, "/reports/x.json", "HIGH"
)
self.assertIn("| Image | Container | C | H |", body)
self.assertIn("| nginx:1.27 | web | 1/1 | 1/2 |", body)
self.assertNotIn("| M |", body)
self.assertRegex(body, table_row_pattern(["Image", "Container", "C", "H"]))
self.assertRegex(body, table_row_pattern(["nginx:1.27", "web", "1/1", "1/2"]))
self.assertNotRegex(body, r"\|\s*M\s*\|")
self.assertIn("CVE-1", body)
self.assertIn("CVE-2", body)
self.assertIn("CVE-5", body)
@@ -507,9 +513,9 @@ class ReportTests(unittest.TestCase):
self.assertIn("CVE-1", body)
self.assertNotIn("CVE-2", body)
self.assertNotIn("CVE-5", body)
self.assertIn("| Image | Container | C |", body)
self.assertIn("| nginx:1.27 | web | 1/1 |", body)
self.assertNotIn("| H |", body)
self.assertRegex(body, table_row_pattern(["Image", "Container", "C"]))
self.assertRegex(body, table_row_pattern(["nginx:1.27", "web", "1/1"]))
self.assertNotRegex(body, r"\|\s*H\s*\|")
self.assertNotIn("Total:", body)
def test_build_other_containers_body_has_counts_per_container(self) -> None:
@@ -522,10 +528,12 @@ class ReportTests(unittest.TestCase):
)
body = bodies[0]
self.assertIn("Other containers with findings", body)
self.assertIn("| Image | Container | C | H |", body)
self.assertIn("| nginx:1.27 | web-worker | 1/1 | 1/2 |", body)
self.assertIn("| redis:7 | cache | 0/0 | 0/4 |", body)
self.assertNotIn("| M |", body)
self.assertRegex(body, table_row_pattern(["Image", "Container", "C", "H"]))
self.assertRegex(
body, table_row_pattern(["nginx:1.27", "web-worker", "1/1", "1/2"])
)
self.assertRegex(body, table_row_pattern(["redis:7", "cache", "0/0", "0/4"]))
self.assertNotRegex(body, r"\|\s*M\s*\|")
self.assertNotIn("Total:", body)
self.assertNotIn("Overall:", body)
@@ -544,8 +552,8 @@ class ReportTests(unittest.TestCase):
[("web", target, result)], all_rows, "HIGH"
)
self.assertIn("Important containers:", body)
self.assertIn("| Image | Container | C | H |", body)
self.assertIn("| nginx:1.27 | web | 1/1 | 1/2 |", body)
self.assertRegex(body, table_row_pattern(["Image", "Container", "C", "H"]))
self.assertRegex(body, table_row_pattern(["nginx:1.27", "web", "1/1", "1/2"]))
self.assertIn("Packages:", body)
self.assertIn("libc 1.0 -> 1.1", body)
self.assertIn("openssl 3.0.1 -> 3.0.2", body)
@@ -554,6 +562,31 @@ class ReportTests(unittest.TestCase):
self.assertIn("Overall: 2/3 fixable/total in 1 container(s)", body)
self.assertNotIn("Total:", body)
def test_summary_table_pads_every_column(self) -> None:
table = scan.summary_table(
[
(
"nginx:1.27",
"web",
{"CRITICAL": 1, "HIGH": 2, "MEDIUM": 0, "LOW": 0},
{"CRITICAL": 1, "HIGH": 1, "MEDIUM": 0, "LOW": 0},
)
],
["CRITICAL", "HIGH"],
)
self.assertEqual(
table,
"\n".join(
[
"```",
"| Image | Container | C | H |",
"| ---------- | --------- | --- | --- |",
"| nginx:1.27 | web | 1/1 | 1/2 |",
"```",
]
),
)
def test_build_missing_body_separates_missing_and_unscanned(self) -> None:
body = scan.build_missing_body(["gone"], ["web"])
self.assertIn("not running", body)
@@ -690,7 +723,7 @@ printf '%s\\n' "$*" >> "$APPRISE_LOG"
self.assertNotIn("Total:", notification)
self.assertIn("No CVEs at or above", notification)
self.assertIn("Vulnerability scan: summary", notification)
self.assertIn("| alpine:3.20 | web | 0/0 | 0/0 |", notification)
self.assertRegex(notification, table_row_pattern(["alpine:3.20", "web", "0/0", "0/0"]))
self.assertIn("Overall: 0/0 fixable/total in 1 container(s)", notification)
def test_notification_includes_container(self) -> None:
@@ -716,10 +749,10 @@ printf '%s\\n' "$*" >> "$APPRISE_LOG"
self.assertEqual(code, 1)
notification = Path(self.apprise_log).read_text()
self.assertIn("Vulnerability scan: web (testphp-php)", notification)
self.assertIn("| testphp-php | web | 1/1 | 0/0 |", notification)
self.assertRegex(notification, table_row_pattern(["testphp-php", "web", "1/1", "0/0"]))
self.assertIn("CVE-2026-0001", notification)
self.assertIn("Vulnerability scan: other containers", notification)
self.assertIn("| redis:7 | cache | 1/1 | 0/0 |", notification)
self.assertRegex(notification, table_row_pattern(["redis:7", "cache", "1/1", "0/0"]))
self.assertNotIn("Total:", notification)
self.assertIn("Vulnerability scan: summary", notification)
self.assertIn("Overall: 2/2 fixable/total in 2 container(s)", notification)