Integrate metrics from metrics.json into the report pdf.
This commit is contained in:
1 parent
9d7df77923
commit
9247608a9f
5 files changed
+155
-18
No files matched your search
+57
-10
@@ -123,7 +123,9 @@ def _dependency_metrics(readings: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
"impact": _impact(scored),
|
||||
"exploitability": _exploitability(scored, readings),
|
||||
"remediation": _remediation(readings),
|
||||
"age": _age(readings),
|
||||
"temporal": _temporal(readings),
|
||||
"taxonomy": _taxonomy(readings),
|
||||
"affected_surface": _affected_surface(readings),
|
||||
}
|
||||
|
||||
|
||||
@@ -255,7 +257,7 @@ def _remediation(readings: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _age(readings: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
def _temporal(readings: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
dated = []
|
||||
for one in readings:
|
||||
stated = one["finding"].get("published")
|
||||
@@ -265,13 +267,58 @@ def _age(readings: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
except ValueError:
|
||||
continue
|
||||
if not dated:
|
||||
return {"newest": None, "oldest": None, "mean_days": None, "median_days": None, "coverage": 0}
|
||||
dated.sort()
|
||||
days = [(datetime.now(UTC) - date.astimezone(UTC)).days for date, _ in dated]
|
||||
age = {"newest": None, "oldest": None, "mean_days": None, "median_days": None, "coverage": 0}
|
||||
else:
|
||||
dated.sort()
|
||||
days = [(datetime.now(UTC) - date.astimezone(UTC)).days for date, _ in dated]
|
||||
age = {
|
||||
"newest": {"cve": dated[-1][1], "published": dated[-1][0].isoformat(), "days": days[-1]},
|
||||
"oldest": {"cve": dated[0][1], "published": dated[0][0].isoformat(), "days": days[0]},
|
||||
"mean_days": round(statistics.fmean(days)),
|
||||
"median_days": round(statistics.median(days)),
|
||||
"coverage": len(dated),
|
||||
}
|
||||
|
||||
return {"published": age, "time_to_exploit_days": None, "cve_volume_trends": None}
|
||||
|
||||
|
||||
def _taxonomy(readings: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
cwes: Counter[str] = Counter()
|
||||
for one in readings:
|
||||
vulnerability = one["finding"]
|
||||
values = vulnerability.get("cwes") or []
|
||||
if not values and vulnerability.get("cweId") is not None:
|
||||
values = [vulnerability["cweId"]]
|
||||
for value in values:
|
||||
if isinstance(value, dict):
|
||||
value = value.get("cweId")
|
||||
if value is not None:
|
||||
cwes[str(value) if str(value).startswith("CWE-") else f"CWE-{value}"] += 1
|
||||
|
||||
return {
|
||||
"newest": {"cve": dated[-1][1], "published": dated[-1][0].isoformat(), "days": days[-1]},
|
||||
"oldest": {"cve": dated[0][1], "published": dated[0][0].isoformat(), "days": days[0]},
|
||||
"mean_days": round(statistics.fmean(days)),
|
||||
"median_days": round(statistics.median(days)),
|
||||
"coverage": len(dated),
|
||||
"cwe_counts": dict(cwes.most_common()),
|
||||
"coverage": sum(cwes.values()),
|
||||
"abstraction_level": None,
|
||||
"relationships": None,
|
||||
}
|
||||
|
||||
|
||||
def _affected_surface(readings: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
components = [one["component"] for one in readings]
|
||||
names = {str(component.get("name")) for component in components if component.get("name")}
|
||||
versions = {str(component.get("version")) for component in components if component.get("version")}
|
||||
vendors = set()
|
||||
for component in components:
|
||||
purl = component.get("purl")
|
||||
if isinstance(purl, str) and purl.startswith("pkg:"):
|
||||
coordinate = purl[4:].split("@", 1)[0]
|
||||
parts = coordinate.split("/")
|
||||
if len(parts) > 2 and parts[1]:
|
||||
vendors.add(parts[1])
|
||||
|
||||
return {
|
||||
"products": len(names),
|
||||
"versions": len(versions),
|
||||
"version_ranges": None,
|
||||
"vendors": sorted(vendors),
|
||||
}
|
||||
Reference in new issue
Block a user