split total counts for other packages
This commit is contained in:
1 parent
66808d77f0
commit
9cabdefdf4
2 files changed
+45
-14
No files matched your search
@@ -1051,7 +1051,7 @@ def _chunk_list(items: list[object], size: int) -> list[list[object]]:
|
|||||||
|
|
||||||
|
|
||||||
def build_other_containers_bodies(
|
def build_other_containers_bodies(
|
||||||
rows: list[tuple[str, str, int, int, int]],
|
rows: list,
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
"""Split the summary by container groups so each message stays small."""
|
"""Split the summary by container groups so each message stays small."""
|
||||||
if not rows:
|
if not rows:
|
||||||
@@ -1059,14 +1059,34 @@ def build_other_containers_bodies(
|
|||||||
bodies: list[str] = []
|
bodies: list[str] = []
|
||||||
for chunk in _chunk_list(rows, 12):
|
for chunk in _chunk_list(rows, 12):
|
||||||
lines = ["Other containers with findings:", ""]
|
lines = ["Other containers with findings:", ""]
|
||||||
for image, container, total, fixable, unfixable in chunk:
|
for row in chunk:
|
||||||
|
if len(row) == 7:
|
||||||
|
image, container, total_all, fixable_all, unfixable_all, counts, fixable_counts = row
|
||||||
|
else:
|
||||||
|
image, container, total_all, fixable_all, unfixable_all = row
|
||||||
|
counts = {s: 0 for s in REPORTED_SEVERITIES}
|
||||||
|
fixable_counts = {s: 0 for s in REPORTED_SEVERITIES}
|
||||||
label = f"{image} [{container}]" if container else image
|
label = f"{image} [{container}]" if container else image
|
||||||
lines.append(f"* {label}: {fixable}/{total} (fixable/total)")
|
lines.append(label)
|
||||||
lines += ["", f"Total: {sum(row[2] for row in chunk)} CVE(s) in {len(chunk)} container(s)"]
|
lines.append(
|
||||||
|
" ".join(
|
||||||
|
f"{name[0]} {fixable_counts.get(name, 0)}/{counts.get(name, 0)}"
|
||||||
|
for name in REPORTED_SEVERITIES
|
||||||
|
)
|
||||||
|
)
|
||||||
|
lines.append(f"Total: {fixable_all}/{total_all}")
|
||||||
|
lines.append("")
|
||||||
|
# Remove trailing blank line
|
||||||
|
if lines and lines[-1] == "":
|
||||||
|
lines.pop()
|
||||||
|
total_cves = sum(row[2] for row in chunk)
|
||||||
|
fixable_cves = sum(row[3] for row in chunk)
|
||||||
|
lines += ["", f"Total: {fixable_cves}/{total_cves} in {len(chunk)} container(s)"]
|
||||||
bodies.append("\n".join(lines))
|
bodies.append("\n".join(lines))
|
||||||
if len(bodies) > 1:
|
if len(bodies) > 1:
|
||||||
overall = f"Total: {sum(row[2] for row in rows)} CVE(s) in {len(rows)} container(s)"
|
overall_fixable = sum(row[3] for row in rows)
|
||||||
bodies[-1] = bodies[-1] + "\n\n" + overall
|
overall_total = sum(row[2] for row in rows)
|
||||||
|
bodies[-1] = bodies[-1] + f"\n\nOverall: {overall_fixable}/{overall_total} in {len(rows)} container(s)"
|
||||||
return bodies
|
return bodies
|
||||||
|
|
||||||
|
|
||||||
@@ -1407,7 +1427,7 @@ def send_notifications(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# One summary notification for every other container.
|
# One summary notification for every other container.
|
||||||
rows: list[tuple[str, str, int, int, int]] = []
|
rows: list = []
|
||||||
for target in targets:
|
for target in targets:
|
||||||
result = aggregated.results.get(target.image)
|
result = aggregated.results.get(target.image)
|
||||||
if result is None:
|
if result is None:
|
||||||
@@ -1416,10 +1436,15 @@ def send_notifications(
|
|||||||
if not entries:
|
if not entries:
|
||||||
continue
|
continue
|
||||||
total, fixable, unfixable = split_counts(entries)
|
total, fixable, unfixable = split_counts(entries)
|
||||||
|
counts = severity_counts(entries)
|
||||||
|
fixable_counts = {severity: 0 for severity in REPORTED_SEVERITIES}
|
||||||
|
for entry in entries:
|
||||||
|
if entry.fixable:
|
||||||
|
fixable_counts[entry.severity] += 1
|
||||||
for container in target.containers or [""]:
|
for container in target.containers or [""]:
|
||||||
if container and container in important:
|
if container and container in important:
|
||||||
continue
|
continue
|
||||||
rows.append((target.image, container, total, fixable, unfixable))
|
rows.append((target.image, container, total, fixable, unfixable, counts, fixable_counts))
|
||||||
|
|
||||||
if rows:
|
if rows:
|
||||||
bodies = build_other_containers_bodies(rows)
|
bodies = build_other_containers_bodies(rows)
|
||||||
|
|||||||
+12
-6
@@ -498,15 +498,19 @@ class ReportTests(unittest.TestCase):
|
|||||||
def test_build_other_containers_body_has_counts_per_container(self) -> None:
|
def test_build_other_containers_body_has_counts_per_container(self) -> None:
|
||||||
bodies = scan.build_other_containers_bodies(
|
bodies = scan.build_other_containers_bodies(
|
||||||
[
|
[
|
||||||
("nginx:1.27", "web-worker", 3, 2, 1),
|
("nginx:1.27", "web-worker", 3, 2, 1, {"CRITICAL":1,"HIGH":2,"MEDIUM":0,"LOW":0}, {"CRITICAL":1,"HIGH":1,"MEDIUM":0,"LOW":0}),
|
||||||
("redis:7", "cache", 4, 0, 4),
|
("redis:7", "cache", 4, 0, 4, {"CRITICAL":0,"HIGH":4,"MEDIUM":0,"LOW":0}, {"CRITICAL":0,"HIGH":0,"MEDIUM":0,"LOW":0}),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
body = bodies[0]
|
body = bodies[0]
|
||||||
self.assertIn("Other containers with findings", body)
|
self.assertIn("Other containers with findings", body)
|
||||||
self.assertIn("nginx:1.27 [web-worker]: 2/3 (fixable/total)", body)
|
self.assertIn("nginx:1.27 [web-worker]", body)
|
||||||
self.assertIn("redis:7 [cache]: 0/4 (fixable/total)", body)
|
self.assertIn("C 1/1 H 1/2 M 0/0 L 0/0", body)
|
||||||
self.assertIn("Total: 7 CVE(s) in 2 container(s)", body)
|
self.assertIn("Total: 2/3", body)
|
||||||
|
self.assertIn("redis:7 [cache]", body)
|
||||||
|
self.assertIn("C 0/0 H 0/4 M 0/0 L 0/0", body)
|
||||||
|
self.assertIn("Total: 0/4", body)
|
||||||
|
self.assertIn("Total: 2/7 in 2 container(s)", body)
|
||||||
|
|
||||||
def test_build_missing_body_separates_missing_and_unscanned(self) -> None:
|
def test_build_missing_body_separates_missing_and_unscanned(self) -> None:
|
||||||
body = scan.build_missing_body(["gone"], ["web"])
|
body = scan.build_missing_body(["gone"], ["web"])
|
||||||
@@ -670,7 +674,9 @@ printf '%s\\n' "$*" >> "$APPRISE_LOG"
|
|||||||
self.assertIn("Container: web", notification)
|
self.assertIn("Container: web", notification)
|
||||||
self.assertIn("CVE-2026-0001", notification)
|
self.assertIn("CVE-2026-0001", notification)
|
||||||
self.assertIn("Vulnerability scan: other containers", notification)
|
self.assertIn("Vulnerability scan: other containers", notification)
|
||||||
self.assertIn("redis:7 [cache]: 1/1 (fixable/total)", notification)
|
self.assertIn("redis:7 [cache]", notification)
|
||||||
|
self.assertIn("C 0/0 H 0/1 M 0/0 L 0/0", notification)
|
||||||
|
self.assertIn("Total: 0/1", notification)
|
||||||
self.assertIn("1/1 (fixable/total)", notification)
|
self.assertIn("1/1 (fixable/total)", notification)
|
||||||
# The important container must not also appear in the summary.
|
# The important container must not also appear in the summary.
|
||||||
self.assertNotIn("testphp-php [web]", notification)
|
self.assertNotIn("testphp-php [web]", notification)
|
||||||
|
|||||||
Reference in new issue
Block a user