35
35
from typing import Set
36
36
from typing import Tuple
37
37
38
+ import pytz
38
39
from binaryornot .helpers import is_binary_string
40
+ from dateutil import parser as dateparser
39
41
from git import DiffIndex
40
42
from git import Repo
41
43
from license_expression import Licensing
42
44
from packageurl import PackageURL
45
+ from univers .version_range import RANGE_CLASS_BY_SCHEMES
43
46
from univers .version_range import VersionRange
44
47
from univers .versions import Version
45
48
@@ -521,13 +524,13 @@ class OvalImporter(Importer):
521
524
"""
522
525
523
526
@staticmethod
524
- def create_purl (pkg_name : str , pkg_version : str , pkg_data : Mapping ) -> PackageURL :
527
+ def create_purl (pkg_name : str , pkg_data : Mapping ) -> PackageURL :
525
528
"""
526
529
Helper method for creating different purls for subclasses without them reimplementing
527
530
get_data_from_xml_doc method
528
531
Note: pkg_data must include 'type' of package
529
532
"""
530
- return PackageURL (name = pkg_name , version = pkg_version , ** pkg_data )
533
+ return PackageURL (name = pkg_name , ** pkg_data )
531
534
532
535
@staticmethod
533
536
def _collect_pkgs (parsed_oval_data : Mapping ) -> Set :
@@ -561,28 +564,17 @@ def advisory_data(self) -> List[AdvisoryData]:
561
564
for metadata , oval_file in self ._fetch ():
562
565
try :
563
566
oval_data = self .get_data_from_xml_doc (oval_file , metadata )
564
- yield oval_data
567
+ yield from oval_data
565
568
except Exception :
566
569
logger .error (
567
570
f"Failed to get updated_advisories: { oval_file !r} "
568
571
f"with { metadata !r} :\n " + traceback .format_exc ()
569
572
)
570
573
continue
571
574
572
- def set_api (self , all_pkgs : Iterable [str ]):
573
- """
574
- This method loads the self.pkg_manager_api with the specified packages.
575
- It fetches and caches all the versions of these packages and exposes
576
- them through self.pkg_manager_api.get(<package_name>). Example
577
-
578
- >> self.set_api(['electron'])
579
- Assume 'electron' has only versions 1.0.0 and 1.2.0
580
- >> assert self.pkg_manager_api.get('electron') == {'1.0.0','1.2.0'}
581
-
582
- """
583
- raise NotImplementedError
584
-
585
- def get_data_from_xml_doc (self , xml_doc : ET .ElementTree , pkg_metadata = {}) -> List [AdvisoryData ]:
575
+ def get_data_from_xml_doc (
576
+ self , xml_doc : ET .ElementTree , pkg_metadata = {}
577
+ ) -> Iterable [AdvisoryData ]:
586
578
"""
587
579
The orchestration method of the OvalDataSource. This method breaks an
588
580
OVAL xml ElementTree into a list of `Advisory`.
@@ -593,12 +585,10 @@ def get_data_from_xml_doc(self, xml_doc: ET.ElementTree, pkg_metadata={}) -> Lis
593
585
Example value of pkg_metadata:
594
586
{"type":"deb","qualifiers":{"distro":"buster"} }
595
587
"""
596
-
597
- all_adv = []
598
- oval_doc = OvalParser (self .translations , xml_doc )
599
- raw_data = oval_doc .get_data ()
600
- all_pkgs = self ._collect_pkgs (raw_data )
601
- self .set_api (all_pkgs )
588
+ oval_parsed_data = OvalParser (self .translations , xml_doc )
589
+ raw_data = oval_parsed_data .get_data ()
590
+ oval_doc = oval_parsed_data .oval_document
591
+ timestamp = oval_doc .getGenerator ().getTimestamp ()
602
592
603
593
# convert definition_data to Advisory objects
604
594
for definition_data in raw_data :
@@ -610,49 +600,31 @@ def get_data_from_xml_doc(self, xml_doc: ET.ElementTree, pkg_metadata={}) -> Lis
610
600
affected_packages = []
611
601
for test_data in definition_data ["test_data" ]:
612
602
for package_name in test_data ["package_list" ]:
613
- if package_name and len (package_name ) >= 50 :
614
- continue
615
-
616
- affected_version_range = test_data ["version_ranges" ] or set ()
617
- version_class = version_class_by_package_type [pkg_metadata ["type" ]]
618
- version_scheme = version_class .scheme
619
-
620
- affected_version_range = VersionRange .from_scheme_version_spec_string (
621
- version_scheme , affected_version_range
622
- )
623
- all_versions = self .pkg_manager_api .get (package_name ).valid_versions
624
-
625
- # FIXME: what is this 50 DB limit? that's too small for versions
626
- # FIXME: we should not drop data this way
627
- # This filter is for filtering out long versions.
628
- # 50 is limit because that's what db permits atm.
629
- all_versions = [version for version in all_versions if len (version ) < 50 ]
630
- if not all_versions :
631
- continue
632
-
633
- affected_purls = []
634
- safe_purls = []
635
- for version in all_versions :
636
- purl = self .create_purl (
637
- pkg_name = package_name ,
638
- pkg_version = version ,
639
- pkg_data = pkg_metadata ,
603
+ affected_version_range = test_data ["version_ranges" ]
604
+ vrc = RANGE_CLASS_BY_SCHEMES [pkg_metadata ["type" ]]
605
+ if affected_version_range :
606
+ try :
607
+ affected_version_range = vrc .from_native (affected_version_range )
608
+ except Exception as e :
609
+ logger .error (
610
+ f"Failed to parse version range { affected_version_range !r} "
611
+ f"for package { package_name !r} :\n { e } "
612
+ )
613
+ continue
614
+ if package_name :
615
+ affected_packages .append (
616
+ AffectedPackage (
617
+ package = self .create_purl (package_name , pkg_metadata ),
618
+ affected_version_range = affected_version_range ,
619
+ )
640
620
)
641
- if version_class (version ) in affected_version_range :
642
- affected_purls .append (purl )
643
- else :
644
- safe_purls .append (purl )
645
-
646
- affected_packages .extend (
647
- nearest_patched_package (affected_purls , safe_purls ),
648
- )
649
-
650
- all_adv .append (
651
- AdvisoryData (
652
- summary = description ,
653
- affected_packages = affected_packages ,
654
- vulnerability_id = vuln_id ,
655
- references = references ,
656
- )
621
+ date_published = dateparser .parse (timestamp )
622
+ if not date_published .tzinfo :
623
+ date_published = date_published .replace (tzinfo = pytz .UTC )
624
+ yield AdvisoryData (
625
+ aliases = [vuln_id ],
626
+ summary = description ,
627
+ affected_packages = affected_packages ,
628
+ references = sorted (references ),
629
+ date_published = date_published ,
657
630
)
658
- return all_adv
0 commit comments