Merge ~litios/ubuntu-cve-tracker:oval_pkg_parent_support into ubuntu-cve-tracker:master

Proposed by David Fernandez Gonzalez
Status: Merged
Merged at revision: 6a3b15b2839e890e1ce769204a674f23f90f1e57
Proposed branch: ~litios/ubuntu-cve-tracker:oval_pkg_parent_support
Merge into: ubuntu-cve-tracker:master
Diff against target: 240 lines (+54/-50)
2 files modified
scripts/generate-oval (+1/-1)
scripts/oval_lib.py (+53/-49)
Reviewer Review Type Date Requested Status
Eduardo Barretto Approve
Review via email: mp+443550@code.launchpad.net

Description of the change

Previously, ESM-related releases were only generating OVAL data for the packages and versions contained in those ESM PPAs. This PR address this issue so they include the information regarding the parent release.

It has also been added an improvement so the filename generated is based on the class attribute.

To post a comment you must log in.
Revision history for this message
Eduardo Barretto (ebarretto) wrote :

lgtm, thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/scripts/generate-oval b/scripts/generate-oval
index e7d13b7..5bab03c 100755
--- a/scripts/generate-oval
+++ b/scripts/generate-oval
@@ -581,7 +581,7 @@ def generate_oval_usn(outdir, usn, usn_release, cve_dir, usn_db_dir, ociprefix=N
581581
582 return True582 return True
583583
584def generate_oval_package(release, outdir, cve_prefix_dir, pkg_cache, cve_cache, oci, no_progress, packages, pathnames, fixed_only, ociprefix=None, ocioutdir=None):584def generate_oval_package(release, outdir, cve_prefix_dir, pkg_cache, cve_cache, oci, no_progress, packages, pathnames, fixed_only, ociprefix='', ocioutdir=None):
585 if not no_progress:585 if not no_progress:
586 print(f'[*] Generating OVAL for packages in release {release}')586 print(f'[*] Generating OVAL for packages in release {release}')
587 ov = oval_lib.OvalGeneratorPkg(release, release_name(release), pathnames, packages, not no_progress,pkg_cache=pkg_cache, fixed_only=fixed_only, cve_cache=cve_cache, oval_format='oci' if oci else 'dpkg', outdir=outdir, cve_prefix_dir=cve_prefix_dir, prefix=ociprefix)587 ov = oval_lib.OvalGeneratorPkg(release, release_name(release), pathnames, packages, not no_progress,pkg_cache=pkg_cache, fixed_only=fixed_only, cve_cache=cve_cache, oval_format='oci' if oci else 'dpkg', outdir=outdir, cve_prefix_dir=cve_prefix_dir, prefix=ociprefix)
diff --git a/scripts/oval_lib.py b/scripts/oval_lib.py
index b67ab51..d657cd6 100644
--- a/scripts/oval_lib.py
+++ b/scripts/oval_lib.py
@@ -146,17 +146,15 @@ class OvalGenerator:
146 supported_oval_elements = ('definition', 'test', 'object', 'state', 'variable')146 supported_oval_elements = ('definition', 'test', 'object', 'state', 'variable')
147 generator_version = '1.1'147 generator_version = '1.1'
148 oval_schema_version = '5.11.1'148 oval_schema_version = '5.11.1'
149 def __init__(self, release, release_name, parent = None, warn_method=False, outdir='./', prefix='', oval_format='dpkg') -> None:149 def __init__(self, release, release_name = None, warn_method=False, outdir='./', prefix='', oval_format='dpkg') -> None:
150 self.release = release150 self.release = release
151 # e.g. codename for trusty/esm should be trusty151 # e.g. codename for trusty/esm should be trusty
152 self.release_codename = parent if parent else self.release.replace('/', '_')152 self.release_codename = cve_lib.release_progenitor(release) if cve_lib.release_progenitor(release) else self.release.replace('/', '_')
153 self.release_name = release_name153 self.release_name = release_name
154 #self.warn = warn_method or self.warn154 #self.warn = warn_method or self.warn
155 self.tmpdir = tempfile.mkdtemp(prefix='oval_lib-')155 self.tmpdir = tempfile.mkdtemp(prefix='oval_lib-')
156 self.output_dir = outdir156 self.output_dir = outdir
157 self.oval_format = oval_format157 self.oval_format = oval_format
158 self.output_filepath = \
159 '{0}com.ubuntu.{1}.cve.oval.xml'.format(prefix, self.release.replace('/', '_'))
160 self.ns = 'oval:com.ubuntu.{0}'.format(self.release_codename)158 self.ns = 'oval:com.ubuntu.{0}'.format(self.release_codename)
161 self.id = 100159 self.id = 100
162 self.host_def_id = self.id160 self.host_def_id = self.id
@@ -342,12 +340,13 @@ class OvalGenerator:
342 return family_state, state340 return family_state, state
343341
344class CVEPkgRelEntry:342class CVEPkgRelEntry:
345 def __init__(self, pkg, cve, status, note) -> None:343 def __init__(self, pkg, release, cve, status, note) -> None:
346 self.pkg = pkg344 self.pkg = pkg
347 self.cve = cve345 self.cve = cve
348 self.orig_status = status346 self.orig_status = status
349 self.orig_note = note347 self.orig_note = note
350 cve_info = CVEPkgRelEntry.parse_package_status(pkg.rel, pkg.name, status, note, cve.number, None)348 self.release = release
349 cve_info = CVEPkgRelEntry.parse_package_status(self.release, pkg.name, status, note, cve.number, None)
351350
352 self.note = cve_info['note']351 self.note = cve_info['note']
353 self.status = cve_info['status']352 self.status = cve_info['status']
@@ -456,9 +455,9 @@ class CVE:
456 self.pkg_rel_entries = {}455 self.pkg_rel_entries = {}
457 self.pkgs = pkgs456 self.pkgs = pkgs
458457
459 def add_pkg(self, pkg_object, state, note):458 def add_pkg(self, pkg_object, release, state, note):
460 cve_pkg_entry = CVEPkgRelEntry(pkg_object, self, state, note)459 cve_pkg_entry = CVEPkgRelEntry(pkg_object, release, self, state, note)
461 self.pkg_rel_entries[Package.get_unique_id(pkg_object.name, pkg_object.rel)] = cve_pkg_entry460 self.pkg_rel_entries[pkg_object.name] = cve_pkg_entry
462 self.pkgs.append(pkg_object)461 self.pkgs.append(pkg_object)
463462
464 def __str__(self) -> str:463 def __str__(self) -> str:
@@ -492,10 +491,6 @@ class Package:
492 self.binaries = binaries if binaries else []491 self.binaries = binaries if binaries else []
493 self.cves = []492 self.cves = []
494493
495 @staticmethod
496 def get_unique_id(name, rel):
497 return f'{name}/{rel}'
498
499 def add_cve(self, cve) -> None:494 def add_cve(self, cve) -> None:
500 self.cves.append(cve)495 self.cves.append(cve)
501496
@@ -506,8 +501,8 @@ class Package:
506 return self.__str__()501 return self.__str__()
507502
508class OvalGeneratorPkg(OvalGenerator):503class OvalGeneratorPkg(OvalGenerator):
509 def __init__(self, release, release_name, cve_paths, packages, progress, pkg_cache, fixed_only=True, cve_cache=None, cve_prefix_dir=None, parent=None, warn_method=False, outdir='./', prefix='', oval_format='dpkg') -> None:504 def __init__(self, release, release_name, cve_paths, packages, progress, pkg_cache, fixed_only=True, cve_cache=None, cve_prefix_dir=None, warn_method=False, outdir='./', prefix='', oval_format='dpkg') -> None:
510 super().__init__(release, release_name, parent, warn_method, outdir, prefix, oval_format)505 super().__init__(release, release_name, warn_method, outdir, prefix, oval_format)
511 ###506 ###
512 # ID schema: 2204|00001|0001507 # ID schema: 2204|00001|0001
513 # * The first four digits are the ubuntu release number508 # * The first four digits are the ubuntu release number
@@ -518,6 +513,8 @@ class OvalGeneratorPkg(OvalGenerator):
518 self.definition_id = release_code * 10 ** 10513 self.definition_id = release_code * 10 ** 10
519 self.definition_step = 1 * 10 ** 5514 self.definition_step = 1 * 10 ** 5
520 self.criterion_step = 10515 self.criterion_step = 10
516 self.output_filepath = \
517 '{0}com.ubuntu.{1}.pkg.oval.xml'.format(prefix, self.release.replace('/', '_'))
521 self.progress = progress518 self.progress = progress
522 self.cve_cache = cve_cache519 self.cve_cache = cve_cache
523 self.pkg_cache = pkg_cache520 self.pkg_cache = pkg_cache
@@ -531,11 +528,10 @@ class OvalGeneratorPkg(OvalGenerator):
531 component = etree.SubElement(advisory, "component")528 component = etree.SubElement(advisory, "component")
532 version = etree.SubElement(advisory, "current_version")529 version = etree.SubElement(advisory, "current_version")
533530
534 pkg_id = Package.get_unique_id(package.name, self.release)
535 for cve in package.cves:531 for cve in package.cves:
536 if cve.pkg_rel_entries[pkg_id].status == 'not-vulnerable':532 if cve.pkg_rel_entries[package.name].status == 'not-vulnerable':
537 continue533 continue
538 elif self.fixed_only and cve.pkg_rel_entries[pkg_id].status != 'fixed':534 elif self.fixed_only and cve.pkg_rel_entries[package.name].status != 'fixed':
539 continue535 continue
540 cve_obj = self._generate_cve_object(cve)536 cve_obj = self._generate_cve_object(cve)
541 advisory.append(cve_obj)537 advisory.append(cve_obj)
@@ -991,7 +987,6 @@ class OvalGeneratorPkg(OvalGenerator):
991 return test, object, var, state987 return test, object, var, state
992988
993 def _populate_pkg(self, package, root_element):989 def _populate_pkg(self, package, root_element):
994 pkg_id = Package.get_unique_id(package.name, self.release)
995 tests = root_element.find("tests")990 tests = root_element.find("tests")
996 objects = root_element.find("objects")991 objects = root_element.find("objects")
997 variables = root_element.find("variables")992 variables = root_element.find("variables")
@@ -1008,7 +1003,7 @@ class OvalGeneratorPkg(OvalGenerator):
1008 cve_added = False1003 cve_added = False
10091004
1010 for cve in package.cves:1005 for cve in package.cves:
1011 pkg_rel_entry = cve.pkg_rel_entries[pkg_id]1006 pkg_rel_entry = cve.pkg_rel_entries[package.name]
1012 if pkg_rel_entry.status == 'vulnerable' and not self.fixed_only:1007 if pkg_rel_entry.status == 'vulnerable' and not self.fixed_only:
1013 cve_added = True1008 cve_added = True
1014 if one_time_added_id:1009 if one_time_added_id:
@@ -1052,7 +1047,6 @@ class OvalGeneratorPkg(OvalGenerator):
1052 self._increase_id(is_definition=True)1047 self._increase_id(is_definition=True)
10531048
1054 def _populate_kernel_pkg(self, package, root_element, running_kernel_id):1049 def _populate_kernel_pkg(self, package, root_element, running_kernel_id):
1055 pkg_id = Package.get_unique_id(package.name, self.release)
1056 tests = root_element.find("tests")1050 tests = root_element.find("tests")
1057 objects = root_element.find("objects")1051 objects = root_element.find("objects")
1058 variables = root_element.find("variables")1052 variables = root_element.find("variables")
@@ -1075,7 +1069,7 @@ class OvalGeneratorPkg(OvalGenerator):
1075 self._add_to_criteria(definition_element, criteria, operator='AND')1069 self._add_to_criteria(definition_element, criteria, operator='AND')
10761070
1077 for cve in package.cves:1071 for cve in package.cves:
1078 pkg_rel_entry = cve.pkg_rel_entries[pkg_id]1072 pkg_rel_entry = cve.pkg_rel_entries[package.name]
1079 if pkg_rel_entry.status == 'vulnerable' and not self.fixed_only:1073 if pkg_rel_entry.status == 'vulnerable' and not self.fixed_only:
1080 cve_added = True1074 cve_added = True
1081 if one_time_added_id:1075 if one_time_added_id:
@@ -1104,6 +1098,22 @@ class OvalGeneratorPkg(OvalGenerator):
1104 definitions.append(definition_element)1098 definitions.append(definition_element)
1105 self._increase_id(is_definition=True)1099 self._increase_id(is_definition=True)
11061100
1101 def _add_new_package(self, package_name, cve, release, cve_data, packages) -> None:
1102 if package_name not in packages:
1103 binaries = self.pkg_cache.get_binarypkgs(package_name, release)
1104 version = ''
1105 if binaries:
1106 version = self.pkg_cache.pkgcache[package_name]['Releases'][release]['source_version']
1107
1108 pkg_obj = Package(package_name, release, binaries, version)
1109 packages[package_name] = pkg_obj
1110
1111 pkg_obj = packages[package_name]
1112 if cve not in pkg_obj.cves:
1113 pkg_obj.cves.append(cve)
1114
1115 cve.add_pkg(pkg_obj, release, cve_data['pkgs'][package_name][release][0],cve_data['pkgs'][package_name][release][1])
1116
1107 def _load_pkgs(self, cve_prefix_dir, packages_filter=None) -> None:1117 def _load_pkgs(self, cve_prefix_dir, packages_filter=None) -> None:
1108 cve_lib.load_external_subprojects()1118 cve_lib.load_external_subprojects()
11091119
@@ -1118,12 +1128,20 @@ class OvalGeneratorPkg(OvalGenerator):
1118 )1128 )
11191129
1120 packages = {}1130 packages = {}
1121 sources[self.release] = load(releases=[self.release], skip_eol_releases=False)[self.release]1131 releases = [self.release]
1122 orig_name = cve_lib.get_orig_rel_name(self.release)1132 current_release = self.release
1123 if '/' in orig_name:1133 while(cve_lib.release_parent(current_release)):
1124 orig_name = orig_name.split('/', maxsplit=1)[1]1134 current_release = cve_lib.release_parent(current_release)
1125 source_map_binaries[self.release] = load(data_type='packages',releases=[orig_name], skip_eol_releases=False)[orig_name] \1135 releases.append(current_release)
1126 if self.release not in cve_lib.external_releases else {}1136
1137 for release in releases:
1138 sources[release] = load(releases=[release], skip_eol_releases=False)[release]
1139
1140 orig_name = cve_lib.get_orig_rel_name(release)
1141 if '/' in orig_name:
1142 orig_name = orig_name.split('/', maxsplit=1)[1]
1143 source_map_binaries[release] = load(data_type='packages',releases=[orig_name], skip_eol_releases=False)[orig_name] \
1144 if release not in cve_lib.external_releases else {}
11271145
1128 i = 01146 i = 0
1129 for cve_path in cves:1147 for cve_path in cves:
@@ -1143,22 +1161,11 @@ class OvalGeneratorPkg(OvalGenerator):
1143 if packages_filter and pkg not in packages_filter:1161 if packages_filter and pkg not in packages_filter:
1144 continue1162 continue
11451163
1146 if self.release in info['pkgs'][pkg] and \1164 for release in releases:
1147 info['pkgs'][pkg][self.release][0] != 'DNE' and \1165 if pkg in sources[release] and release in info['pkgs'][pkg] and \
1148 pkg in sources[self.release]:1166 info['pkgs'][pkg][release][0] != 'DNE':
1149 pkg_id = Package.get_unique_id(pkg, self.release)1167 self._add_new_package(pkg, cve_obj, release, info, packages)
1150 if pkg_id not in packages:1168 break
1151 binaries = self.pkg_cache.get_binarypkgs(pkg, self.release)
1152 version = ''
1153 if binaries:
1154 version = self.pkg_cache.pkgcache[pkg]['Releases'][self.release]['source_version']
1155 pkg_obj = Package(pkg, self.release, binaries, version)
1156 packages[pkg_id] = pkg_obj
1157
1158 pkg_obj = packages[pkg_id]
1159 pkg_obj.cves.append(cve_obj)
1160 # add_pkg (pkg, status, note)
1161 cve_obj.add_pkg(pkg_obj, info['pkgs'][pkg][self.release][0],info['pkgs'][pkg][self.release][1])
11621169
1163 packages = dict(sorted(packages.items()))1170 packages = dict(sorted(packages.items()))
1164 if self.progress:1171 if self.progress:
@@ -1186,14 +1193,11 @@ class OvalGeneratorPkg(OvalGenerator):
1186 self._populate_pkg(self.packages[pkg], root_element)1193 self._populate_pkg(self.packages[pkg], root_element)
11871194
1188 #etree.indent(xml_tree, level=0) -> only available from Python 3.91195 #etree.indent(xml_tree, level=0) -> only available from Python 3.9
1189 filename = f"com.ubuntu.{self.release_codename}.pkg.oval.xml"
1190 xmlstr = minidom.parseString(etree.tostring(root_element)).toprettyxml(indent=" ")1196 xmlstr = minidom.parseString(etree.tostring(root_element)).toprettyxml(indent=" ")
1191 if self.oval_format == 'oci':
1192 filename = f'oci.{filename}'
11931197
1194 with open(os.path.join(self.output_dir, filename), 'w') as file:1198 with open(os.path.join(self.output_dir, self.output_filepath), 'w') as file:
1195 file.write(xmlstr)1199 file.write(xmlstr)
1196 #xml_tree.write(os.path.join(self.output_dir, filename))1200 #xml_tree.write(os.path.join(self.output_dir, self.output_filepath))
1197 return1201 return
11981202
1199class OvalGeneratorCVE:1203class OvalGeneratorCVE:

Subscribers

People subscribed via source and target branches