Coverage for lintro / parsers / osv_scanner / osv_scanner_issue.py: 100%
23 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Issue model for OSV-Scanner output."""
3from dataclasses import dataclass, field
4from typing import ClassVar
6from lintro.enums.severity_level import SeverityLevel
7from lintro.parsers.base_issue import BaseIssue
10@dataclass
11class OsvScannerIssue(BaseIssue):
12 """Represents a vulnerability found by OSV-Scanner.
14 Attributes:
15 DISPLAY_FIELD_MAP: Mapping of display field names to attribute names.
16 DEFAULT_SEVERITY: Fallback severity (ERROR for security vulnerabilities).
17 vuln_id: OSV vulnerability ID (e.g., GHSA-xxxx, CVE-xxxx, PYSEC-xxxx).
18 severity: Severity level (CRITICAL, HIGH, MEDIUM, LOW).
19 package_name: Name of the affected package.
20 package_version: Installed version of the affected package.
21 package_ecosystem: Ecosystem of the package (PyPI, npm, Go, etc.).
22 fixed_version: Version that fixes the vulnerability, if available.
23 """
25 DISPLAY_FIELD_MAP: ClassVar[dict[str, str]] = {
26 **BaseIssue.DISPLAY_FIELD_MAP,
27 "code": "vuln_id",
28 }
30 DEFAULT_SEVERITY: ClassVar[SeverityLevel] = SeverityLevel.ERROR
32 vuln_id: str = field(default="")
33 severity: str = field(default="MEDIUM")
34 package_name: str = field(default="")
35 package_version: str = field(default="")
36 package_ecosystem: str = field(default="")
37 fixed_version: str = field(default="")
39 def __post_init__(self) -> None:
40 """Initialize the inherited fields with formatted message."""
41 if not self.file:
42 self.file = "lockfile"
43 self.message = self._get_message()
45 def _get_message(self) -> str:
46 """Get the formatted issue message.
48 Returns:
49 Formatted issue message with vulnerability context.
50 """
51 parts = f"[{self.vuln_id}] {self.package_name}@{self.package_version}"
52 if self.fixed_version:
53 parts += f" (fix: {self.fixed_version})"
54 return parts