Coverage for lintro / parsers / bandit / bandit_issue.py: 100%

21 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-04-03 18:53 +0000

1"""Bandit issue model for security vulnerabilities.""" 

2 

3from dataclasses import dataclass, field 

4from typing import Any, ClassVar 

5 

6from lintro.parsers.base_issue import BaseIssue 

7 

8 

9@dataclass 

10class BanditIssue(BaseIssue): 

11 """Represents a security issue found by Bandit. 

12 

13 Attributes: 

14 DISPLAY_FIELD_MAP: Mapping of display field names to attribute names. 

15 col_offset: int: Column offset of the issue. 

16 issue_severity: str: Severity level (LOW, MEDIUM, HIGH). 

17 issue_confidence: str: Confidence level (LOW, MEDIUM, HIGH). 

18 test_id: str: Bandit test ID (e.g., B602, B301). 

19 test_name: str: Name of the test that found the issue. 

20 issue_text: str: Description of the security issue. 

21 more_info: str: URL with more information about the issue. 

22 cwe: dict[str, Any] | None: CWE (Common Weakness Enumeration) information. 

23 code_snippet: str: Code snippet containing the issue. 

24 line_range: list[int]: Range of lines containing the issue. 

25 """ 

26 

27 DISPLAY_FIELD_MAP: ClassVar[dict[str, str]] = { 

28 **BaseIssue.DISPLAY_FIELD_MAP, 

29 "code": "test_id", 

30 "message": "issue_text", 

31 "severity": "issue_severity", 

32 } 

33 

34 col_offset: int = field(default=0) 

35 issue_severity: str = field(default="UNKNOWN") 

36 issue_confidence: str = field(default="UNKNOWN") 

37 test_id: str = field(default="") 

38 test_name: str = field(default="") 

39 issue_text: str = field(default="") 

40 more_info: str = field(default="") 

41 cwe: dict[str, Any] | None = field(default=None) 

42 code_snippet: str | None = field(default=None) 

43 line_range: list[int] | None = field(default=None) 

44 

45 def __post_init__(self) -> None: 

46 """Initialize the inherited fields.""" 

47 # Map col_offset to column for BaseIssue compatibility 

48 self.column = self.col_offset 

49 # Set the message field to the computed value for general use 

50 self.message = self._get_message() 

51 

52 def _get_message(self) -> str: 

53 """Get the formatted issue message. 

54 

55 Returns: 

56 str: Formatted issue message. 

57 """ 

58 return ( 

59 f"[{self.test_id}:{self.test_name}] {self.issue_severity} severity, " 

60 f"{self.issue_confidence} confidence: {self.issue_text}" 

61 )