Merge ~litios/ubuntu-cve-tracker:oval_pkg_parent_support into ubuntu-cve-tracker:master
- Git
- lp:~litios/ubuntu-cve-tracker
- oval_pkg_parent_support
- Merge into 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) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Eduardo Barretto | Approve | ||
Review via email: mp+443550@code.launchpad.net |
Commit message
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.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/scripts/generate-oval b/scripts/generate-oval |
2 | index e7d13b7..5bab03c 100755 |
3 | --- a/scripts/generate-oval |
4 | +++ b/scripts/generate-oval |
5 | @@ -581,7 +581,7 @@ def generate_oval_usn(outdir, usn, usn_release, cve_dir, usn_db_dir, ociprefix=N |
6 | |
7 | return True |
8 | |
9 | -def generate_oval_package(release, outdir, cve_prefix_dir, pkg_cache, cve_cache, oci, no_progress, packages, pathnames, fixed_only, ociprefix=None, ocioutdir=None): |
10 | +def generate_oval_package(release, outdir, cve_prefix_dir, pkg_cache, cve_cache, oci, no_progress, packages, pathnames, fixed_only, ociprefix='', ocioutdir=None): |
11 | if not no_progress: |
12 | print(f'[*] Generating OVAL for packages in release {release}') |
13 | 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) |
14 | diff --git a/scripts/oval_lib.py b/scripts/oval_lib.py |
15 | index b67ab51..d657cd6 100644 |
16 | --- a/scripts/oval_lib.py |
17 | +++ b/scripts/oval_lib.py |
18 | @@ -146,17 +146,15 @@ class OvalGenerator: |
19 | supported_oval_elements = ('definition', 'test', 'object', 'state', 'variable') |
20 | generator_version = '1.1' |
21 | oval_schema_version = '5.11.1' |
22 | - def __init__(self, release, release_name, parent = None, warn_method=False, outdir='./', prefix='', oval_format='dpkg') -> None: |
23 | + def __init__(self, release, release_name = None, warn_method=False, outdir='./', prefix='', oval_format='dpkg') -> None: |
24 | self.release = release |
25 | # e.g. codename for trusty/esm should be trusty |
26 | - self.release_codename = parent if parent else self.release.replace('/', '_') |
27 | + self.release_codename = cve_lib.release_progenitor(release) if cve_lib.release_progenitor(release) else self.release.replace('/', '_') |
28 | self.release_name = release_name |
29 | #self.warn = warn_method or self.warn |
30 | self.tmpdir = tempfile.mkdtemp(prefix='oval_lib-') |
31 | self.output_dir = outdir |
32 | self.oval_format = oval_format |
33 | - self.output_filepath = \ |
34 | - '{0}com.ubuntu.{1}.cve.oval.xml'.format(prefix, self.release.replace('/', '_')) |
35 | self.ns = 'oval:com.ubuntu.{0}'.format(self.release_codename) |
36 | self.id = 100 |
37 | self.host_def_id = self.id |
38 | @@ -342,12 +340,13 @@ class OvalGenerator: |
39 | return family_state, state |
40 | |
41 | class CVEPkgRelEntry: |
42 | - def __init__(self, pkg, cve, status, note) -> None: |
43 | + def __init__(self, pkg, release, cve, status, note) -> None: |
44 | self.pkg = pkg |
45 | self.cve = cve |
46 | self.orig_status = status |
47 | self.orig_note = note |
48 | - cve_info = CVEPkgRelEntry.parse_package_status(pkg.rel, pkg.name, status, note, cve.number, None) |
49 | + self.release = release |
50 | + cve_info = CVEPkgRelEntry.parse_package_status(self.release, pkg.name, status, note, cve.number, None) |
51 | |
52 | self.note = cve_info['note'] |
53 | self.status = cve_info['status'] |
54 | @@ -456,9 +455,9 @@ class CVE: |
55 | self.pkg_rel_entries = {} |
56 | self.pkgs = pkgs |
57 | |
58 | - def add_pkg(self, pkg_object, state, note): |
59 | - cve_pkg_entry = CVEPkgRelEntry(pkg_object, self, state, note) |
60 | - self.pkg_rel_entries[Package.get_unique_id(pkg_object.name, pkg_object.rel)] = cve_pkg_entry |
61 | + def add_pkg(self, pkg_object, release, state, note): |
62 | + cve_pkg_entry = CVEPkgRelEntry(pkg_object, release, self, state, note) |
63 | + self.pkg_rel_entries[pkg_object.name] = cve_pkg_entry |
64 | self.pkgs.append(pkg_object) |
65 | |
66 | def __str__(self) -> str: |
67 | @@ -492,10 +491,6 @@ class Package: |
68 | self.binaries = binaries if binaries else [] |
69 | self.cves = [] |
70 | |
71 | - @staticmethod |
72 | - def get_unique_id(name, rel): |
73 | - return f'{name}/{rel}' |
74 | - |
75 | def add_cve(self, cve) -> None: |
76 | self.cves.append(cve) |
77 | |
78 | @@ -506,8 +501,8 @@ class Package: |
79 | return self.__str__() |
80 | |
81 | class OvalGeneratorPkg(OvalGenerator): |
82 | - 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: |
83 | - super().__init__(release, release_name, parent, warn_method, outdir, prefix, oval_format) |
84 | + 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: |
85 | + super().__init__(release, release_name, warn_method, outdir, prefix, oval_format) |
86 | ### |
87 | # ID schema: 2204|00001|0001 |
88 | # * The first four digits are the ubuntu release number |
89 | @@ -518,6 +513,8 @@ class OvalGeneratorPkg(OvalGenerator): |
90 | self.definition_id = release_code * 10 ** 10 |
91 | self.definition_step = 1 * 10 ** 5 |
92 | self.criterion_step = 10 |
93 | + self.output_filepath = \ |
94 | + '{0}com.ubuntu.{1}.pkg.oval.xml'.format(prefix, self.release.replace('/', '_')) |
95 | self.progress = progress |
96 | self.cve_cache = cve_cache |
97 | self.pkg_cache = pkg_cache |
98 | @@ -531,11 +528,10 @@ class OvalGeneratorPkg(OvalGenerator): |
99 | component = etree.SubElement(advisory, "component") |
100 | version = etree.SubElement(advisory, "current_version") |
101 | |
102 | - pkg_id = Package.get_unique_id(package.name, self.release) |
103 | for cve in package.cves: |
104 | - if cve.pkg_rel_entries[pkg_id].status == 'not-vulnerable': |
105 | + if cve.pkg_rel_entries[package.name].status == 'not-vulnerable': |
106 | continue |
107 | - elif self.fixed_only and cve.pkg_rel_entries[pkg_id].status != 'fixed': |
108 | + elif self.fixed_only and cve.pkg_rel_entries[package.name].status != 'fixed': |
109 | continue |
110 | cve_obj = self._generate_cve_object(cve) |
111 | advisory.append(cve_obj) |
112 | @@ -991,7 +987,6 @@ class OvalGeneratorPkg(OvalGenerator): |
113 | return test, object, var, state |
114 | |
115 | def _populate_pkg(self, package, root_element): |
116 | - pkg_id = Package.get_unique_id(package.name, self.release) |
117 | tests = root_element.find("tests") |
118 | objects = root_element.find("objects") |
119 | variables = root_element.find("variables") |
120 | @@ -1008,7 +1003,7 @@ class OvalGeneratorPkg(OvalGenerator): |
121 | cve_added = False |
122 | |
123 | for cve in package.cves: |
124 | - pkg_rel_entry = cve.pkg_rel_entries[pkg_id] |
125 | + pkg_rel_entry = cve.pkg_rel_entries[package.name] |
126 | if pkg_rel_entry.status == 'vulnerable' and not self.fixed_only: |
127 | cve_added = True |
128 | if one_time_added_id: |
129 | @@ -1052,7 +1047,6 @@ class OvalGeneratorPkg(OvalGenerator): |
130 | self._increase_id(is_definition=True) |
131 | |
132 | def _populate_kernel_pkg(self, package, root_element, running_kernel_id): |
133 | - pkg_id = Package.get_unique_id(package.name, self.release) |
134 | tests = root_element.find("tests") |
135 | objects = root_element.find("objects") |
136 | variables = root_element.find("variables") |
137 | @@ -1075,7 +1069,7 @@ class OvalGeneratorPkg(OvalGenerator): |
138 | self._add_to_criteria(definition_element, criteria, operator='AND') |
139 | |
140 | for cve in package.cves: |
141 | - pkg_rel_entry = cve.pkg_rel_entries[pkg_id] |
142 | + pkg_rel_entry = cve.pkg_rel_entries[package.name] |
143 | if pkg_rel_entry.status == 'vulnerable' and not self.fixed_only: |
144 | cve_added = True |
145 | if one_time_added_id: |
146 | @@ -1104,6 +1098,22 @@ class OvalGeneratorPkg(OvalGenerator): |
147 | definitions.append(definition_element) |
148 | self._increase_id(is_definition=True) |
149 | |
150 | + def _add_new_package(self, package_name, cve, release, cve_data, packages) -> None: |
151 | + if package_name not in packages: |
152 | + binaries = self.pkg_cache.get_binarypkgs(package_name, release) |
153 | + version = '' |
154 | + if binaries: |
155 | + version = self.pkg_cache.pkgcache[package_name]['Releases'][release]['source_version'] |
156 | + |
157 | + pkg_obj = Package(package_name, release, binaries, version) |
158 | + packages[package_name] = pkg_obj |
159 | + |
160 | + pkg_obj = packages[package_name] |
161 | + if cve not in pkg_obj.cves: |
162 | + pkg_obj.cves.append(cve) |
163 | + |
164 | + cve.add_pkg(pkg_obj, release, cve_data['pkgs'][package_name][release][0],cve_data['pkgs'][package_name][release][1]) |
165 | + |
166 | def _load_pkgs(self, cve_prefix_dir, packages_filter=None) -> None: |
167 | cve_lib.load_external_subprojects() |
168 | |
169 | @@ -1118,12 +1128,20 @@ class OvalGeneratorPkg(OvalGenerator): |
170 | ) |
171 | |
172 | packages = {} |
173 | - sources[self.release] = load(releases=[self.release], skip_eol_releases=False)[self.release] |
174 | - orig_name = cve_lib.get_orig_rel_name(self.release) |
175 | - if '/' in orig_name: |
176 | - orig_name = orig_name.split('/', maxsplit=1)[1] |
177 | - source_map_binaries[self.release] = load(data_type='packages',releases=[orig_name], skip_eol_releases=False)[orig_name] \ |
178 | - if self.release not in cve_lib.external_releases else {} |
179 | + releases = [self.release] |
180 | + current_release = self.release |
181 | + while(cve_lib.release_parent(current_release)): |
182 | + current_release = cve_lib.release_parent(current_release) |
183 | + releases.append(current_release) |
184 | + |
185 | + for release in releases: |
186 | + sources[release] = load(releases=[release], skip_eol_releases=False)[release] |
187 | + |
188 | + orig_name = cve_lib.get_orig_rel_name(release) |
189 | + if '/' in orig_name: |
190 | + orig_name = orig_name.split('/', maxsplit=1)[1] |
191 | + source_map_binaries[release] = load(data_type='packages',releases=[orig_name], skip_eol_releases=False)[orig_name] \ |
192 | + if release not in cve_lib.external_releases else {} |
193 | |
194 | i = 0 |
195 | for cve_path in cves: |
196 | @@ -1143,22 +1161,11 @@ class OvalGeneratorPkg(OvalGenerator): |
197 | if packages_filter and pkg not in packages_filter: |
198 | continue |
199 | |
200 | - if self.release in info['pkgs'][pkg] and \ |
201 | - info['pkgs'][pkg][self.release][0] != 'DNE' and \ |
202 | - pkg in sources[self.release]: |
203 | - pkg_id = Package.get_unique_id(pkg, self.release) |
204 | - if pkg_id not in packages: |
205 | - binaries = self.pkg_cache.get_binarypkgs(pkg, self.release) |
206 | - version = '' |
207 | - if binaries: |
208 | - version = self.pkg_cache.pkgcache[pkg]['Releases'][self.release]['source_version'] |
209 | - pkg_obj = Package(pkg, self.release, binaries, version) |
210 | - packages[pkg_id] = pkg_obj |
211 | - |
212 | - pkg_obj = packages[pkg_id] |
213 | - pkg_obj.cves.append(cve_obj) |
214 | - # add_pkg (pkg, status, note) |
215 | - cve_obj.add_pkg(pkg_obj, info['pkgs'][pkg][self.release][0],info['pkgs'][pkg][self.release][1]) |
216 | + for release in releases: |
217 | + if pkg in sources[release] and release in info['pkgs'][pkg] and \ |
218 | + info['pkgs'][pkg][release][0] != 'DNE': |
219 | + self._add_new_package(pkg, cve_obj, release, info, packages) |
220 | + break |
221 | |
222 | packages = dict(sorted(packages.items())) |
223 | if self.progress: |
224 | @@ -1186,14 +1193,11 @@ class OvalGeneratorPkg(OvalGenerator): |
225 | self._populate_pkg(self.packages[pkg], root_element) |
226 | |
227 | #etree.indent(xml_tree, level=0) -> only available from Python 3.9 |
228 | - filename = f"com.ubuntu.{self.release_codename}.pkg.oval.xml" |
229 | xmlstr = minidom.parseString(etree.tostring(root_element)).toprettyxml(indent=" ") |
230 | - if self.oval_format == 'oci': |
231 | - filename = f'oci.{filename}' |
232 | |
233 | - with open(os.path.join(self.output_dir, filename), 'w') as file: |
234 | + with open(os.path.join(self.output_dir, self.output_filepath), 'w') as file: |
235 | file.write(xmlstr) |
236 | - #xml_tree.write(os.path.join(self.output_dir, filename)) |
237 | + #xml_tree.write(os.path.join(self.output_dir, self.output_filepath)) |
238 | return |
239 | |
240 | class OvalGeneratorCVE: |
lgtm, thanks!