Merge ~ebarretto/ubuntu-cve-tracker:oval-bugs into ubuntu-cve-tracker:master

Proposed by Eduardo Barretto
Status: Merged
Merge reported by: Eduardo Barretto
Merged at revision: 11ea9be3dc481fe183ffb6bf66401461cb8fb189
Proposed branch: ~ebarretto/ubuntu-cve-tracker:oval-bugs
Merge into: ubuntu-cve-tracker:master
Diff against target: 933 lines (+134/-351)
7 files modified
scripts/cve_lib.py (+2/-0)
scripts/generate-oval (+74/-291)
scripts/oval_lib.py (+42/-44)
test/test_oval_lib_end_to_end.py (+4/-4)
test/test_oval_lib_functional.py (+6/-6)
test/test_oval_lib_unit.py (+3/-3)
test/test_utils.py (+3/-3)
Reviewer Review Type Date Requested Status
David Fernandez Gonzalez Approve
Ubuntu Security Team Pending
Review via email: mp+461249@code.launchpad.net

Description of the change

Some clean-up on generate-oval:
- removed unused variables, fuctions and imports
- removed --cve-prefix-dir
- improved helper descriptions
- added --type flag, removed --usn-oval and --pkg-oval
- rework calls to OCI OVAL generation
- rework tests to address new changes

PS: There's a few commits that launchpad is not showing, you might want to look directly at the branch.

To post a comment you must log in.
11ea9be... by Eduardo Barretto

generate-oval: make oval-releases use nargs instead of appending

This allow single calls with --oval-releases bionic xenial
instead of --oval-releases bionic --oval-releases xenial

Revision history for this message
David Fernandez Gonzalez (litios) wrote :

LGTM, no changes in the OVAL output before and after this PR. Thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/scripts/cve_lib.py b/scripts/cve_lib.py
index 416d5f7..090cdea 100755
--- a/scripts/cve_lib.py
+++ b/scripts/cve_lib.py
@@ -492,6 +492,7 @@ subprojects = {
492 },492 },
493 "ubuntu/trusty": {493 "ubuntu/trusty": {
494 "eol": True,494 "eol": True,
495 "oval": True,
495 "components": ["main", "restricted", "universe", "multiverse"],496 "components": ["main", "restricted", "universe", "multiverse"],
496 "name": "Ubuntu 14.04 LTS",497 "name": "Ubuntu 14.04 LTS",
497 "version": 14.04,498 "version": 14.04,
@@ -532,6 +533,7 @@ subprojects = {
532 },533 },
533 "ubuntu/xenial": {534 "ubuntu/xenial": {
534 "eol": True,535 "eol": True,
536 "oval": True,
535 "components": ["main", "restricted", "universe", "multiverse"],537 "components": ["main", "restricted", "universe", "multiverse"],
536 "name": "Ubuntu 16.04 LTS",538 "name": "Ubuntu 16.04 LTS",
537 "version": 16.04,539 "version": 16.04,
diff --git a/scripts/generate-oval b/scripts/generate-oval
index 920bba6..c555304 100755
--- a/scripts/generate-oval
+++ b/scripts/generate-oval
@@ -32,31 +32,11 @@ import os
32import re32import re
33import sys33import sys
3434
35import apt_pkg35from cve_lib import (product_series, PRODUCT_UBUNTU, all_releases, eol_releases, devel_release, release_parent, release_name, needs_oval)
36from cve_lib import (kernel_srcs, product_series, load_cve, PRODUCT_UBUNTU, all_releases, eol_releases, devel_release, release_parent, release_name, release_progenitor, needs_oval)
37from kernel_lib import meta_kernels
38import oval_lib36import oval_lib
3937
40# cope with apt_pkg api changes.
41if 'init_system' in dir(apt_pkg):
42 apt_pkg.init_system()
43else:
44 apt_pkg.InitSystem()
45
46supported_releases = []
47for r in set(all_releases).difference(set(eol_releases)).difference(set([devel_release])):
48 if needs_oval(r):
49 supported_releases.append(r)
50 parent = release_parent(r)
51 if parent and parent not in supported_releases:
52 supported_releases.append(parent)
53
54default_cves_to_process = ['active/CVE-*', 'retired/CVE-*']
55
56debug_level = 038debug_level = 0
5739
58package_cache = None
59
60def main():40def main():
61 """ parse command line options and iterate through files to be processed41 """ parse command line options and iterate through files to be processed
62 """42 """
@@ -64,9 +44,10 @@ def main():
64 global supported_releases44 global supported_releases
6545
66 # parse command line options46 # parse command line options
67 parser = argparse.ArgumentParser(description='Generate CVE OVAL from '47 parser = argparse.ArgumentParser(description='Generate OVAL for CVE, PKG or USNs.')
68 'CVE metadata files.')48 parser.add_argument('--type', required=True, choices=['cve', 'pkg', 'usn'],
69 parser.add_argument('pathname', nargs='*',49 help='OVAL format')
50 parser.add_argument('--cves', nargs='*', default=['active/CVE-*', 'retired/CVE-*'],
70 help='pathname patterns (globs) specifying CVE '51 help='pathname patterns (globs) specifying CVE '
71 'metadata files to be converted into OVAL '52 'metadata files to be converted into OVAL '
72 '(default: "./active/CVE-*" "./retired/CVE-*")')53 '(default: "./active/CVE-*" "./retired/CVE-*")')
@@ -78,255 +59,76 @@ def main():
78 help='output directory for OCI manifest OVAL files (default is to use the same directory as --output-dir)')59 help='output directory for OCI manifest OVAL files (default is to use the same directory as --output-dir)')
79 parser.add_argument('--oci-prefix', nargs='?', default='oci.',60 parser.add_argument('--oci-prefix', nargs='?', default='oci.',
80 help='Prefix to use for OCI manifest OVAL files names (required if oci-output-dir is the same as output-dir)')61 help='Prefix to use for OCI manifest OVAL files names (required if oci-output-dir is the same as output-dir)')
81 parser.add_argument('--cve-prefix-dir', nargs='?', default='./',
82 help='location of CVE metadata files to process '
83 '(default is ./)')
84 parser.add_argument('--no-progress', action='store_true',62 parser.add_argument('--no-progress', action='store_true',
85 help='do not show progress meter')63 help='do not show progress meter')
86 parser.add_argument('--pkg-cache-dir', action='store', default='./',64 parser.add_argument('--pkg-cache-dir', action='store', default='./',
87 help='cache location for binary packages')65 help='cache location for binary packages')
88 parser.add_argument('-d', '--debug', action='count', default=0,66 parser.add_argument('-d', '--debug', action='count', default=0,
89 help="report debugging information")67 help="report debugging information")
90 parser.add_argument('--usn-oval', action='store_true',
91 help='generates oval from the USN database')
92 parser.add_argument('--pkg-oval', action='store_true',
93 help='generates oval from the Package database')
94 parser.add_argument('--usn-db-dir', default='./', type=str,68 parser.add_argument('--usn-db-dir', default='./', type=str,
95 help='location of USN database.json to process '69 help='location of USN database.json to process '
96 '(default is ./)')70 '(default is ./)')
97 parser.add_argument('--usn-number', default=None, type=str,71 parser.add_argument('--usn-number', default=None, type=str,
98 help='if passed specifics a USN for the oval_usn generator')72 help='if passed specifics a USN for the oval_usn generator')
99 parser.add_argument('--oval-releases', default=None, action='append',73 parser.add_argument('--oval-releases', default=None, nargs='+',
100 help='specifies releases to generate the oval')74 help='only generate OVAL for specific releases')
101 parser.add_argument('--packages', nargs='+', action='store', default=None,75 parser.add_argument('--packages', nargs='+', action='store', default=None,
102 help='generates oval for specific packages. Only for '76 help='generates OVAL for specific packages')
103 'CVE OVAL')
104 parser.add_argument('--fixed-only', action='store_true',77 parser.add_argument('--fixed-only', action='store_true',
105 help='only generate pkg oval for fixed CVEs')78 help='only generate OVAL for fixed CVEs')
106 parser.add_argument('--expand', action='store_true',79 parser.add_argument('--expand', action='store_true', default=False,
107 help='avoids combining all the oval data into one '80 help='avoids combining all the OVAL data into one '
108 'file and expands the output oval files into different '81 'file and expands the output OVAL files into different '
109 'releases, such as esm-apps, esm-infra, and ubuntu')82 'releases, such as esm-apps, esm-infra, and ubuntu')
11083
111 args = parser.parse_args()84 args = parser.parse_args()
112 pathnames = args.pathname or default_cves_to_process
113 debug_level = args.debug85 debug_level = args.debug
11486
115 # debugging; caution, can expose credentials87 if args.output_dir and not os.path.isdir(args.output_dir):
116 if debug_level >= 2:88 raise FileNotFoundError("Could not find '%s'" % args.output_dir)
117 import httplib2
118 httplib2.debuglevel = 1
119
120 # create oval generators for each supported release
121 outdir = './'
122 if args.output_dir:
123 outdir = args.output_dir
124 if not os.path.isdir(outdir):
125 raise FileNotFoundError("Could not find '%s'" % outdir)
126 if args.oci:
127 if args.oci_output_dir:
128 ocioutdir = args.oci_output_dir
129 else:
130 ocioutdir = args.output_dir
131 if not os.path.isdir(ocioutdir):
132 raise FileNotFoundError("Could not find '%s'" % ocioutdir)
133 ociprefix = args.oci_prefix
134 if outdir == ocioutdir and len(ociprefix) < 1:
135 raise ValueError("oci-prefix must be set when output-dir and oci-output-dir are the same")
136
137 if args.usn_oval:
138 if args.oci:
139 generate_oval_usn(args.output_dir, args.usn_number, args.oval_releases,
140 args.cve_prefix_dir, args.usn_db_dir, args.no_progress, ociprefix, ocioutdir)
141 else:
142 generate_oval_usn(args.output_dir, args.usn_number, args.oval_releases,
143 args.cve_prefix_dir, args.usn_db_dir, args.no_progress,)
14489
145 return90 if args.oci_prefix:
91 if not args.oci_output_dir:
92 args.oci_output_dir = args.output_dir
93 elif args.output_dir == args.oci_output_dir and len(args.oci_prefix) < 1:
94 raise ValueError("oci-prefix must be set when output-dir and oci-output-dir are the same")
14695
147 # if --oval-release, we still need to load parents cache96 releases = []
148 # so we can generate a complete oval for those releases that
149 # have a parent
150 releases = supported_releases
151 if args.oval_releases:97 if args.oval_releases:
152 releases = args.oval_releases98 releases = args.oval_releases
153 for release in releases:99 for release in releases:
154 if release not in supported_releases:100 if not needs_oval(release):
155 error(f"unknown oval release {release}")101 error(f"unknown oval release {release}")
102 else:
103 releases = []
104 for r in set(all_releases).difference(set(eol_releases)).difference(set([devel_release])):
105 if needs_oval(r):
106 releases.append(r)
107
108 # for each release we need to get its parent to also
109 # load their cache data in order to generate a complete
110 # oval for such release
111 parent_releases = set()
112 for release in releases:
113 while(release_parent(release)):
114 release = release_parent(release)
115 parent_releases.add(release)
156116
157 expand = args.expand117 releases = set(releases + list(parent_releases))
158
159 cache = {}
160 for release in supported_releases:
161 cve_cache = {}
162 cache.update({release: get_package_cache(args.pkg_cache_dir, release)})
163
164 if args.pkg_oval:
165 if args.oci:
166 generate_oval_package(releases, outdir, args.cve_prefix_dir, cache, cve_cache, args.oci, args.no_progress, args.packages, pathnames, args.fixed_only, ocioutdir, expand)
167 else:
168 generate_oval_package(releases, outdir, args.cve_prefix_dir, cache, cve_cache, args.oci, args.no_progress, args.packages, pathnames, args.fixed_only, expand)
169 return
170118
171 if args.oci:119 if args.type == 'usn':
172 generate_oval_cve(releases, outdir, args.cve_prefix_dir, cache, cve_cache, args.oci, args.no_progress, args.packages, pathnames, args.fixed_only, ocioutdir, expand)120 generate_oval_usn(args.output_dir, args.usn_number, releases,
121 args.cves, args.usn_db_dir, args.no_progress, args.oci_prefix, args.oci_output_dir)
173 else:122 else:
174 generate_oval_cve(releases, outdir, args.cve_prefix_dir, cache, cve_cache, args.oci, args.no_progress, args.packages, pathnames, args.fixed_only, expand)123 cache = {}
175 return124 for release in releases:
176125 cve_cache = {}
177126 cache.update({release: get_package_cache(args.pkg_cache_dir, release)})
178# given a status generated by parse_package_status(), duplicate it for a127
179# different source package, computing binary packages for the new source128 if args.type == 'pkg':
180# package129 generate_oval_package(releases, args.output_dir, args.cves, cache, cve_cache, args.oci, args.no_progress, args.packages, args.fixed_only, args.oci_output_dir, args.expand)
181def duplicate_package_status(release, package, original_status, cache, override_version=None):130 elif args.type == 'cve':
182 copied_status = {}131 generate_oval_cve(releases, args.output_dir, args.cves, cache, cve_cache, args.oci, args.no_progress, args.packages, args.fixed_only, args.oci_output_dir, args.expand)
183 copied_status['status'] = original_status['status']
184 copied_status['note'] = original_status['note']
185 if override_version:
186 copied_status['fix-version'] = override_version
187 elif 'fix-version' in original_status:
188 copied_status['fix-version'] = original_status['fix-version']
189
190 if 'bin-pkgs' in original_status:
191 copied_status['bin-pkgs'] = original_status['bin-pkgs']
192
193 return copied_status
194
195
196# returns True if we should ignore this source package; primarily used
197# for -edge kernels
198def ignore_source_package(source):
199 if re.match('linux-.*-edge$', source):
200 return True
201 if re.match('linux-riscv.*$', source):
202 # linux-riscv.* currently causes a lot of false positives, skip
203 # it altogether while we don't land a better fix
204 return True
205 return False
206
207
208def parse_cve_file(filepath, cache, pkg_filter=None, expand=False):
209 """ parse CVE data file into a dictionary using cve_lib """
210
211 cve_header_data = {
212 'Candidate': '',
213 'CRD': '',
214 'PublicDate': '',
215 'PublicDateAtUSN': '',
216 'References': [get_cve_url(filepath)],
217 'Description': '',
218 'Ubuntu-Description': '',
219 'Notes': '',
220 'Mitigation': '',
221 'Bugs': [],
222 'Priority': '',
223 'Discovered-by': '',
224 'Assigned-to': '',
225 'CVSS': '',
226 'Unknown-Fields': [],
227 'Source-note': filepath
228 }
229 data = load_cve(filepath)
230 # first try a naive translation of fields
231 for f in cve_header_data:
232 try:
233 cve_header_data[f] = data[f]
234 except KeyError:
235 pass
236
237 # then handle any particular fields which are expected to have a
238 # different format
239 cve_header_data['Description'] = cve_header_data['Description'].strip().replace('\n', ' ')
240 cve_header_data['Ubuntu-Description'] = cve_header_data['Ubuntu-Description'].strip().replace('\n', ' ')
241 cve_header_data['References'] = [ref.strip() for ref in cve_header_data['References'].split('\n') if len(ref.strip()) > 0]
242 cve_header_data['References'].insert(0, get_cve_url(filepath))
243 cve_header_data['Bugs'] = [bug.strip() for bug in cve_header_data['Bugs'].split('\n') if len(bug.strip()) > 0]
244 cve_header_data['Notes'] = ' '.join(user + '> ' + note.replace('\n', ' ') for user, note in cve_header_data['Notes'])
245 cve_header_data['Priority'] = cve_header_data['Priority'][0]
246 packages = {}
247 for pkg in data['pkgs']:
248 if ignore_source_package(pkg):
249 continue
250 if pkg_filter:
251 if pkg not in pkg_filter:
252 continue
253
254 packages[pkg] = {'Releases': {},
255 'Priority': '',
256 'Tags': []}
257 for rel in data['pkgs'][pkg]:
258 if rel in ['upstream', 'devel']:
259 continue
260 if rel not in supported_releases:
261 continue
262 state, details = data['pkgs'][pkg][rel]
263 packages[pkg]['Releases'][rel] = oval_lib.CVEPkgRelEntry.parse_package_status(rel, pkg, state, details, filepath, cache, oval_lib.find_release_codename(rel), expand)
264
265 # add supplemental packages; usually kernels only need this special case.
266 for package in [name for name in packages if name in kernel_srcs]:
267 for release in [
268 rel for rel in packages[package]['Releases']
269 if packages[package]['Releases'][rel]['status'] != 'not-applicable'
270 ]:
271 # add signed package
272 # handle signed package of subprojects without needing to have them in kernel_lib
273 progenitor = release_progenitor(release)
274 if progenitor:
275 signed_pkg = meta_kernels.get_signed(progenitor, package, quiet=(debug_level < 1))
276 else:
277 signed_pkg = meta_kernels.get_signed(release, package, quiet=(debug_level < 1))
278 if signed_pkg:
279 if signed_pkg not in packages:
280 packages[signed_pkg] = {
281 'Priority': packages[package]['Priority'],
282 'Tags': packages[package]['Tags'],
283 'Releases': {}
284 }
285 if release not in packages[signed_pkg]['Releases']:
286 packages[signed_pkg]['Releases'][release] = \
287 duplicate_package_status(release, signed_pkg, packages[package]['Releases'][release], cache)
288
289 # if subproject is based on an ubuntu release
290 for pkg in packages:
291 # if subproject is DNE for a given package, then copy parent's status
292 for rel in packages[pkg]['Releases']:
293 parent = release_parent(rel)
294 if parent and parent in packages[pkg]['Releases']:
295 if packages[pkg]['Releases'][parent]['status'] != 'not-applicable' and packages[pkg]['Releases'][rel]['status'] == 'not-applicable':
296 packages[pkg]['Releases'][rel] = \
297 duplicate_package_status(parent, pkg, packages[pkg]['Releases'][parent], cache)
298 # this is needed for update instructions
299 progenitor = release_progenitor(parent)
300 if progenitor and progenitor in packages[pkg]['Releases']:
301 if packages[pkg]['Releases'][parent]['status'] == packages[pkg]['Releases'][progenitor]['status']:
302 packages[pkg]['Releases'][rel]['parent'] = progenitor
303 else:
304 packages[pkg]['Releases'][rel]['parent'] = parent
305 else:
306 packages[pkg]['Releases'][rel]['parent'] = parent
307 # if supported release not in CVE file, then copy parent's status
308 for rel in supported_releases:
309 if rel not in packages[pkg]['Releases']:
310 parent = release_parent(rel)
311 if parent and parent not in packages[pkg]['Releases']:
312 parent = release_parent(parent)
313
314 if not parent or parent not in packages[pkg]['Releases']:
315 continue
316
317 packages[pkg]['Releases'][rel] = \
318 duplicate_package_status(parent, pkg, packages[pkg]['Releases'][parent], cache)
319 packages[pkg]['Releases'][rel]['parent'] = parent
320
321 return {'header': cve_header_data, 'packages': packages}
322
323
324def get_cve_url(filepath):
325 """ returns a url to CVE data from a filepath """
326 path = os.path.realpath(filepath).split(os.sep)
327 url = "https://ubuntu.com/security"
328 cve = path[-1]
329 return "%s/%s" % (url, cve)
330132
331133
332def warn(message):134def warn(message):
@@ -343,17 +145,6 @@ def debug(message):
343 if debug_level > 0:145 if debug_level > 0:
344 sys.stdout.write('\rDEBUG: {0}\n'.format(message))146 sys.stdout.write('\rDEBUG: {0}\n'.format(message))
345147
346def progress_bar(current, total, size=20):
347 """ show a simple progress bar on the CLI """
348 current_percent = float(current) / total
349 hashes = '#' * int(round(current_percent * size))
350 spaces = ' ' * (size - len(hashes))
351 sys.stdout.write('\rProgress: [{0}] {1}% ({2} of {3} CVEs processed)'.format(hashes + spaces, int(round(current_percent * 100)), current, total))
352 if (current == total):
353 sys.stdout.write('\n')
354
355 sys.stdout.flush()
356
357def prepend_usn_to_id(usn_database, usn_id):148def prepend_usn_to_id(usn_database, usn_id):
358 if re.search(r'^[0-9]+-[0-9]$', usn_id):149 if re.search(r'^[0-9]+-[0-9]$', usn_id):
359 usn_database[usn_id]['id'] = 'USN-' + usn_id150 usn_database[usn_id]['id'] = 'USN-' + usn_id
@@ -381,15 +172,15 @@ def get_usn_database(usn_db_dir):
381172
382# Usage:173# Usage:
383# for a given release only:174# for a given release only:
384# ./generate-oval --usn-oval --usn-db-dir ~/usndb --usn-oval-release=focal --output-dir /tmp/oval_usn175# ./generate-oval --type usn --usn-db-dir ~/usndb --oval-releases=focal --output-dir /tmp/oval_usn
385# for all the releases:176# for all the releases:
386# ./generate-oval --usn-oval --usn-db-dir ~/usndb --output-dir /tmp/oval_usn177# ./generate-oval --type usn --usn-db-dir ~/usndb --output-dir /tmp/oval_usn
387# for a specific release and USN-number178# for a specific release and USN-number
388# ./generate-oval --usn-oval --usn-db-dir ~/usndb --usn-oval-release=focal --usn-number=1234179# ./generate-oval --type usn --usn-db-dir ~/usndb --oval-releases=focal --usn-number=1234
389# WARNING:180# WARNING:
390# be sure the release you are passing is in the usn-number passed181# be sure the release you are passing is in the usn-number passed
391# otherwise it will generate an oval file without the usn info.182# otherwise it will generate an oval file without the usn info.
392def generate_oval_usn(outdir, usn, usn_releases, cve_dir, usn_db_dir, no_progress, ociprefix=None, ocioutdir=None):183def generate_oval_usn(outdir, usn, usn_releases, cves, usn_db_dir, no_progress, ociprefix, ocioutdir):
393 # Get the usn database.json data184 # Get the usn database.json data
394 usn_database = get_usn_database(usn_db_dir)185 usn_database = get_usn_database(usn_db_dir)
395 if not usn_database:186 if not usn_database:
@@ -404,33 +195,27 @@ def generate_oval_usn(outdir, usn, usn_releases, cve_dir, usn_db_dir, no_progres
404 valid_releases = []195 valid_releases = []
405196
406 # Check or generate valid releases197 # Check or generate valid releases
407 if usn_releases:198 valid_releases = list(filter(lambda release: product_series(release)[0] == PRODUCT_UBUNTU, usn_releases))
408 for usn_release in usn_releases:
409 if usn_release not in supported_releases:
410 error(f"Invalid release name '{usn_release}'.")
411 valid_releases = usn_releases
412 else:
413 valid_releases = list(filter(lambda release: product_series(release)[0] == PRODUCT_UBUNTU, supported_releases))
414199
415 if not no_progress:200 if not no_progress:
416 print('[*] Generating OVAL USN for packages in releases', ', '.join(valid_releases))201 print('[*] Generating OVAL USN for packages in releases', ', '.join(valid_releases))
417202
418 for release in valid_releases:203 for release in valid_releases:
419 ovals.append(oval_lib.OvalGeneratorUSN(release, release_name(release), outdir, cve_dir))204 ovals.append(oval_lib.OvalGeneratorUSN(release, release_name(release), outdir, cves))
420 # Also produce oval generator object for OCI205 # Also produce oval generator object for OCI
421 if ocioutdir:206 if ocioutdir:
422 ovals.append(oval_lib.OvalGeneratorUSN(release, release_name(release), ocioutdir,207 ovals.append(oval_lib.OvalGeneratorUSN(release, release_name(release), ocioutdir,
423 cve_dir, ociprefix, 'oci'))208 cves, ociprefix, 'oci'))
424 # Generate OVAL USN data209 # Generate OVAL USN data
425 if usn:210 if usn:
426 prepend_usn_to_id(usn_database, usn)211 prepend_usn_to_id(usn_database, usn)
427 for oval in ovals:212 for oval in ovals:
428 oval.generate_usn_oval(usn_database[usn], usn_database[usn]['id'], cve_dir)213 oval.generate_usn_oval(usn_database[usn], usn_database[usn]['id'], cves)
429 else:214 else:
430 for usn in sorted(usn_database.keys()):215 for usn in sorted(usn_database.keys()):
431 prepend_usn_to_id(usn_database, usn)216 prepend_usn_to_id(usn_database, usn)
432 for oval in ovals:217 for oval in ovals:
433 oval.generate_usn_oval(usn_database[usn], usn_database[usn]['id'], cve_dir)218 oval.generate_usn_oval(usn_database[usn], usn_database[usn]['id'], cves)
434219
435 for oval in ovals:220 for oval in ovals:
436 oval.write_oval_elements()221 oval.write_oval_elements()
@@ -452,21 +237,20 @@ def filter_releases_for_output(releases, ov):
452 return output_releases237 return output_releases
453238
454239
455def generate_oval_package(releases, outdir, cve_prefix_dir, pkg_cache, cve_cache, oci, no_progress, packages, pathnames, fixed_only, ocioutdir=None, expand=False):240def generate_oval_package(releases, outdir, cves, pkg_cache, cve_cache, oci, no_progress, packages, fixed_only, ocioutdir, expand):
456 if not no_progress:241 if not no_progress:
457 print('[*] Initiating OVAL Generation for PKG')242 print('[*] Initiating OVAL Generation for PKG')
458243
459 ov = oval_lib.OvalGeneratorPkg(244 ov = oval_lib.OvalGeneratorPkg(
460 releases, 245 releases,
461 pathnames, 246 cves,
462 packages, 247 packages,
463 not no_progress, 248 not no_progress,
464 pkg_cache=pkg_cache, 249 pkg_cache=pkg_cache,
465 fixed_only=fixed_only, 250 fixed_only=fixed_only,
466 cve_cache=cve_cache, 251 cve_cache=cve_cache,
467 oval_format='dpkg',252 oval_format='dpkg',
468 outdir=outdir, 253 outdir=outdir,
469 cve_prefix_dir=cve_prefix_dir,
470 expand=expand254 expand=expand
471 )255 )
472256
@@ -485,21 +269,20 @@ def generate_oval_package(releases, outdir, cve_prefix_dir, pkg_cache, cve_cache
485 if not no_progress:269 if not no_progress:
486 print(f'[X] Done generating OVAL PKG for packages in releases {", ".join(output_releases)}')270 print(f'[X] Done generating OVAL PKG for packages in releases {", ".join(output_releases)}')
487271
488def generate_oval_cve(releases, outdir, cve_prefix_dir, pkg_cache, cve_cache, oci, no_progress, packages, pathnames, fixed_only, ocioutdir=None, expand=False):272def generate_oval_cve(releases, outdir, cves, pkg_cache, cve_cache, oci, no_progress, packages, fixed_only, ocioutdir, expand):
489 if not no_progress:273 if not no_progress:
490 print('[*] Initiating OVAL Generation for CVE')274 print('[*] Initiating OVAL Generation for CVE')
491275
492 ov = oval_lib.OvalGeneratorCVE(276 ov = oval_lib.OvalGeneratorCVE(
493 releases, 277 releases,
494 pathnames, 278 cves,
495 packages, 279 packages,
496 not no_progress,280 not no_progress,
497 pkg_cache=pkg_cache, 281 pkg_cache=pkg_cache,
498 fixed_only=fixed_only, 282 fixed_only=fixed_only,
499 cve_cache=cve_cache, 283 cve_cache=cve_cache,
500 oval_format='dpkg',284 oval_format='dpkg',
501 outdir=outdir, 285 outdir=outdir,
502 cve_prefix_dir=cve_prefix_dir,
503 expand=expand286 expand=expand
504 )287 )
505288
diff --git a/scripts/oval_lib.py b/scripts/oval_lib.py
index d60c6dc..a974eaf 100644
--- a/scripts/oval_lib.py
+++ b/scripts/oval_lib.py
@@ -29,7 +29,6 @@ import tempfile
29import collections29import collections
30import glob30import glob
31import xml.etree.cElementTree as etree31import xml.etree.cElementTree as etree
32import json
33from xml.dom import minidom32from xml.dom import minidom
34from typing import Tuple # Needed because of Python < 3.9 and to also support < 3.733from typing import Tuple # Needed because of Python < 3.9 and to also support < 3.7
3534
@@ -172,7 +171,7 @@ def get_binarypkgs(cache, source_name, release):
172 """ return a list of binary packages from the source package version """171 """ return a list of binary packages from the source package version """
173 packages_to_ignore = ("-dev", "-doc", "-dbg", "-dbgsym", "-udeb", "-locale-")172 packages_to_ignore = ("-dev", "-doc", "-dbg", "-dbgsym", "-udeb", "-locale-")
174 binaries_map = collections.defaultdict(dict)173 binaries_map = collections.defaultdict(dict)
175 174
176 rel = get_real_release(cache, source_name, release)175 rel = get_real_release(cache, source_name, release)
177 if not rel: return None, None176 if not rel: return None, None
178177
@@ -316,7 +315,7 @@ class CVE:
316 self.bugs.append(url)315 self.bugs.append(url)
317 elif url:316 elif url:
318 self.references.append(url)317 self.references.append(url)
319 318
320 for bug in info['Bugs'].split('\n'):319 for bug in info['Bugs'].split('\n'):
321 if bug:320 if bug:
322 self.bugs.append(bug)321 self.bugs.append(bug)
@@ -331,7 +330,7 @@ class CVE:
331 for pkg in self.pkgs:330 for pkg in self.pkgs:
332 if pkg.rel not in releases:331 if pkg.rel not in releases:
333 continue332 continue
334 333
335 if pkg.name not in pkg_rel:334 if pkg.name not in pkg_rel:
336 pkg_rel[pkg.name] = pkg335 pkg_rel[pkg.name] = pkg
337 else:336 else:
@@ -356,7 +355,7 @@ class CVE:
356355
357 if pkg.name in pkg_rel and pkg_rel[pkg.name].rel == pkg.rel:356 if pkg.name in pkg_rel and pkg_rel[pkg.name].rel == pkg.rel:
358 pkgs.append(pkg)357 pkgs.append(pkg)
359 358
360 return pkgs359 return pkgs
361360
362361
@@ -429,7 +428,7 @@ class Package:
429428
430 def version_exists(self, source_version):429 def version_exists(self, source_version):
431 return source_version in self.versions_binaries430 return source_version in self.versions_binaries
432 431
433 def all_binaries_same_version(self, source_version):432 def all_binaries_same_version(self, source_version):
434 if source_version not in self.versions_binaries:433 if source_version not in self.versions_binaries:
435 return len(self.versions_binaries[self.earliest_version]) <= 1434 return len(self.versions_binaries[self.earliest_version]) <= 1
@@ -514,7 +513,7 @@ class OvalGenerator:
514 supported_oval_elements = ('definition', 'test', 'object', 'state', 'variable')513 supported_oval_elements = ('definition', 'test', 'object', 'state', 'variable')
515 generator_version = '2'514 generator_version = '2'
516 oval_schema_version = '5.11.1'515 oval_schema_version = '5.11.1'
517 def __init__(self, type, releases, cve_paths, packages, progress, pkg_cache, fixed_only=True, cve_cache=None, cve_prefix_dir=None, outdir='./', oval_format='dpkg', expand=False) -> None:516 def __init__(self, type, releases, cve_paths, packages, progress, pkg_cache, fixed_only=True, cve_cache=None, outdir='./', oval_format='dpkg', expand=False) -> None:
518 self.releases = releases517 self.releases = releases
519 self.output_dir = outdir518 self.output_dir = outdir
520 self.oval_format = oval_format519 self.oval_format = oval_format
@@ -524,7 +523,7 @@ class OvalGenerator:
524 self.pkg_cache = pkg_cache523 self.pkg_cache = pkg_cache
525 self.cve_paths = cve_paths524 self.cve_paths = cve_paths
526 self.fixed_only = fixed_only525 self.fixed_only = fixed_only
527 self.packages, self.cves = self._load(cve_prefix_dir, packages)526 self.packages, self.cves = self._load(packages)
528 self.expand = expand527 self.expand = expand
529528
530 def _init_ids(self, release):529 def _init_ids(self, release):
@@ -532,7 +531,7 @@ class OvalGenerator:
532 self.release = release531 self.release = release
533 self.release_codename = cve_lib.release_progenitor(self.release) if cve_lib.release_progenitor(self.release) else self.release.replace('/', '_')532 self.release_codename = cve_lib.release_progenitor(self.release) if cve_lib.release_progenitor(self.release) else self.release.replace('/', '_')
534 self.release_name = cve_lib.release_name(self.release)533 self.release_name = cve_lib.release_name(self.release)
535 534
536 self.parent_releases = list()535 self.parent_releases = list()
537 current_release = self.release536 current_release = self.release
538 while(cve_lib.release_parent(current_release)):537 while(cve_lib.release_parent(current_release)):
@@ -540,7 +539,7 @@ class OvalGenerator:
540 if current_release != self.release and \539 if current_release != self.release and \
541 current_release not in self.parent_releases:540 current_release not in self.parent_releases:
542 self.parent_releases.append(current_release)541 self.parent_releases.append(current_release)
543 542
544 self.ns = 'oval:com.ubuntu.{0}'.format(self.release_codename)543 self.ns = 'oval:com.ubuntu.{0}'.format(self.release_codename)
545 self.id = 100544 self.id = 100
546 self.host_def_id = self.id545 self.host_def_id = self.id
@@ -564,7 +563,7 @@ class OvalGenerator:
564 self.output_filepath = \563 self.output_filepath = \
565 '{0}com.ubuntu.{1}.{2}.oval.xml'.format('oci.' if self.oval_format == 'oci' else '', self.release.replace('/', '_'), self.generator_type)564 '{0}com.ubuntu.{1}.{2}.oval.xml'.format('oci.' if self.oval_format == 'oci' else '', self.release.replace('/', '_'), self.generator_type)
566565
567 566
568 def _add_structure(self, root) -> None:567 def _add_structure(self, root) -> None:
569 structure = {}568 structure = {}
570 for element in self.supported_oval_elements:569 for element in self.supported_oval_elements:
@@ -756,14 +755,14 @@ class OvalGenerator:
756 pkg_obj = packages[package_name]755 pkg_obj = packages[package_name]
757 cve.add_pkg(pkg_obj, release, cve_data['pkgs'][package_name][release][0],cve_data['pkgs'][package_name][release][1], self.expand)756 cve.add_pkg(pkg_obj, release, cve_data['pkgs'][package_name][release][0],cve_data['pkgs'][package_name][release][1], self.expand)
758757
759 def _load(self, cve_prefix_dir, packages_filter=None) -> None:758 def _load(self, packages_filter=None) -> None:
760 cve_lib.load_external_subprojects()759 cve_lib.load_external_subprojects()
761760
762 cve_paths = []761 path_to_cves = []
763 for pathname in self.cve_paths:762 for pathname in self.cve_paths:
764 cve_paths = cve_paths + glob.glob(os.path.join(cve_prefix_dir, pathname))763 path_to_cves = path_to_cves + glob.glob(pathname)
765764
766 cve_paths.sort(key=lambda cve:765 path_to_cves.sort(key=lambda cve:
767 (int(cve.split('/')[-1].split('-')[1]), int(cve.split('/')[-1].split('-')[2])) \766 (int(cve.split('/')[-1].split('-')[1]), int(cve.split('/')[-1].split('-')[2])) \
768 if cve.split('/')[-1].split('-')[2].isnumeric() \767 if cve.split('/')[-1].split('-')[2].isnumeric() \
769 else (int(cve.split('/')[-1].split('-')[1]), 0)768 else (int(cve.split('/')[-1].split('-')[1]), 0)
@@ -790,12 +789,12 @@ class OvalGenerator:
790 if release not in cve_lib.external_releases else {}789 if release not in cve_lib.external_releases else {}
791790
792 i = 0791 i = 0
793 for cve_path in cve_paths:792 for cve_path in path_to_cves:
794 cve_number = cve_path.rsplit('/', 1)[1]793 cve_number = cve_path.rsplit('/', 1)[1]
795 i += 1794 i += 1
796795
797 if self.progress:796 if self.progress:
798 print(f'[{i:5}/{len(cve_paths)}] Processing {cve_number:18}', end='\r')797 print(f'[{i:5}/{len(path_to_cves)}] Processing {cve_number:18}', end='\r')
799798
800 if not cve_number in self.cve_cache:799 if not cve_number in self.cve_cache:
801 self.cve_cache[cve_number] = cve_lib.load_cve(cve_path)800 self.cve_cache[cve_number] = cve_lib.load_cve(cve_path)
@@ -849,7 +848,7 @@ class OvalGenerator:
849 extend_definition.set("applicability_check", "true")848 extend_definition.set("applicability_check", "true")
850849
851 return criteria850 return criteria
852 851
853 def _generate_definition_object(self, object) -> etree.Element:852 def _generate_definition_object(self, object) -> etree.Element:
854 id = f"{self.ns}:def:{self.definition_id}"853 id = f"{self.ns}:def:{self.definition_id}"
855 definition = etree.Element("definition")854 definition = etree.Element("definition")
@@ -889,7 +888,7 @@ class OvalGenerator:
889 cve_tag.set('usns', ','.join(cve.usns))888 cve_tag.set('usns', ','.join(cve.usns))
890889
891 return cve_tag890 return cve_tag
892 891
893 def _generate_var_element(self, comment, id, binaries) -> etree.Element:892 def _generate_var_element(self, comment, id, binaries) -> etree.Element:
894 var = etree.Element("constant_variable",893 var = etree.Element("constant_variable",
895 attrib={894 attrib={
@@ -1323,9 +1322,9 @@ class OvalGenerator:
13231322
13241323
1325class OvalGeneratorPkg(OvalGenerator):1324class OvalGeneratorPkg(OvalGenerator):
1326 def __init__(self, releases, cve_paths, packages, progress, pkg_cache, fixed_only=True, cve_cache=None, cve_prefix_dir=None, outdir='./', oval_format='dpkg',expand=False) -> None:1325 def __init__(self, releases, cve_paths, packages, progress, pkg_cache, fixed_only=True, cve_cache=None, outdir='./', oval_format='dpkg',expand=False) -> None:
1327 self.expand = expand1326 self.expand = expand
1328 super().__init__('pkg', releases, cve_paths, packages, progress, pkg_cache, fixed_only, cve_cache, cve_prefix_dir, outdir, oval_format, expand)1327 super().__init__('pkg', releases, cve_paths, packages, progress, pkg_cache, fixed_only, cve_cache, outdir, oval_format, expand)
13291328
1330 def _generate_advisory(self, package: Package) -> etree.Element:1329 def _generate_advisory(self, package: Package) -> etree.Element:
1331 advisory = etree.Element("advisory")1330 advisory = etree.Element("advisory")
@@ -1431,7 +1430,7 @@ class OvalGeneratorPkg(OvalGenerator):
1431 binary_id_version = binary_version1430 binary_id_version = binary_version
14321431
1433 binaries_ids.setdefault(binary_id_version, None)1432 binaries_ids.setdefault(binary_id_version, None)
1434 binaries_id = binaries_ids[binary_id_version] 1433 binaries_id = binaries_ids[binary_id_version]
1435 test, obj, var, state = self._generate_elements(package, binaries, binary_version, pkg_rel_entry, binaries_id)1434 test, obj, var, state = self._generate_elements(package, binaries, binary_version, pkg_rel_entry, binaries_id)
14361435
1437 if state:1436 if state:
@@ -1451,7 +1450,7 @@ class OvalGeneratorPkg(OvalGenerator):
14511450
1452 self._increase_id(is_definition=True)1451 self._increase_id(is_definition=True)
14531452
1454 def _populate_kernel_pkg(self, package, root_element, running_kernel_id): 1453 def _populate_kernel_pkg(self, package, root_element, running_kernel_id):
1455 for cve in package.cves:1454 for cve in package.cves:
1456 pkg_rel_entry = cve.pkg_rel_entries[str(package)]1455 pkg_rel_entry = cve.pkg_rel_entries[str(package)]
1457 version_to_check = package.get_version_to_check(pkg_rel_entry.fixed_version)1456 version_to_check = package.get_version_to_check(pkg_rel_entry.fixed_version)
@@ -1482,7 +1481,7 @@ class OvalGeneratorPkg(OvalGenerator):
1482 cve_added = True1481 cve_added = True
14831482
1484 # Determine if CVE is linked to existing test_ref1483 # Determine if CVE is linked to existing test_ref
1485 test_ref_id = self.definition_id 1484 test_ref_id = self.definition_id
1486 if fixed_versions.get(pkg_rel_entry.fixed_version, False):1485 if fixed_versions.get(pkg_rel_entry.fixed_version, False):
1487 test_ref_id = fixed_versions[pkg_rel_entry.fixed_version]1486 test_ref_id = fixed_versions[pkg_rel_entry.fixed_version]
1488 self._add_test_ref_to_cve_tag(test_ref_id, cve, definition_element)1487 self._add_test_ref_to_cve_tag(test_ref_id, cve, definition_element)
@@ -1513,7 +1512,7 @@ class OvalGeneratorPkg(OvalGenerator):
1513 all_pkgs = dict()1512 all_pkgs = dict()
1514 for parent_release in self.parent_releases[::-1]:1513 for parent_release in self.parent_releases[::-1]:
1515 all_pkgs.update(self.packages[parent_release])1514 all_pkgs.update(self.packages[parent_release])
1516 1515
1517 all_pkgs.update(self.packages[self.release])1516 all_pkgs.update(self.packages[self.release])
15181517
1519 for pkg in all_pkgs:1518 for pkg in all_pkgs:
@@ -1529,9 +1528,9 @@ class OvalGeneratorPkg(OvalGenerator):
1529 self._write_oval_xml(xml_tree, root_element)1528 self._write_oval_xml(xml_tree, root_element)
15301529
1531class OvalGeneratorCVE(OvalGenerator):1530class OvalGeneratorCVE(OvalGenerator):
1532 def __init__(self, releases, cve_paths, packages, progress, pkg_cache, fixed_only=True, cve_cache=None, cve_prefix_dir=None, outdir='./', oval_format='dpkg', expand=False) -> None:1531 def __init__(self, releases, cve_paths, packages, progress, pkg_cache, fixed_only=True, cve_cache=None, outdir='./', oval_format='dpkg', expand=False) -> None:
1533 self.expand = expand1532 self.expand = expand
1534 super().__init__('cve', releases, cve_paths, packages, progress, pkg_cache, fixed_only, cve_cache, cve_prefix_dir, outdir, oval_format, expand)1533 super().__init__('cve', releases, cve_paths, packages, progress, pkg_cache, fixed_only, cve_cache, outdir, oval_format, expand)
15351534
1536 # For CVE OVAL, the definition ID is generated1535 # For CVE OVAL, the definition ID is generated
1537 # from the CVE ID1536 # from the CVE ID
@@ -1551,7 +1550,7 @@ class OvalGeneratorCVE(OvalGenerator):
1551 if cve.assigned_to:1550 if cve.assigned_to:
1552 assigned_to = etree.SubElement(advisory, "assigned_to")1551 assigned_to = etree.SubElement(advisory, "assigned_to")
1553 assigned_to.text = cve.assigned_to1552 assigned_to.text = cve.assigned_to
1554 1553
1555 if cve.discoverd_by:1554 if cve.discoverd_by:
1556 discoverd_by = etree.SubElement(advisory, "discoverd_by")1555 discoverd_by = etree.SubElement(advisory, "discoverd_by")
1557 discoverd_by.text = cve.discoverd_by1556 discoverd_by.text = cve.discoverd_by
@@ -1596,7 +1595,7 @@ class OvalGeneratorCVE(OvalGenerator):
1596 "ref_url": f'https://cve.mitre.org/cgi-bin/cvename.cgi?name={cve.number}'1595 "ref_url": f'https://cve.mitre.org/cgi-bin/cvename.cgi?name={cve.number}'
1597 })1596 })
15981597
1599 return reference 1598 return reference
16001599
1601 def prepare_instructions(self, instruction, cve: CVE, product_description, package: Package, fixed_version):1600 def prepare_instructions(self, instruction, cve: CVE, product_description, package: Package, fixed_version):
1602 if "LSN" in cve.number:1601 if "LSN" in cve.number:
@@ -1729,13 +1728,13 @@ class OvalGeneratorCVE(OvalGenerator):
1729 pkg_added = True1728 pkg_added = True
1730 else:1729 else:
1731 pkg_added = self._populate_pkg(cve, pkg, root_element, definition_element, pkg_cache, fixed_versions)1730 pkg_added = self._populate_pkg(cve, pkg, root_element, definition_element, pkg_cache, fixed_versions)
1732 1731
1733 if pkg_rel_entry.status == 'fixed' and pkg_added:1732 if pkg_rel_entry.status == 'fixed' and pkg_added:
1734 product_description = cve_lib.get_subproject_description(pkg_rel_entry.release)1733 product_description = cve_lib.get_subproject_description(pkg_rel_entry.release)
1735 instructions = self.prepare_instructions(instructions, cve, product_description, pkg, pkg_rel_entry.fixed_version)1734 instructions = self.prepare_instructions(instructions, cve, product_description, pkg, pkg_rel_entry.fixed_version)
17361735
1737 cve_added = cve_added | pkg_added1736 cve_added = cve_added | pkg_added
1738 1737
1739 if cve_added:1738 if cve_added:
1740 definitions = root_element.find("definitions")1739 definitions = root_element.find("definitions")
1741 metadata = definition_element.find('metadata')1740 metadata = definition_element.find('metadata')
@@ -1780,8 +1779,8 @@ class OvalGeneratorCVE(OvalGenerator):
1780 self._write_oval_xml(xml_tree, root_element)1779 self._write_oval_xml(xml_tree, root_element)
17811780
1782class OvalGeneratorUSNs(OvalGenerator):1781class OvalGeneratorUSNs(OvalGenerator):
1783 def __init__(self, releases, cve_paths, packages, progress, pkg_cache, usn_database, fixed_only=True, cve_cache=None, cve_prefix_dir=None, outdir='./', oval_format='dpkg') -> None:1782 def __init__(self, releases, cve_paths, packages, progress, pkg_cache, usn_database, fixed_only=True, cve_cache=None, outdir='./', oval_format='dpkg') -> None:
1784 super().__init__('usn', releases, cve_paths, packages, progress, pkg_cache, fixed_only, cve_cache, cve_prefix_dir, outdir, oval_format)1783 super().__init__('usn', releases, cve_paths, packages, progress, pkg_cache, fixed_only, cve_cache, outdir, oval_format)
1785 self.usns = self._load_usns(usn_database)1784 self.usns = self._load_usns(usn_database)
17861785
1787 def _load_usns(self, usn_database):1786 def _load_usns(self, usn_database):
@@ -1838,7 +1837,7 @@ class OvalGeneratorUSNs(OvalGenerator):
1838 platform = etree.SubElement(affected, "platform")1837 platform = etree.SubElement(affected, "platform")
18391838
1840 reference = self._generate_reference(usn)1839 reference = self._generate_reference(usn)
1841 metadata.append(reference) 1840 metadata.append(reference)
1842 advisory = self._generate_advisory(usn)1841 advisory = self._generate_advisory(usn)
1843 metadata.append(reference)1842 metadata.append(reference)
1844 metadata.append(advisory)1843 metadata.append(advisory)
@@ -1920,7 +1919,7 @@ class OvalGeneratorUSNs(OvalGenerator):
1920 self._increase_id(is_definition=False)1919 self._increase_id(is_definition=False)
1921 else:1920 else:
1922 self._add_to_criteria(main_criteria, cache[package.name], depth=2, operator='OR')1921 self._add_to_criteria(main_criteria, cache[package.name], depth=2, operator='OR')
1923 1922
1924 self._increase_id(is_definition=True)1923 self._increase_id(is_definition=True)
19251924
1926 def generate_oval(self) -> None:1925 def generate_oval(self) -> None:
@@ -1952,11 +1951,11 @@ class OvalGeneratorUSNs(OvalGenerator):
1952 self._populate_kernel_pkg(self.cves[cve], pkg, root_element, definition_element, running_kernel_id, pkg_cache, fixed_versions)1951 self._populate_kernel_pkg(self.cves[cve], pkg, root_element, definition_element, running_kernel_id, pkg_cache, fixed_versions)
1953 else:1952 else:
1954 self._populate_pkg(self.cves[cve], pkg, root_element, definition_element, pkg_cache, fixed_versions)1953 self._populate_pkg(self.cves[cve], pkg, root_element, definition_element, pkg_cache, fixed_versions)
1955 1954
1956 if pkg_rel_entry.status == 'fixed' and pkg.binaries:1955 if pkg_rel_entry.status == 'fixed' and pkg.binaries:
1957 product_description = cve_lib.get_subproject_description(pkg_rel_entry.release)1956 product_description = cve_lib.get_subproject_description(pkg_rel_entry.release)
1958 instructions = prepare_instructions(instructions, self.cves[cve].number, product_description, {'binaries': pkg.binaries, 'fix-version': pkg_rel_entry.fixed_version})1957 instructions = prepare_instructions(instructions, self.cves[cve].number, product_description, {'binaries': pkg.binaries, 'fix-version': pkg_rel_entry.fixed_version})
1959 1958
1960 metadata = definition_element.find('metadata')1959 metadata = definition_element.find('metadata')
1961 metadata.find('description').text = metadata.find('description').text + instructions1960 metadata.find('description').text = metadata.find('description').text + instructions
1962 definitions.append(definition_element)1961 definitions.append(definition_element)
@@ -2467,14 +2466,13 @@ class OvalGeneratorUSN():
2467 return constant_variable2466 return constant_variable
24682467
2469 def get_cve_info_from_file(self, cve, cve_dir):2468 def get_cve_info_from_file(self, cve, cve_dir):
2470 cve_active_file_path = os.path.join(cve_dir, 'active', cve)2469 cve_file_path = ""
2471 cve_retired_file_path = os.path.join(cve_dir, 'retired', cve)2470 for path in cve_dir:
2471 if os.path.exists(os.path.join(path, cve)):
2472 cve_file_path = os.path.join(path, cve)
2473 break
24722474
2473 if os.path.exists(cve_active_file_path):2475 if not cve_file_path:
2474 cve_file_path = cve_active_file_path
2475 elif os.path.exists(cve_retired_file_path):
2476 cve_file_path = cve_retired_file_path
2477 else:
2478 return None2476 return None
24792477
2480 cve_object = cve_lib.load_cve(cve_file_path)2478 cve_object = cve_lib.load_cve(cve_file_path)
diff --git a/test/test_oval_lib_end_to_end.py b/test/test_oval_lib_end_to_end.py
index bfad6c4..db74957 100644
--- a/test/test_oval_lib_end_to_end.py
+++ b/test/test_oval_lib_end_to_end.py
@@ -6,13 +6,13 @@ from test_utils import TestUtilities as util
6from test_utils import OVALType6from test_utils import OVALType
7class TestOvalLibEndToEnd:7class TestOvalLibEndToEnd:
8 @pytest.mark.parametrize("output_file,oscap_args",8 @pytest.mark.parametrize("output_file,oscap_args",
9 [(util.focal_dpkg_file, ["--oval-release", "focal"]),9 [(util.focal_dpkg_file, ["--oval-releases", "focal"]),
10 (util.xenial_dpkg_file, ["--oval-release", "xenial"])])10 (util.xenial_dpkg_file, ["--oval-releases", "xenial"])])
11 def test_validate_entire_dpkg_oval(self, output_file, oscap_args):11 def test_validate_entire_dpkg_oval(self, output_file, oscap_args):
12 """Coherence check of entire generated dpkg OVAL"""12 """Coherence check of entire generated dpkg OVAL"""
13 write_file = util.rel_test_path + output_file13 write_file = util.rel_test_path + output_file
1414
15 subprocess.check_output(["./scripts/generate-oval", "--usn-oval",15 subprocess.check_output(["./scripts/generate-oval", "--type=usn",
16 "--output-dir={}".format(util.rel_test_path)] + oscap_args,16 "--output-dir={}".format(util.rel_test_path)] + oscap_args,
17 stderr=subprocess.STDOUT)17 stderr=subprocess.STDOUT)
1818
@@ -29,4 +29,4 @@ class TestOvalLibEndToEnd:
29 def test_validate_entire_oci_oval(self, dpkg_file, manifest, release):29 def test_validate_entire_oci_oval(self, dpkg_file, manifest, release):
30 """Coherence check of entire generated oci OVAL"""30 """Coherence check of entire generated oci OVAL"""
31 util.create_validate_oci(dpkg_file, "{}_full".format(release),31 util.create_validate_oci(dpkg_file, "{}_full".format(release),
32 ["--oval-release", release], manifest, release, OVALType.USN)32 ["--oval-releases", release], manifest, release, OVALType.USN)
diff --git a/test/test_oval_lib_functional.py b/test/test_oval_lib_functional.py
index 8b400fb..aad0116 100644
--- a/test/test_oval_lib_functional.py
+++ b/test/test_oval_lib_functional.py
@@ -12,18 +12,18 @@ class TestOvalLibFunctional:
12 def test_multiple_binary_package(self, manifest):12 def test_multiple_binary_package(self, manifest):
13 """Test a package with multiple binaries"""13 """Test a package with multiple binaries"""
14 util.create_validate_oci(util.focal_dpkg_file, "focal_4410",14 util.create_validate_oci(util.focal_dpkg_file, "focal_4410",
15 ["--usn-number", "4410-1", "--oval-release", "focal"],15 ["--usn-number", "4410-1", "--oval-releases", "focal"],
16 manifest, "focal_mock_4410_vul", OVALType.USN)16 manifest, "focal_mock_4410_vul", OVALType.USN)
1717
18 @pytest.mark.parametrize("manifest",18 @pytest.mark.parametrize("manifest",
19 # Binary is in manifest and not vulnerable 19 # Binary is in manifest and not vulnerable
20 [("bionic_mock_3642_not_vul"),20 [("bionic_mock_3642_not_vul"),
21 # Binary is in manifest and vulnerable 21 # Binary is in manifest and vulnerable
22 ("bionic_mock_3642_vul")])22 ("bionic_mock_3642_vul")])
23 def test_single_binary_package(self, manifest):23 def test_single_binary_package(self, manifest):
24 """Test a package with a single binary"""24 """Test a package with a single binary"""
25 util.create_validate_oci(util.bionic_dpkg_file, "bionic_3642",25 util.create_validate_oci(util.bionic_dpkg_file, "bionic_3642",
26 ["--usn-number", "3642-1", "--oval-release", "bionic"],26 ["--usn-number", "3642-1", "--oval-releases", "bionic"],
27 manifest, manifest, OVALType.USN)27 manifest, manifest, OVALType.USN)
2828
29 @pytest.mark.parametrize("manifest",29 @pytest.mark.parametrize("manifest",
@@ -34,7 +34,7 @@ class TestOvalLibFunctional:
34 def test_multiple_packages_usn(self, manifest):34 def test_multiple_packages_usn(self, manifest):
35 """Test USN with multiple source packages"""35 """Test USN with multiple source packages"""
36 util.create_validate_oci(util.bionic_dpkg_file, "bionic_4428",36 util.create_validate_oci(util.bionic_dpkg_file, "bionic_4428",
37 ["--usn-number", "4428-1", "--oval-release", "bionic"],37 ["--usn-number", "4428-1", "--oval-releases", "bionic"],
38 manifest, "bionic_mock_4428", OVALType.USN)38 manifest, "bionic_mock_4428", OVALType.USN)
3939
40 @pytest.mark.parametrize("manifest,gold_file,usn",40 @pytest.mark.parametrize("manifest,gold_file,usn",
@@ -68,7 +68,7 @@ class TestOvalLibFunctional:
68 def test_epoch(self, manifest, gold_file, usn):68 def test_epoch(self, manifest, gold_file, usn):
69 """Test epochs are used correctly in vulnerability assesments"""69 """Test epochs are used correctly in vulnerability assesments"""
70 util.create_validate_oci(util.focal_dpkg_file, "focal_{}".format(usn),70 util.create_validate_oci(util.focal_dpkg_file, "focal_{}".format(usn),
71 ["--usn-number", usn, "--oval-release", "focal"], manifest,71 ["--usn-number", usn, "--oval-releases", "focal"], manifest,
72 gold_file, OVALType.USN)72 gold_file, OVALType.USN)
7373
7474
diff --git a/test/test_oval_lib_unit.py b/test/test_oval_lib_unit.py
index c3abf85..ab3a758 100644
--- a/test/test_oval_lib_unit.py
+++ b/test/test_oval_lib_unit.py
@@ -429,8 +429,8 @@ No subscription required"""
429 assert cve_info is None429 assert cve_info is None
430430
431 def test_create_dict_from_cve_file(self):431 def test_create_dict_from_cve_file(self):
432 cve_dir = os.environ["UCT"]432 cve_dir = os.path.join(os.environ["UCT"], "active/")
433 dst_cve_file = os.path.join(cve_dir, "active", self.test_cve_file)433 dst_cve_file = os.path.join(cve_dir, self.test_cve_file)
434 src_cve_file = os.path.join(rel_test_path, self.test_cve_file)434 src_cve_file = os.path.join(rel_test_path, self.test_cve_file)
435 copyfile(src_cve_file, dst_cve_file)435 copyfile(src_cve_file, dst_cve_file)
436 corr_cve_info = {436 corr_cve_info = {
@@ -451,7 +451,7 @@ No subscription required"""
451 }451 }
452452
453 cve_info = oval_lib.OvalGeneratorUSN.get_cve_info_from_file(453 cve_info = oval_lib.OvalGeneratorUSN.get_cve_info_from_file(
454 self.oval_gen_mock, self.test_cve_file, cve_dir)454 self.oval_gen_mock, self.test_cve_file, [cve_dir])
455455
456 try:456 try:
457 assert cve_info == corr_cve_info457 assert cve_info == corr_cve_info
diff --git a/test/test_utils.py b/test/test_utils.py
index 682e45a..d62a842 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -6,9 +6,9 @@ import subprocess
6from enum import Enum6from enum import Enum
77
8class OVALType(Enum):8class OVALType(Enum):
9 USN = '--usn-oval'9 USN = '--type=usn'
10 CVE = ''10 CVE = '--type=cve'
11 PKG = '--pkg-oval'11 PKG = '--type=pkg'
1212
13class TestUtilities:13class TestUtilities:
14 cwd = os.getcwd()14 cwd = os.getcwd()

Subscribers

People subscribed via source and target branches