@@ -106,9 +106,9 @@ class DataSource(ContextManager):
106106 def __init__ (
107107 self ,
108108 batch_size : int ,
109- last_run_date : Optional [datetime ] = None ,
110- cutoff_date : Optional [datetime ] = None ,
111- config : Optional [Mapping [str , Any ]] = None ,
109+ last_run_date : Optional [datetime ]= None ,
110+ cutoff_date : Optional [datetime ]= None ,
111+ config : Optional [Mapping [str , Any ]]= None ,
112112 ):
113113 """
114114 Create a DataSource instance.
@@ -240,9 +240,9 @@ def __exit__(self, exc_type, exc_val, exc_tb):
240240
241241 def file_changes (
242242 self ,
243- subdir : str = None ,
244- recursive : bool = False ,
245- file_ext : Optional [str ] = None ,
243+ subdir : str = None ,
244+ recursive : bool = False ,
245+ file_ext : Optional [str ]= None ,
246246 ) -> Tuple [Set [str ], Set [str ]]:
247247 """
248248 Returns all added and modified files since last_run_date or cutoff_date (whichever is more
@@ -382,9 +382,9 @@ def _update_from_remote(self, remote, branch) -> None:
382382
383383def _include_file (
384384 path : str ,
385- subdir : Optional [str ] = None ,
386- recursive : bool = False ,
387- file_ext : Optional [str ] = None ,
385+ subdir : Optional [str ]= None ,
386+ recursive : bool = False ,
387+ file_ext : Optional [str ]= None ,
388388) -> bool :
389389 match = True
390390
@@ -408,6 +408,7 @@ class OvalDataSource(DataSource):
408408 All data sources which collect data from OVAL files must inherit from this
409409 `OvalDataSource` class. Subclasses must implement the methods `_fetch` and `set_api`.
410410 """
411+
411412 @staticmethod
412413 def create_purl (pkg_name : str , pkg_version : str , pkg_data : Mapping ) -> PackageURL :
413414 """
@@ -433,29 +434,48 @@ def _collect_pkgs(parsed_oval_data: Mapping) -> Set:
433434
434435 def _fetch (self ) -> Tuple [Mapping , Iterable [ET .ElementTree ]]:
435436 """
436- This method contains logic to fetch OVAL files and yield them into
437- a tuple of file's metadata and it's ET.ElementTree.
437+ Return a two-tuple of ({mapping of Package URL data}, it's ET.ElementTree)
438438 Subclasses must implement this method.
439439
440- Note: Mapping MUST INCLUDE "type" key. Example values of Mapping
441- {"type":"deb","qualifiers":{"distro":"buster"} }
440+ Note: Package URL data MUST INCLUDE a Package URL "type" key so
441+ implement _fetch() accordingly.
442+ For example::
442443
444+ {"type":"deb","qualifiers":{"distro":"buster"} }
443445 """
446+ # TODO: enforce that we receive the proper data here
444447 raise NotImplementedError
445448
446449 def updated_advisories (self ) -> List [Advisory ]:
447- """
448- Note: metadata MUST INCLUDE "type" key, implement _fetch accordingly.
449- """
450- for metadata , oval_file in self ._fetch ():
450+ for purl_data , oval_etree in self ._fetch ():
451+ if 'type' not in purl_data :
452+ ets = (oval_etree and ET .tostring (oval_etree )) or 'NO DATA'
453+ msg = (
454+ "Failed to get updated_advisories for Ubuntu: purl_data is "
455+ f"missing a package type { purl_data !r} \n "
456+ f"with OVAL XML:\n "
457+ f"{ ets } \n "
458+ f"... continuing..."
459+ )
460+ print (msg )
461+ logger .error (msg )
462+ continue
463+
451464 try :
452- oval_data = self .get_data_from_xml_doc (oval_file , metadata )
465+ oval_data = self .get_data_from_xml_doc (oval_etree , purl_data )
453466 yield oval_data
454467 except Exception :
455- logger .error (
456- f"Failed to get updated_advisories: { oval_file !r} "
457- "with {metadata!r}:\n " + traceback .format_exc ()
468+ ets = (oval_etree and ET .tostring (oval_etree )) or 'NO DATA'
469+ tb = traceback .format_exc ()
470+ msg = (
471+ f"Failed to get updated_advisories for Ubuntu:"
472+ f"with { purl_data !r} \n "
473+ f"and with OVAL XML:\n "
474+ f"{ ets } \n { tb } \n "
475+ f"... continuing..."
458476 )
477+ print (msg )
478+ logger .error (msg )
459479 continue
460480
461481 def set_api (self , all_pkgs : Iterable [str ]):
@@ -473,57 +493,89 @@ def set_api(self, all_pkgs: Iterable[str]):
473493
474494 def get_data_from_xml_doc (self , xml_doc : ET .ElementTree , pkg_metadata = {}) -> List [Advisory ]:
475495 """
476- The orchestration method of the OvalDataSource. This method breaks an OVAL xml
477- ElementTree into a list of `Advisory`.
496+ The orchestration method of the OvalDataSource. This method breaks an
497+ OVAL xml ElementTree into a list of `Advisory`.
478498
479- Note: pkg_metadata MUST INCLUDE "type" key. Example value of pkg_metadata,
499+ Note: pkg_metadata is a mapping of Package URL data that MUST INCLUDE
500+ "type" key.
501+
502+ Example value of pkg_metadata:
480503 {"type":"deb","qualifiers":{"distro":"buster"} }
481504 """
505+ if 'type' not in pkg_metadata :
506+ ets = xml_doc and ET .tostring (xml_doc ) or 'NO DATA'
507+ msg = (
508+ "Failed to get_data_from_xml_doc: pkg_metadata is "
509+ f"missing a package type { pkg_metadata !r} \n "
510+ f"with OVAL XML:\n "
511+ f"{ ets } "
512+ )
513+ print (msg )
514+ logger .error (msg )
515+ raise Exception (msg )
516+
482517 all_adv = []
483518 oval_doc = OvalParser (self .translations , xml_doc )
484- raw_data = oval_doc .get_data ()
519+ try :
520+ raw_data = oval_doc .get_data ()
521+ except Exception :
522+ ets = xml_doc and ET .tostring (xml_doc ) or 'NO DATA'
523+ tb = traceback .format_exc ()
524+ msg = (
525+ f"Failed to get_data_from_xml_doc:"
526+ f"with { pkg_metadata !r} \n "
527+ f"and with OVAL XML:\n "
528+ f"{ ets } \n { tb } "
529+ )
530+ print (msg )
531+ logger .error (msg )
532+ raise Exception (msg )
533+
485534 all_pkgs = self ._collect_pkgs (raw_data )
486535 self .set_api (all_pkgs )
487- for definition_data in raw_data : # definition_data -> Advisory
488536
489- # These fields are definition level, i.e common for all
490- # elements connected/linked to an OvalDefinition
537+ # convert definition_data to Advisory objects
538+ for definition_data in raw_data :
539+ # These fields are definition level, i.e common for all elements
540+ # connected/linked to an OvalDefinition
491541 vuln_id = definition_data ['vuln_id' ]
492542 description = definition_data ['description' ]
493543 affected_purls = set ()
494544 safe_purls = set ()
495- references = [Reference (url = url )
496- for url in definition_data ['reference_urls' ]]
497-
545+ references = [Reference (url = url ) for url in definition_data ['reference_urls' ]]
498546 for test_data in definition_data ['test_data' ]:
499547 for package in test_data ['package_list' ]:
500548 pkg_name = package
501549 if package and len (pkg_name ) >= 50 :
502550 continue
503- aff_ver_range = test_data ['version_ranges' ]
551+ aff_ver_range = test_data ['version_ranges' ] or set ()
504552 all_versions = self .pkg_manager_api .get (package )
553+
554+ # FIXME: what is this 50 DB limit? that's too small for versions
555+ # FIXME: we should not drop data this way
505556 # This filter is for filtering out long versions.
506557 # 50 is limit because that's what db permits atm.
507- all_versions = set (
508- filter (
509- lambda x : len (x ) < 50 ,
510- all_versions ))
558+ all_versions = set (filter (lambda x : len (x ) < 50 , all_versions ))
511559 if not all_versions :
512560 continue
513- affected_versions = set (
514- filter (
515- lambda x : x in aff_ver_range ,
516- all_versions ))
561+
562+ affected_versions = set (filter (lambda x : x in aff_ver_range , all_versions ))
517563 safe_versions = all_versions - affected_versions
518564
519565 for version in affected_versions :
520566 pkg_url = self .create_purl (
521- pkg_name = pkg_name , pkg_version = version , pkg_data = pkg_metadata )
567+ pkg_name = pkg_name ,
568+ pkg_version = version ,
569+ pkg_data = pkg_metadata ,
570+ )
522571 affected_purls .add (pkg_url )
523572
524573 for version in safe_versions :
525574 pkg_url = self .create_purl (
526- pkg_name = pkg_name , pkg_version = version , pkg_data = pkg_metadata )
575+ pkg_name = pkg_name ,
576+ pkg_version = version ,
577+ pkg_data = pkg_metadata ,
578+ )
527579 safe_purls .add (pkg_url )
528580
529581 all_adv .append (
@@ -532,5 +584,8 @@ def get_data_from_xml_doc(self, xml_doc: ET.ElementTree, pkg_metadata={}) -> Lis
532584 impacted_package_urls = affected_purls ,
533585 resolved_package_urls = safe_purls ,
534586 cve_id = vuln_id ,
535- vuln_references = references ))
587+ vuln_references = references ,
588+ ))
589+
590+ print (f"Processed { len (all_adv )} Advisory from Oval data for { pkg_metadata } " )
536591 return all_adv
0 commit comments