from __future__ import annotations from abc import ABC, abstractmethod from dataclasses import dataclass, field from typing import Any @dataclass class AuditResult: vulnerabilities: list[dict[str, Any]] = field(default_factory=list) outdated: list[dict[str, Any]] = field(default_factory=list) license_issues: list[dict[str, Any]] = field(default_factory=list) unused: list[dict[str, Any]] = field(default_factory=list) scanned_files: list[str] = field(default_factory=list) scanned_count: int = 0 error_count: int = 0 scan_duration: float = 0.0 def to_dict(self) -> dict[str, Any]: return { "vulnerabilities": self.vulnerabilities, "outdated": self.outdated, "license_issues": self.license_issues, "unused": self.unused, "scanned_files": self.scanned_files, "scanned_count": self.scanned_count, "error_count": self.error_count, "scan_duration": self.scan_duration, "summary": self.get_summary(), } def get_summary(self) -> dict[str, Any]: severity_counts: dict[str, int] = {"critical": 0, "high": 0, "medium": 0, "low": 0} for vuln in self.vulnerabilities: severity = vuln.get("severity", "unknown") if severity in severity_counts: severity_counts[severity] += 1 return { "total_vulnerabilities": len(self.vulnerabilities), "severity_breakdown": severity_counts, "total_outdated": len(self.outdated), "total_license_issues": len(self.license_issues), "total_unused": len(self.unused), } class Formatter(ABC): def __init__(self, use_color: bool = True, verbosity: str = "info"): self.use_color = use_color self.verbosity = verbosity @abstractmethod def format(self, result: AuditResult) -> str: pass def verbose(self, message: str) -> None: if self.verbosity == "debug": self._log(message) def _log(self, message: str) -> None: print(message)