Coverage for /home/benjarobin/Bootlin/projects/Schneider-Electric-Senux/sbom-cve-check/src/sbom_cve_check/cve_db/annot_spdx2.py: 52%

56 statements  

« prev     ^ index     » next       coverage.py v7.11.1, created at 2025-11-28 15:37 +0100

1# -*- coding: utf-8 -*- 

2# SPDX-License-Identifier: GPL-2.0-only 

3 

4import re 

5from collections.abc import Generator, Iterable 

6from datetime import datetime 

7from typing import Any 

8 

9from ..sbom import sbom_spdx2 

10from ..sbom.component import CompId 

11from ..vuln.cpe import Cpe23 

12from ..vuln.cve import ( 

13 CveId, 

14 CveVexAssessment, 

15 CveVexFixedAssessment, 

16) 

17from ..vuln.version import SemVerRange 

18from .annot_base import AnnotDatabase, AnnotDbEntry 

19from .db_base import CveDatabase 

20 

21 

22class Spdx2AnnotEntry(AnnotDbEntry): 

23 def __init__( 

24 self, 

25 parent_db: CveDatabase, 

26 cve_id: CveId, 

27 cpes: set[Cpe23], 

28 pkg_version: str | None, 

29 ) -> None: 

30 super().__init__(parent_db) 

31 self._cve_id = cve_id 

32 self._cpes = cpes 

33 self._pkg_version = pkg_version 

34 

35 def add_cpes(self, cpes: Iterable[Cpe23]) -> None: 

36 self._cpes.update(cpes) 

37 

38 @property 

39 def identifier(self) -> CveId: 

40 return self._cve_id 

41 

42 @property 

43 def date_modified(self) -> datetime | None: 

44 return None 

45 

46 @property 

47 def description(self) -> str | None: 

48 return None 

49 

50 @property 

51 def vex_assessment(self) -> CveVexAssessment | None: 

52 return CveVexFixedAssessment(vex_version="1.0", status_notes="patched") 

53 

54 def _iterate_cpes(self, pkg: Any) -> Generator[Cpe23, None, None]: 

55 yield from self._cpes 

56 

57 def get_associated_sem_ver_ranges( 

58 self, comp_ids: Iterable[CompId] 

59 ) -> Iterable[SemVerRange]: 

60 return self._get_associated_sem_ver_ranges(comp_ids, self._pkg_version) 

61 

62 

63class Spdx2AnnotDatabase(AnnotDatabase): 

64 def __init__( 

65 self, 

66 name: str, 

67 sbom: "sbom_spdx2.Spdx2Sbom", 

68 **kwargs: Any, 

69 ) -> None: 

70 super().__init__(name, **kwargs) 

71 self._sbom = sbom 

72 self._vulns: dict[CveId, Spdx2AnnotEntry] = {} 

73 

74 def _initialize(self) -> None: 

75 re_cve = re.compile(r"CVE-[0-9]+-[0-9]+") 

76 

77 for _, recipe_pkg in self._sbom.iterate_recipes(): 

78 cpes = sbom_spdx2.parse_ext_refs_cpe(recipe_pkg) 

79 pkg_vers: str | None = recipe_pkg.get("versionInfo") 

80 source_info: str = recipe_pkg.get("sourceInfo", "") 

81 

82 for cve in re_cve.findall(source_info): 

83 cve_id = CveId(cve) 

84 annot = self._vulns.get(cve_id) 

85 if annot: 

86 annot.add_cpes(cpes) 

87 else: 

88 self._vulns[cve_id] = Spdx2AnnotEntry(self, cve_id, cpes, pkg_vers) 

89 

90 def get_cve(self, cve_id: CveId) -> Spdx2AnnotEntry | None: 

91 return self._vulns.get(cve_id) 

92 

93 def iterate_cves(self) -> Generator[Spdx2AnnotEntry, None, None]: 

94 yield from self._vulns.values()