diff --git a/local-app/python-tools/cross-organization/assess_check_ecr.py b/local-app/python-tools/cross-organization/assess_check_ecr.py index f52a407e..82b16897 100755 --- a/local-app/python-tools/cross-organization/assess_check_ecr.py +++ b/local-app/python-tools/cross-organization/assess_check_ecr.py @@ -1,10 +1,11 @@ #!/usr/bin/env python + import json, argparse, sys, os, glob from datetime import datetime, timezone from collections import Counter, defaultdict # --- VERSIONING --- -__version__ = "1.3.1" +__version__ = "1.3.2" def find_latest_file(pattern): files = glob.glob(pattern) @@ -28,7 +29,7 @@ def bucket_age(days, counters): else: counters['<30'] += 1 def main(): - parser = argparse.ArgumentParser(description="ECR Full Spectrum Assessor - v1.3.1") + parser = argparse.ArgumentParser(description="ECR Full Spectrum Assessor - v1.3.2") parser.add_argument("--input", help="JSON audit file") args = parser.parse_args() @@ -53,6 +54,9 @@ def main(): "org_vulns": Counter(), "scanned_imgs": 0 } + # Tracking for duplicates using a Counter for digests + digest_tracker = Counter() + for idx, account in enumerate(data, 1): checks = account.get("data", {}) for key, val in checks.items(): @@ -74,11 +78,14 @@ def main(): for img in images: # Security - # FIX: Ensure img is a dictionary before calling .get() - # If img is a single-element list containing a dict, use img[0] if isinstance(img, list) and len(img) > 0: img = img[0] + # ADD: Record digest for duplicate checking + digest = img.get("image_digest") + if digest: + digest_tracker[digest] += 1 + counts = img.get("severity_counts", {}) if counts: stats["scanned_imgs"] += 1 @@ -108,6 +115,17 @@ def main(): print(f" --- Security & Vulnerabilities ---") print(f" Scan Coverage: {stats['scanned_imgs']} of {stats['total_images']} images scanned") print(f" Org Totals: " + " | ".join([f"{s}: {stats['org_vulns'][s]:,}" for s in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]])) + + # ADD: Duplicate Image Audit Summary + duplicates = {d: c for d, c in digest_tracker.items() if c > 1} + print(f"\n --- Duplicate Image Audit ---") + print(f" Total Unique Digests: {len(digest_tracker)}") + print(f" Total Duplicated Image Instances: {sum(duplicates.values())} (across {len(duplicates)} unique digests)") + if duplicates: + print(f" {'Digest':<75} | {'Instance Count'}") + print(f" {'-'*75} | {'-'*14}") + for d, c in sorted(duplicates.items(), key=lambda x: x[1], reverse=True): + print(f" {d:<75} | {c}") print(f"\n --- Age Distribution (Days since Push vs Pull) ---") print(f" Average Image Age: {avg_push_age:.1f} days")