90 lines
3.0 KiB
Python
90 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
|
|
@dataclass
|
|
class Vulnerability:
|
|
id: str
|
|
package_name: str
|
|
current_version: str
|
|
severity: str
|
|
title: str
|
|
description: str
|
|
affected_versions: list[str]
|
|
fixed_version: str | None
|
|
published: str
|
|
modified: str
|
|
cvss_score: float | None = None
|
|
cwe: list[str] = field(default_factory=list)
|
|
references: list[str] = field(default_factory=list)
|
|
source: str = "unknown"
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"id": self.id,
|
|
"package_name": self.package_name,
|
|
"current_version": self.current_version,
|
|
"severity": self.severity,
|
|
"title": self.title,
|
|
"description": self.description,
|
|
"affected_versions": self.affected_versions,
|
|
"fixed_version": self.fixed_version,
|
|
"published": self.published,
|
|
"modified": self.modified,
|
|
"cvss_score": self.cvss_score,
|
|
"cwe": self.cwe,
|
|
"references": self.references,
|
|
"source": self.source,
|
|
}
|
|
|
|
@classmethod
|
|
def from_osv(cls, data: dict[str, Any], package_name: str, current_version: str) -> "Vulnerability":
|
|
affected = data.get("affected", [])
|
|
versions = []
|
|
fixed_version = None
|
|
|
|
if affected:
|
|
pkg = affected[0]
|
|
ranges = pkg.get("ranges", [])
|
|
for range_info in ranges:
|
|
if range_info.get("type") == "SEMVER":
|
|
for event in range_info.get("events", []):
|
|
if event.get("type") == "introduced":
|
|
versions.append(event.get("value", ""))
|
|
elif event.get("type") == "fixed":
|
|
fixed_version = event.get("value")
|
|
|
|
severity = "medium"
|
|
cvss = None
|
|
for severity_info in data.get("severity", []):
|
|
if severity_info.get("type") == "CVSS_V3":
|
|
cvss = float(severity_info.get("score", 0))
|
|
if cvss >= 9.0:
|
|
severity = "critical"
|
|
elif cvss >= 7.0:
|
|
severity = "high"
|
|
elif cvss >= 4.0:
|
|
severity = "medium"
|
|
else:
|
|
severity = "low"
|
|
break
|
|
|
|
return cls(
|
|
id=data.get("id", ""),
|
|
package_name=package_name,
|
|
current_version=current_version,
|
|
severity=severity,
|
|
title=data.get("summary", ""),
|
|
description=data.get("details", ""),
|
|
affected_versions=versions,
|
|
fixed_version=fixed_version,
|
|
published=data.get("published", ""),
|
|
modified=data.get("modified", ""),
|
|
cvss_score=cvss,
|
|
cwe=data.get("cwe", []),
|
|
references=[ref.get("url", "") for ref in data.get("references", [])],
|
|
source="OSV",
|
|
)
|