Initial curated ITWorx_MCP_Hub source from 368fba691ea8d23403b4d56b53b5ec670d7c5020
This commit is contained in:
commit
cb5be898ea
663 files changed
+82674
No files matched your search
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Draft CVE exception entries from a vulnerability scan summary.
|
||||
|
||||
Produces one exception entry per (package, CVE) pair for every CRITICAL/HIGH
|
||||
finding in --scan-summary (the format scripts that produce
|
||||
evidence/*/vulnerability-scan-summary.json already write). Every drafted
|
||||
entry has ``approvalStatus: "pending"`` and empty ``riskOwner``/``approver``
|
||||
fields -- this script only assembles the factual, machine-derivable parts
|
||||
(CVE id, package, severity, affected image digests, scan date). It
|
||||
deliberately cannot grant approval on anyone's behalf; a human risk owner
|
||||
must review each entry and set approvalStatus to "approved" (or "rejected")
|
||||
with their name before scripts/check_cve_exceptions.py will treat it as
|
||||
satisfying the release gate for that finding.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from datetime import date, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
_ROOT_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_ROOT_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_ROOT_DIR))
|
||||
|
||||
from scripts.packlib import brussels_now, load_json # noqa: E402
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--scan-summary", required=True, type=Path)
|
||||
parser.add_argument(
|
||||
"--image-digests",
|
||||
type=Path,
|
||||
help="evidence/<packet>/image-digests.json to populate affectedImageDigests from.",
|
||||
)
|
||||
parser.add_argument("--evidence-reference", required=True)
|
||||
parser.add_argument("--output", required=True, type=Path)
|
||||
parser.add_argument("--expiry-days", type=int, default=90)
|
||||
parser.add_argument("--rescan-days", type=int, default=30)
|
||||
args = parser.parse_args()
|
||||
|
||||
scan = load_json(args.scan_summary)
|
||||
scan_date = scan.get("scannedAt", brussels_now())[:10]
|
||||
scanner = f"trivy {scan.get('trivyVersion', 'unknown')}"
|
||||
|
||||
affected_digests: dict[str, str] = {}
|
||||
if args.image_digests:
|
||||
digest_doc = load_json(args.image_digests)
|
||||
for service, entry in digest_doc.get("images", {}).items():
|
||||
digest = entry.get("digest") or entry.get("imageId")
|
||||
if digest:
|
||||
affected_digests[service] = digest
|
||||
|
||||
today = date.fromisoformat(scan_date) if len(scan_date) == 10 else date.today()
|
||||
expiry = (today + timedelta(days=args.expiry_days)).isoformat()
|
||||
rescan = (today + timedelta(days=args.rescan_days)).isoformat()
|
||||
|
||||
exceptions = []
|
||||
for row in scan.get("unresolvedCriticalOrHigh", []):
|
||||
package = row["package"]
|
||||
for cve in row["cves"]:
|
||||
exceptions.append(
|
||||
{
|
||||
"id": f"{package}-{cve}",
|
||||
"cve": cve,
|
||||
"package": package,
|
||||
"installedVersion": row.get("installedVersion"),
|
||||
"severity": row.get("severity"),
|
||||
"scanner": scanner,
|
||||
"scanDate": scan_date,
|
||||
"affectedImageDigests": dict(affected_digests),
|
||||
"reachabilityAnalysis": row.get("reachability", ""),
|
||||
"compensatingControls": "",
|
||||
"riskOwner": "",
|
||||
"approver": "",
|
||||
"approvalStatus": "pending",
|
||||
"expiryDate": expiry,
|
||||
"mandatoryRescanDate": rescan,
|
||||
"remediationTrigger": (
|
||||
f"an upstream fixed version becomes available for {package}"
|
||||
if row.get("fixedVersion") is None
|
||||
else f"upgrade to {row.get('fixedVersion')} or later"
|
||||
),
|
||||
"evidenceReference": args.evidence_reference,
|
||||
}
|
||||
)
|
||||
|
||||
document = {
|
||||
"schemaVersion": "1.0",
|
||||
"generatedAt": brussels_now(),
|
||||
"exceptions": exceptions,
|
||||
}
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(json.dumps(document, indent=2) + "\n", encoding="utf-8", newline="")
|
||||
print(f"Drafted {len(exceptions)} exception(s) (all pending review) to {args.output}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user