@@ -393,10 +393,15 @@ def _include_file(
393393
394394
395395class OvalDataSource (DataSource ):
396-
396+ """
397+ All data sources which collect data from OVAL files must inherit from this (OvalDataSource) class.
398+ Subclasses must implement the methods `_fetch` and `set_api`.
399+ """
397400 @staticmethod
398- def create_purl (pkg_name : str , pkg_version : str , pkg_data : Mapping ):
401+ def create_purl (pkg_name : str , pkg_version : str , pkg_data : Mapping ) -> PackageURL :
399402 """
403+ Helper method for creating different purls for subclasses without them reimplementing
404+ get_data_from_xml_doc method
400405 Note: pkg_data must include 'type' of package
401406 """
402407 return PackageURL (name = pkg_name , version = pkg_version , ** pkg_data )
@@ -405,7 +410,7 @@ def create_purl(pkg_name: str, pkg_version: str, pkg_data: Mapping):
405410 def _collect_pkgs (parsed_oval_data : Mapping ) -> Set :
406411 """
407412 Helper method, used for loading the API. It expects data from
408- OvalParser.get_data() .
413+ OvalParser.get_data().
409414 """
410415 all_pkgs = set ()
411416 for definition_data in parsed_oval_data :
@@ -419,47 +424,66 @@ def _fetch() -> Tuple[Mapping, Iterable[ET.ElementTree]]:
419424 """
420425 This method contains logic to fetch OVAL files and yield them into
421426 a tuple of file's metadata and it's ET.ElementTree.
422- Subclasses must implement this method.
427+ Subclasses must implement this method.
428+
429+ Note: Mapping MUST INCLUDE "type" key. Example values of Mapping
430+ {"type":"deb","qualifiers":{"distro":"buster"} }
431+
423432 """
424433 raise NotImplementedError
425434
426435 def added_advisories (self ) -> List [Advisory ]:
436+ """
437+ Note: metadata MUST INCLUDE "type" key, implement _fetch accordingly.
438+ """
427439 advisories = []
428440 for metadata , oval_file in self ._fetch ():
429441 advisories .extend (self .get_data_from_xml_doc (oval_file , metadata ))
430- return advisories
442+ return self . batch_advisories ( advisories )
431443
432444 def set_api (self , all_pkgs : Iterable [str ]):
433445 """
434446 This method loads the self.pkg_manager_api with the specified packages. It fetches
435- and caches the data about these packages exposes them through
436- self.pkg_manager_api.get(<package_name>)
447+ and caches all the versions of these packages and exposes them through
448+ self.pkg_manager_api.get(<package_name>). Example
449+
450+ >>> self.set_api(['electron'])
451+ Assume 'electron' has only versions 1.0.0 and 1.2.0
452+ >>> assert self.pkg_manager_api.get('electron') == {'1.0.0','1.2.0'}
453+
437454 """
438455 raise NotImplementedError
439456
440457 def get_data_from_xml_doc (self , xml_doc : ET .ElementTree , pkg_metadata = {}) -> List [Advisory ]:
441458 """
442- The orchestration method of the OvalDataSource. Breaks an OVAL xml
443- ElementTree into a list of Advisory.
459+ The orchestration method of the OvalDataSource. This method breaks an OVAL xml
460+ ElementTree into a list of `Advisory`.
461+
462+ Note: pkg_metadata MUST INCLUDE "type" key. Example value of pkg_metadata,
463+ {"type":"deb","qualifiers":{"distro":"buster"} }
444464 """
445465 all_adv = []
446466 oval_doc = OvalParser (self .translations , xml_doc )
447467 raw_data = oval_doc .get_data ()
448468 all_pkgs = self ._collect_pkgs (raw_data )
449469 self .set_api (all_pkgs )
450470 for definition_data in raw_data : # definition_data -> Advisory
471+
472+ # These fields are definition level, i.e common for all
473+ # elements connected/linked to an OvalDefinition
451474 vuln_id = definition_data ['vuln_id' ]
452475 description = definition_data ['description' ]
453476 affected_purls = set ()
454477 safe_purls = set ()
455478 urls = definition_data ['reference_urls' ]
479+
456480 for test_data in definition_data ['test_data' ]:
457481 for package in test_data ['package_list' ]:
458482 pkg_name = package
459483 aff_ver_range = test_data ['version_ranges' ]
460484 all_versions = self .pkg_manager_api .get (package )
461- # This filter is to filter out long versions.
462- # 50 is limit because that's what db permits atm
485+ # This filter is for filtering out long versions.
486+ # 50 is limit because that's what db permits atm.
463487 all_versions = set (
464488 filter (
465489 lambda x : len (x ) < 50 ,
@@ -489,4 +513,4 @@ def get_data_from_xml_doc(self, xml_doc: ET.ElementTree, pkg_metadata={}) -> Lis
489513 resolved_package_urls = safe_purls ,
490514 cve_id = vuln_id ,
491515 reference_urls = urls ))
492- return self . batch_advisories ( all_adv )
516+ return all_adv
0 commit comments