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", )