Merge ~eslerm/ubuntu-cve-tracker:check-cves-f-strings into ubuntu-cve-tracker:master

Proposed by Mark Esler
Status: Merged
Merged at revision: 6f6eb4c1ef0abf924ca1755f68da9bfb3b5aa8cf
Proposed branch: ~eslerm/ubuntu-cve-tracker:check-cves-f-strings
Merge into: ubuntu-cve-tracker:master
Diff against target: 701 lines (+123/-117)
1 file modified
scripts/check-cves (+123/-117)
Reviewer Review Type Date Requested Status
Steve Beattie Approve
Marc Deslauriers Approve
Review via email: mp+462539@code.launchpad.net

Commit message

check-cves: switch formatting regular strings to f-strings and friends

Description of the change

Converts formatting of regular strings to f-strings.

> F-strings provide a concise, readable way to include the value of Python expressions inside strings.
https://peps.python.org/pep-0498/

f-strings were introduced in 3.6. This means that f-strings work on bionic++.

There are four remaining cases involving regex that I did not want to change and test in this MR.

There are several cases where `print("%s" % foo)` is replaced as `print(foo)`.

And a case where concatenating strings was clearer. e.g., `str_a + str_b`

Note that f-strings cannot contain backslashes, hence cases like `print(" %s" % "\n ".join(info))` are kept.

This is my second time linting check-cves to use f-strings. I reviewed my code several times for errors after my final commit and ran several use cases.

To post a comment you must log in.
Revision history for this message
Marc Deslauriers (mdeslaur) wrote :

These changes LGTM. Thanks for breaking down all your refactoring into reviewable changes!

review: Approve
Revision history for this message
Steve Beattie (sbeattie) wrote :

 review approve

On Fri, Mar 15, 2024 at 10:52:17PM -0000, Mark Esler wrote:
> @@ -1344,20 +1351,20 @@ class CVEHandler(xml.sax.handler.ContentHandler):
> if dpkg_compare_versions(version, 'ge', fixed_version):
> if rel == cve_lib.devel_release:
> rel = 'devel'
> - fixed_in += ",%s,%s" % (rel, version)
> + fixed_in += f",{rel},{version}"
> break
> elif self.debian[cve]['pkgs'][pkg]['state'].startswith('<not-affected>') and \
> len(self.debian[cve]['pkgs'][pkg]['priority']) > 0:
> # capture that debian believes their version is unaffected
> - not_affected.append((pkg, "debian: %s" % self.debian[cve]['pkgs'][pkg]['priority']))
> - cmd += ['-p', "%s%s" % (pkg, fixed_in)]
> + not_affected.append(pkg, f"debian: {self.debian[cve]['pkgs'][pkg]['priority']}")

Note that the append() call here gets converted from a tuple to two
arguments, which append() won't accept. I added a commit to reinstate
the tuple:

 https://git.launchpad.net/ubuntu-cve-tracker/commit/?id=946c26c48f8619120efe31c73581823d082dbb42

and have merged your changes with it to master.

Thanks!

--
Steve Beattie
<email address hidden>

review: Approve
Revision history for this message
Marc Deslauriers (mdeslaur) wrote :

Oh, nice catch, I didn't notice that one.

Revision history for this message
Mark Esler (eslerm) wrote :

Thank you for the thorough review and merge!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/scripts/check-cves b/scripts/check-cves
2index 0ce30ef..c00cd27 100755
3--- a/scripts/check-cves
4+++ b/scripts/check-cves
5@@ -254,7 +254,7 @@ def import_debian(handler):
6 for cve in dsas[dsa]['cves']:
7 if not cve_lib.CVE_RE.match(cve):
8 if args.verbose:
9- print("Skipping %s, not well-formed?" % cve, file=sys.stderr)
10+ print(f"Skipping {cve}, not well-formed?", file=sys.stderr)
11 continue
12
13 year = int(re.split('-', cve)[1])
14@@ -275,27 +275,27 @@ def import_debian(handler):
15 cves[cve]['date'] = dsas[dsa]['date']
16
17 if args.verbose:
18- print("Processing %s: %s (%s)" % (dsa, dsas[dsa]['desc'], cves[cve]['date']), file=sys.stderr)
19+ print(f"Processing {dsa}: {dsas[dsa]['desc']} ({cves[cve]['date']})", file=sys.stderr)
20
21 # Now pull in CVEs from the data/CVE/list
22 for cve in handler.debian:
23 if args.verbose:
24- print("[--- Processing %s ---]" % cve, file=sys.stderr)
25+ print(f"[--- Processing {cve} ---]", file=sys.stderr)
26
27 if cve in cves:
28 if args.verbose:
29- print("Skipping %s, already found in DSA" % cve, file=sys.stderr)
30+ print(f"Skipping {cve}, already found in DSA", file=sys.stderr)
31 continue
32
33 if not cve_lib.CVE_RE.match(cve):
34 if args.verbose:
35- print("Skipping %s, not well-formed?" % cve, file=sys.stderr)
36+ print(f"Skipping {cve}, not well-formed?", file=sys.stderr)
37 continue
38
39 year = int(re.split('-', cve)[1])
40 if year < cve_limit:
41 if args.verbose:
42- print("Skipping %s, year %d predates %d" % (cve, year, cve_limit), file=sys.stderr)
43+ print(f"Skipping {cve}, year {year} predates {cve_limit}", file=sys.stderr)
44 continue
45
46 # If we already know about the CVE, skip it unless is mistriaged
47@@ -305,7 +305,7 @@ def import_debian(handler):
48 handler.debian[cve]['desc'] = mistriaged_hint + handler.debian[cve]['desc']
49 else:
50 if args.verbose:
51- print("Skipping %s, already known" % cve, file=sys.stderr)
52+ print(f"Skipping {cve}, already known", file=sys.stderr)
53 continue
54
55 if handler.debian[cve]['desc'] or handler.debian[cve]['state'] == 'FOUND':
56@@ -315,13 +315,13 @@ def import_debian(handler):
57 cves[cve]['subject'] = '[Unknown description]'
58
59 # just make something up. It'll get adjusted whenever mitre adds it
60- date = "%s-12-31" % year
61+ date = f"{year}-12-31"
62 if year >= today.year:
63- date = "%s-%s-%s" % (today.year, today.month, today.day)
64+ date = f"{today.year}-{today.month}-{today.day}"
65 cves[cve]['date'] = datetime.strptime(date, "%Y-%m-%d")
66
67 if args.verbose:
68- print("Processing %s: %s (%s)" % (cve, handler.debian[cve]['desc'], cves[cve]['date']), file=sys.stderr)
69+ print(f"Processing {cve}: {handler.debian[cve]['desc']} ({cves[cve]['date']})", file=sys.stderr)
70
71 nvd = convert_to_nvd(cves, lambda cve: cves[cve]['subject'])
72 tmp = tempfile.NamedTemporaryFile(mode='w', prefix='debian-import_', suffix='.json', delete=False)
73@@ -397,12 +397,12 @@ def read_rhel8oval_file(f):
74 file for processing.
75 '''
76 if not os.path.isfile(f):
77- print("'%s' not a file" % f, file=sys.stderr)
78+ print(f"'{f}' not a file", file=sys.stderr)
79 sys.exit(1)
80
81 name = os.path.abspath(f + ".json")
82 if os.path.exists(name):
83- print("'%s' already exists" % name, file=sys.stderr)
84+ print(f"'{name}' already exists", file=sys.stderr)
85 sys.exit(1)
86
87 parser = xml.sax.make_parser()
88@@ -425,12 +425,12 @@ def read_locate_cves_output(f):
89 file for processing.
90 '''
91 if not os.path.isfile(f):
92- print("'%s' not a file" % f, file=sys.stderr)
93+ print(f"'{f}' not a file", file=sys.stderr)
94 sys.exit(1)
95
96 name = os.path.abspath(f + ".json")
97 if os.path.exists(name):
98- print("'%s' already exists" % name, file=sys.stderr)
99+ print(f"'{name}' already exists", file=sys.stderr)
100 sys.exit(1)
101
102 with open(f) as _f:
103@@ -449,15 +449,15 @@ def read_locate_cves_output(f):
104 if line.startswith("Couldn't find CVE"):
105 cve = line.split()[2]
106 if not cve_lib.CVE_RE.match(cve):
107- print("Skipping malformed CVE: '%s' from '%s'" % (cve, f), file=sys.stderr)
108+ print(f"Skipping malformed CVE: '{cve}' from '{f}'", file=sys.stderr)
109 cve = None
110 elif cve in cves:
111 if args.verbose:
112- print("Skipping duplicate '%s' from '%s'" % (cve, f), file=sys.stderr)
113+ print(f"Skipping duplicate '{cve}' from '{f}'", file=sys.stderr)
114 cve = None
115 else:
116 if args.verbose:
117- print("Adding '%s'" % cve, file=sys.stderr)
118+ print(f"Adding '{cve}'", file=sys.stderr)
119 cves[cve] = dict()
120 continue
121
122@@ -469,7 +469,7 @@ def read_locate_cves_output(f):
123 date = " ".join(line.split(": ")[1].strip().split()[0:5])
124 cves[cve]['date'] = datetime.strptime(date, "%a, %d %b %Y %H:%M:%S")
125 except Exception:
126- print("Could not process date '%s', skipping %s from '%s'" % (line, cve, f), file=sys.stderr)
127+ print(f"Could not process date '{line}', skipping {cve} from '{f}'", file=sys.stderr)
128 del cves[cve]
129 cve = None
130 continue
131@@ -491,11 +491,10 @@ def read_locate_cves_output(f):
132 # NOTE: while we can determine the url for the year/month/day, we
133 # cannot determine the specific message on that day. This gets us
134 # close though, so use it.
135- url = "http://www.openwall.com/lists/oss-security/%s" % (cves[cve]['date'].strftime("%Y/%m/%d"))
136+ url = "http://www.openwall.com/lists/oss-security/" + cves[cve]['date'].strftime('%Y/%m/%d')
137 cves[cve].setdefault('refs', [] + [url])
138
139- nvd = convert_to_nvd(cves, lambda c: '''ML-Date: %s, ML-Subject: %s''' %
140- (cves[c]['date'], escape(cves[c]['subject'])))
141+ nvd = convert_to_nvd(cves, lambda c: f'''ML-Date: {cves[c]['date']}, ML-Subject: {escape(cves[c]['subject'])}''')
142
143 tmp = tempfile.NamedTemporaryFile(mode='w', prefix='locate-cves-import_', suffix='.json', delete=False)
144 tmp.file.write(json.dumps(nvd))
145@@ -510,7 +509,7 @@ def read_mbox_file(f):
146 And process through read_locate_cves_output()
147 '''
148 if not os.path.isfile(f) and not os.path.isdir(f):
149- print("'%s' not a file" % f, file=sys.stderr)
150+ print(f"'{f}' not a file", file=sys.stderr)
151 sys.exit(1)
152
153 child = subprocess.Popen(['./scripts/locate_cves.py', f], stdout=subprocess.PIPE, universal_newlines=True)
154@@ -602,17 +601,23 @@ class CVEHandler(xml.sax.handler.ContentHandler):
155 timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
156
157 # Append to timestamp file list
158- with open('%s/check-cves.log' % (destdir), 'a') as f:
159- f.write('%s UTC - %s added, %s ignored, %s skipped, %s total - files: %s\n' %
160- (timestamp, self.num_added, self.num_ignored, self.num_skipped, self.num_added + self.num_ignored, [os.path.basename(x) for x in args.uris]))
161+ with open(f'{destdir}/check-cves.log', 'a') as f:
162+ f.write(
163+ f"{timestamp} UTC - "
164+ f"{self.num_added} added, "
165+ f"{self.num_ignored} ignored, "
166+ f"{self.num_skipped} skipped, "
167+ f"{self.num_added + self.num_ignored} total - "
168+ f"files: {[os.path.basename(x) for x in args.uris]}\n"
169+ )
170
171 def printReport(self):
172 print('\n============================ Triage summary =============================')
173- print("\n %4d CVEs added" % self.num_added)
174- print(" %4d CVEs ignored" % self.num_ignored)
175- print(" %4d CVEs skipped" % self.num_skipped)
176+ print(f"\n {self.num_added: 4d} CVEs added")
177+ print(f" {self.num_ignored: 4d} CVEs ignored")
178+ print(f" {self.num_skipped: 4d} CVEs skipped")
179 print("---------------------------")
180- print("%5d total CVEs triaged" % (self.num_added + self.num_ignored))
181+ print(f"{self.num_added + self.num_ignored: 5d} total CVEs triaged")
182 updates_detected, updates_details = self.detect_updates_to_external_repositories()
183 if updates_detected:
184 print('\n====================== External updates detected ========================')
185@@ -636,7 +641,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
186 if process.returncode == 0 and process.stdout:
187 if process.stdout:
188 updates_detected = True
189- updates_details += "\n %s \n %s" % (repository_dir, process.stdout)
190+ updates_details += f"\n {repository_dir} \n {process.stdout}"
191 except subprocess.CalledProcessError as exception:
192 print(exception)
193 updates_detected = False
194@@ -657,11 +662,11 @@ class CVEHandler(xml.sax.handler.ContentHandler):
195 "data_version": "4.0"}
196 for key in list(template_cve.keys()):
197 if key not in cve or cve[key] != template_cve[key]:
198- raise KeyError("NVD JSON in '%s' seems invalid" % fp.name)
199+ raise KeyError(f"NVD JSON in '{fp.name}' seems invalid")
200
201 metadata = cve["CVE_data_meta"]
202 if not re.match(r'^CVE-\d{4}-\d{4,}$', metadata["ID"]):
203- print("Ignoring invalid CVE with ID '%s'" % metadata["ID"])
204+ print(f"Ignoring invalid CVE with ID '{metadata['ID']}'")
205 return
206 self.curr_cve = metadata["ID"]
207
208@@ -693,7 +698,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
209 # check for expected fields
210 for key in list(template_nvd.keys()):
211 if key not in record or record[key] != template_nvd[key]:
212- raise KeyError("NVD JSON in '%s' seems invalid - missing key '%s'" % (fp.name, key))
213+ raise KeyError(f"NVD JSON in '{fp.name}' seems invalid - missing key '{key}'")
214 for item in record["CVE_Items"]:
215 self.curr_cvss = []
216 self.curr_refs = []
217@@ -787,7 +792,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
218 return
219
220 if self.curr_cve in self.cve_seen:
221- print("Skipping repeat: %s" % (self.curr_cve), file=sys.stderr)
222+ print(f"Skipping repeat: {self.curr_cve}", file=sys.stderr)
223 return
224 self.cve_seen.add(self.curr_cve)
225
226@@ -802,18 +807,20 @@ class CVEHandler(xml.sax.handler.ContentHandler):
227 return self.cve_list
228
229 def display_command_file_usage(self, f, line_prefix=''):
230- f.write('%sThe following commands can be used in this file:\n' % (line_prefix))
231- f.write('%s\n' % (line_prefix))
232- f.write('%s* Add a new CVE to the tracker:\n' % (line_prefix))
233- f.write('%s <CVE> add <PRIORITY> <PACKAGE> [PACKAGE] ...\n' % (line_prefix))
234- f.write('%s* Add a new CVE to the tracker and open it in your editor:\n' % (line_prefix))
235- f.write('%s <CVE> edit <PRIORITY> <PACKAGE> [PACKAGE] ...\n' % (line_prefix))
236- f.write('%s* Unembargo a CVE that is now public:\n' % (line_prefix))
237- f.write('%s <CVE> unembargo>\n' % (line_prefix))
238- f.write('%s* Permanently ignore a CVE:\n' % (line_prefix))
239- f.write('%s <CVE> ignore <REASON>\n' % (line_prefix))
240- f.write('%s* Temporarily skip over a CVE:\n' % (line_prefix))
241- f.write('%s <CVE> skip\n\n' % (line_prefix))
242+ # fmt: off
243+ f.write(f'{line_prefix}The following commands can be used in this file:\n')
244+ f.write(f'{line_prefix}\n')
245+ f.write(f'{line_prefix}* Add a new CVE to the tracker:\n')
246+ f.write(f'{line_prefix} <CVE> add <PRIORITY> <PACKAGE> [PACKAGE] ...\n')
247+ f.write(f'{line_prefix}* Add a new CVE to the tracker and open it in your editor:\n')
248+ f.write(f'{line_prefix} <CVE> edit <PRIORITY> <PACKAGE> [PACKAGE] ...\n')
249+ f.write(f'{line_prefix}* Unembargo a CVE that is now public:\n')
250+ f.write(f'{line_prefix} <CVE> unembargo>\n')
251+ f.write(f'{line_prefix}* Permanently ignore a CVE:\n')
252+ f.write(f'{line_prefix} <CVE> ignore <REASON>\n')
253+ f.write(f'{line_prefix}* Temporarily skip over a CVE:\n')
254+ f.write(f'{line_prefix} <CVE> skip\n\n')
255+ # fmt: on
256 f.flush()
257
258 def find_hint_in_external_subprojects(self, software_hints_from_cve_description):
259@@ -861,24 +868,24 @@ class CVEHandler(xml.sax.handler.ContentHandler):
260 print('=================================end details==================================')
261 # Display CVE information
262 if self.cve_data[cve]['public']:
263- print(' Published: %s' % (self.cve_data[cve]['public']))
264+ print(f" Published: {self.cve_data[cve]['public']}")
265 for ref in self.cve_data[cve]['refs']:
266- print(' %s: %s' % (ref[0], ref[1]), end='')
267+ print(f' {ref[0]}: {ref[1]}', end='')
268 # Do not repeat URL if it matches the contents of the reference
269 if ref[2] and ref[1].strip() != ref[2].strip():
270- print(' %s' % (ref[2]), end='')
271+ print(f' {ref[2]}', end='')
272 print()
273 if wrap_desc:
274- print('%s' % _wrap_desc(self.cve_data[cve]['desc']))
275+ print(_wrap_desc(self.cve_data[cve]['desc']))
276 else:
277 print('\n======================== CVE details ==========================')
278- print(' %s' % cve)
279- print(' %s' % (self.cve_data[cve]['desc']))
280+ print(f' {cve}')
281+ print(f" {self.cve_data[cve]['desc']}")
282 for cvss in self.cve_data[cve]['cvss']:
283- print(' CVSS (%s): %s [%.1f]' % (cvss['source'], cvss['vector'], cvss['baseScore']))
284+ print(f" CVSS ({cvss['source']}): {cvss['vector']} [{cvss['baseScore']: .1f}]")
285 if self.debian and cve in self.debian:
286 print('\n======================= Debian details ========================')
287- print(' Debian CVE Tracker: %s' % (self.debian[cve]['state']))
288+ print(f" Debian CVE Tracker: {self.debian[cve]['state']}")
289 if len(self.debian[cve]['note']):
290 print("\t" + "\n\t".join(self.debian[cve]['note']))
291 for pkg in self.debian[cve]['pkgs']:
292@@ -889,23 +896,23 @@ class CVEHandler(xml.sax.handler.ContentHandler):
293 info.append(self.debian[cve]['pkgs'][pkg]['bug'])
294 if self.debian[cve]['pkgs'][pkg]['note']:
295 info.append(self.debian[cve]['pkgs'][pkg]['note'])
296- print(" Debian: %s: %s (%s)" % (pkg, self.debian[cve]['pkgs'][pkg]['state'], "; ".join(info)))
297+ print(f" Debian: {pkg}: {self.debian[cve]['pkgs'][pkg]['state']} ({'; '.join(info)})")
298 # Display version and component details for Ubuntu's pkg
299 answer = source_map.madison(source, pkg)
300 for name in sorted(answer.keys()):
301 for pkg in sorted(answer[name].keys()):
302- print(' Ubuntu: %s | %s | %s' % (pkg, answer[name][pkg], name))
303+ print(f' Ubuntu: {pkg} | {answer[name][pkg]} | {name}')
304 # no debian info, display possible commented ignore command when
305 # using command file (i.e. wrap_desc is true)
306 if (self.debian[cve]['state'] == 'RESERVED' or self.debian[cve]['state'] == None) and wrap_desc:
307 proposed_ignore = self.ignore_suggestion.get_ignore_suggestion(self.cve_data[cve]['desc'])
308- print('%s ignore "%s"' % (cve, proposed_ignore))
309+ print(f'{cve} ignore "{proposed_ignore}"')
310 # debian rejected, so offer to reject by ignoring when using command file (i.e. wrap_desc is true)
311 if (self.debian[cve]['state'] == 'REJECTED' and wrap_desc):
312- print('%s ignore "%s"' % (cve, "REJECTED"))
313+ print(f'{cve} ignore "REJECTED"')
314 else:
315 proposed_ignore = self.ignore_suggestion.get_ignore_suggestion(self.cve_data[cve]['desc'])
316- print('%s ignore %s' % (cve, proposed_ignore))
317+ print(f'{cve} ignore {proposed_ignore}')
318
319 software_hints_from_cve_desc = self.get_software_hints_from_cve_description(self.cve_data[cve]["desc"])
320 if software_hints_from_cve_desc:
321@@ -953,7 +960,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
322 if self.debian[cve]['pkgs'][pkg]['state'] == '<itp>':
323 # software has not been admitted into debian
324 action = 'ignore'
325- reason = '%s: <itp> (dbug %s)' % (pkg, self.debian[cve]['pkgs'][pkg]['bug'])
326+ reason = f"{pkg}: <itp> (dbug {self.debian[cve]['pkgs'][pkg]['bug']})"
327 if self.debian[cve]['state'] == 'REJECTED':
328 action = 'ignore'
329 reason = 'REJECTED'
330@@ -1003,7 +1010,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
331 def human_process_cve(self, cve, action='skip', reason='', package=''):
332 info = ''
333 while info == "" or not info[0] in ['i', 'a', 's', 'q', 'r']:
334- prompt_user('\nA]dd (or R]epeat), I]gnore forever, S]kip for now, or Q]uit? [%s] ' % (action))
335+ prompt_user(f'\nA]dd (or R]epeat), I]gnore forever, S]kip for now, or Q]uit? [{action}] ')
336 info = sys.stdin.readline().strip().lower()
337 if info == "":
338 info = action
339@@ -1023,7 +1030,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
340 if package == "":
341 package = self.saved_package
342 if package != "":
343- prompt_user('[%s] ' % (package))
344+ prompt_user(f'[{package}] ')
345 info = sys.stdin.readline().strip()
346 if info == '':
347 info = package
348@@ -1037,19 +1044,19 @@ class CVEHandler(xml.sax.handler.ContentHandler):
349 self.saved_cve = cve
350
351 print('\n===================== Dependant packages ======================')
352- print(' Detecting packages built using: %s...' % info, end='')
353+ print(f' Detecting packages built using: {info}...', end='')
354 sys.stdout.flush()
355 built_using = ""
356 try:
357 built_using = get_built_using(info)
358 except Exception as e:
359- print("ERROR: %s" % e, file=sys.stderr)
360+ print(f"ERROR: {e}", file=sys.stderr)
361 pass # for now just show the error but don't break triage
362
363 if built_using != "":
364 print("found:\n")
365- print("%s" % source_map.get_built_using_header())
366- print("%s" % built_using)
367+ print(source_map.get_built_using_header())
368+ print(built_using)
369 print("IMPORTANT: the above packages are candidates for rebuilds when fixes are applied to:")
370 print(" %s" % "\n ".join(info))
371 else:
372@@ -1071,7 +1078,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
373 prompts.append(choice)
374
375 for i in range(0, len(prompts)):
376- print(' %s) %s' % (chr(97 + i), prompts[i]))
377+ print(f" {chr(97 + i)}) {prompts[i]}")
378 prompt_user(' > ')
379
380 info = sys.stdin.readline().strip()
381@@ -1113,13 +1120,13 @@ class CVEHandler(xml.sax.handler.ContentHandler):
382 try:
383 (cve, action) = (args[0].upper(), args[1].lower())
384 except IndexError:
385- raise ValueError('Invalid formatting on line %d:\n%s' % (line_num, orig_line))
386+ raise ValueError(f'Invalid formatting on line {line_num}:\n{orig_line}')
387
388 if not cve.startswith('CVE-'):
389 # The first arg should look like a CVE ID
390- raise ValueError('Invalid CVE ID formatting (%s) on line %d:\n%s' % (cve, line_num, orig_line))
391+ raise ValueError(f'Invalid CVE ID formatting ({cve}) on line {line_num}:\n{orig_line}')
392 elif cve in cves:
393- raise ValueError('Performing multiple operations on the same CVE (%s) is not supported (line %d):\n%s' % (cve, line_num, orig_line))
394+ raise ValueError(f'Performing multiple operations on the same CVE ({cve}) is not supported (line {line_num}):\n{orig_line}')
395 cves.append(cve)
396
397 if action == 'add' or action == 'edit':
398@@ -1130,13 +1137,13 @@ class CVEHandler(xml.sax.handler.ContentHandler):
399 priority = args[0].lower()
400 packages = args[1:]
401 except IndexError:
402- raise ValueError('Invalid add command on line %d:\n%s' % (line_num, orig_line))
403+ raise ValueError(f'Invalid add command on line {line_num}:\n{orig_line}')
404
405 if not priority in cve_lib.priorities and not priority == 'untriaged':
406- raise ValueError('Invalid priority on line %d:\n%s' % (line_num, orig_line))
407+ raise ValueError(f'Invalid priority on line {line_num}:\n{orig_line}')
408
409- if os.path.exists('%s/active/%s' % (destdir, cve)):
410- raise ValueError('Updating an existing CVE is not supported (line %d):\n%s' % (line_num, orig_line))
411+ if os.path.exists(f'{destdir}/active/{cve}'):
412+ raise ValueError(f'Updating an existing CVE is not supported (line {line_num}):\n{orig_line}')
413
414 if preprocess:
415 continue
416@@ -1150,10 +1157,10 @@ class CVEHandler(xml.sax.handler.ContentHandler):
417 _spawn_editor(cve_path)
418 elif action == 'unembargo':
419 if cve not in EmbargoList:
420- raise ValueError('CVE %s is not in the embargo database (line %d):\n%s' % (cve, line_num, orig_line))
421+ raise ValueError(f'CVE {cve} is not in the embargo database (line {line_num}):\n{orig_line}')
422
423 if os.path.exists(os.path.join('active', cve)):
424- raise ValueError('Cannot unembargo %s because it already exists in the active directory (line %d):\n%s' % (cve, line_num, orig_line))
425+ raise ValueError(f'Cannot unembargo {cve} because it already exists in the active directory (line {line_num}):\n{orig_line}')
426
427 if preprocess:
428 continue
429@@ -1164,7 +1171,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
430 try:
431 reason = args[2]
432 except IndexError:
433- raise ValueError('Invalid ignore command on line %d:\n%s' % (line_num, orig_line))
434+ raise ValueError(f'Invalid ignore command on line {line_num}:\n{orig_line}')
435
436 if preprocess:
437 continue
438@@ -1173,7 +1180,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
439 elif action == 'skip':
440 # If the CVE should be skipped, no arguments are allowed
441 if len(args) > 2:
442- raise ValueError('Invalid skip command on line %d:\n%s' % (line_num, orig_line))
443+ raise ValueError(f'Invalid skip command on line {line_num}:\n{orig_line}')
444
445 if preprocess:
446 continue
447@@ -1181,7 +1188,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
448 self.skip_cve()
449 else:
450 # The second arg must be a known action
451- raise ValueError('Unknown action (%s) on line %d:\n%s' % (action, line_num, orig_line))
452+ raise ValueError(f'Unknown action ({action}) on line {line_num}:\n{orig_line}')
453
454 def preprocess_cve(self, cve):
455 desc = ''
456@@ -1195,20 +1202,20 @@ class CVEHandler(xml.sax.handler.ContentHandler):
457 desc += '# =================================end details==================================\n'
458 # Display CVE information
459 if self.cve_data[cve]['public']:
460- desc += '# Published: %s\n' % (self.cve_data[cve]['public'])
461+ desc += f'# Published: {self.cve_data[cve]["public"]}\n'
462 for ref in self.cve_data[cve]['refs']:
463- desc += '# %s: %s' % (ref[0], ref[1])
464+ desc += f'# {ref[0]}: {ref[1]}'
465 # Do not repeat URL if it matches the contents of the reference
466 if ref[2] and ref[1].strip() != ref[2].strip():
467- desc += ' %s' % (ref[2])
468+ desc += f' {ref[2]}'
469 desc += '\n'
470 for line in _wrap_desc(self.cve_data[cve]['desc']).split('\n'):
471- desc += '# %s\n' % line
472+ desc += f'# {line}\n'
473 if self.debian and cve in self.debian:
474- desc += '# Debian CVE Tracker: %s\n' % (self.debian[cve]['state'])
475+ desc += f"# Debian CVE Tracker: {self.debian[cve]['state']}\n"
476 if len(self.debian[cve]['note']):
477 for note in self.debian[cve]['note']:
478- desc += '# \t%s\n' % note
479+ desc += f'# \t{note}\n'
480 for pkg in self.debian[cve]['pkgs']:
481 info = []
482 if self.debian[cve]['pkgs'][pkg]['priority']:
483@@ -1222,7 +1229,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
484 answer = source_map.madison(source, pkg)
485 for name in sorted(answer.keys()):
486 for pkg in sorted(answer[name].keys()):
487- desc += '# Ubuntu: %s | %s | %s\n' % (pkg, answer[name][pkg], name)
488+ desc += f'# Ubuntu: {pkg} | {answer[name][pkg]} | {name}\n'
489
490 action = 'skip'
491 data = ""
492@@ -1240,13 +1247,13 @@ class CVEHandler(xml.sax.handler.ContentHandler):
493 action = 'add'
494 data = " ".join(self.debian[cve]['pkgs'])
495
496- print('%s %s %s\n%s' % (action, cve, data, desc))
497+ print(f'{action} {cve} {data}\n{desc}')
498
499 def add_cve(self, cve, packages, priority=None):
500 # remove from not-for-us.txt if adding and ensure we remove any
501 # mistriaged_hint from the description
502 if cve in CVEIgnoreNotForUsSet:
503- cmd = ['sed', '-i', '/^%s #.*$/d' % cve, './ignored/not-for-us.txt']
504+ cmd = ['sed', '-i', f'/^{cve} #.*$/d', './ignored/not-for-us.txt']
505 subprocess.call(cmd)
506 self.cve_data[cve]['desc'] = self.cve_data[cve]['desc'].replace(mistriaged_hint, '')
507
508@@ -1294,7 +1301,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
509 elif self.debian[cve]['pkgs'][pkg]['bug']:
510 bug = self.debian[cve]['pkgs'][pkg]['bug']
511 if bug:
512- url = "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s" % bug
513+ url = "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=" + bug
514 if url not in bug_urls:
515 bug_urls.append(url)
516
517@@ -1330,7 +1337,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
518 self.debian[cve]['pkgs'][pkg]['state']:
519 if re.search(r'^[0-9]', self.debian[cve]['pkgs'][pkg]['state']):
520 fixed_version = self.debian[cve]['pkgs'][pkg]['state']
521- fixed_in = ",%s" % fixed_version
522+ fixed_in = f",{fixed_version}"
523
524 # Now see if we can correlate this to an Ubuntu version
525 answer = source_map.madison(source, pkg)
526@@ -1344,20 +1351,20 @@ class CVEHandler(xml.sax.handler.ContentHandler):
527 if dpkg_compare_versions(version, 'ge', fixed_version):
528 if rel == cve_lib.devel_release:
529 rel = 'devel'
530- fixed_in += ",%s,%s" % (rel, version)
531+ fixed_in += f",{rel},{version}"
532 break
533 elif self.debian[cve]['pkgs'][pkg]['state'].startswith('<not-affected>') and \
534 len(self.debian[cve]['pkgs'][pkg]['priority']) > 0:
535 # capture that debian believes their version is unaffected
536- not_affected.append((pkg, "debian: %s" % self.debian[cve]['pkgs'][pkg]['priority']))
537- cmd += ['-p', "%s%s" % (pkg, fixed_in)]
538+ not_affected.append(pkg, f"debian: {self.debian[cve]['pkgs'][pkg]['priority']}")
539+ cmd += ['-p', f"{pkg}{fixed_in}"]
540
541 subprocess.call(cmd)
542 for (pkg, reason) in not_affected:
543 cmd = ['./scripts/mass-cve-edit', '-p', pkg, '-r', 'upstream', '-s', 'not-affected', '-v', reason, cve]
544 subprocess.call(cmd)
545 self.num_added += 1
546- return './active/%s' % cve
547+ return f'./active/{cve}'
548
549 def unembargo_cve(self, cve):
550 # unembargo a cve now public
551@@ -1368,8 +1375,8 @@ class CVEHandler(xml.sax.handler.ContentHandler):
552 # Append to ignore list unless is already in CVEIgnoreList and then
553 # append to the ignored/ignore-mistriaged.txt
554 txtfile = 'ignore-mistriaged.txt' if cve in CVEIgnoreNotForUsSet else 'not-for-us.txt'
555- with open('%s/ignored/%s' % (destdir, txtfile), 'a') as f:
556- f.write('%s # %s\n' % (cve, reason))
557+ with open(f'{destdir}/ignored/{txtfile}', 'a') as f:
558+ f.write(f'{cve} # {reason}\n')
559
560 self.num_ignored += 1
561
562@@ -1428,7 +1435,7 @@ if args.cve:
563 continue
564 # error out if is ignored
565 if cve in CVEIgnoreList:
566- print("%s already exists in UCT - please remove it then retriage." % cve)
567+ print(f"{cve} already exists in UCT - please remove it then retriage.")
568 sys.exit(1)
569 specific_cves.add(cve)
570
571@@ -1453,7 +1460,7 @@ if (args.import_missing_debian or args.mistriaged) and handler.debian is not Non
572
573
574 for uri in args.uris:
575- print('Loading %s ...' % (uri), file=sys.stderr)
576+ print(f'Loading {uri} ...', file=sys.stderr)
577 if '://' in uri:
578 readable = urllib.request.urlopen(uri)
579 else:
580@@ -1464,7 +1471,7 @@ for uri in args.uris:
581 else:
582 parser.parse(readable)
583 except xml.sax._exceptions.SAXParseException as e:
584- print("\n\nWARNING: %s is malformed:\n%s" % (uri, e))
585+ print(f"\n\nWARNING: {uri} is malformed:\n{e}")
586 print("Aborting", file=sys.stderr)
587 sys.exit(1)
588 print('')
589@@ -1490,17 +1497,17 @@ def refresh_cves(cve_refresh_list, full_refresh=True):
590 cvsss = handler.cve_data[cve]['cvss']
591 except:
592 if args.verbose:
593- print('%s not listed in XML' % (cve), file=sys.stderr)
594+ print(f'{cve} not listed in XML', file=sys.stderr)
595
596 # Find the on-disk CVE file
597 cvefile = ""
598 for status in ['active', 'retired', 'ignored']:
599- check = '%s/%s/%s' % (destdir, status, cve)
600+ check = f'{destdir}/{status}/{cve}'
601 if os.path.exists(check):
602 cvefile = check
603 break
604 if cvefile == "":
605- print('local dirs missing %s?!' % (cve), file=sys.stderr)
606+ print(f'local dirs missing {cve}?!', file=sys.stderr)
607 continue
608
609 # Load CVE
610@@ -1524,14 +1531,14 @@ def refresh_cves(cve_refresh_list, full_refresh=True):
611 if data['Description'].strip() != desc:
612 cve_lib.update_multiline_field(cvefile, 'Description', desc)
613 updated = True
614- debug("updated description for %s" % (cvefile))
615+ debug(f"updated description for {cvefile}")
616
617 # Update Publication Date if it needs it
618 if public:
619 if 'PublicDate' not in data or ('PublicDate' in data and data['PublicDate'] != public):
620 cve_lib.update_field(cvefile, 'PublicDate', public)
621 updated = True
622- debug("updated pubdate for %s" % (cvefile))
623+ debug(f"updated pubdate for {cvefile}")
624
625 # Add CVE Reference, if it's missing
626 if 'References' in data and re.match(r'^CVE-\d+-\d+$', cve):
627@@ -1539,19 +1546,19 @@ def refresh_cves(cve_refresh_list, full_refresh=True):
628 if mitre_ref not in data['References']:
629 cve_lib.add_reference(cvefile, mitre_ref)
630 updated = True
631- debug("updated reference for %s" % (cvefile))
632+ debug(f"updated reference for {cvefile}")
633
634 # Update CVSS if needs it
635 for entry in cvsss:
636 try:
637 updated |= cve_lib.add_cvss(cvefile, entry['source'], entry['vector'])
638- debug("updated cvss for %s" % (cvefile))
639+ debug(f"updated cvss for {cvefile}")
640 except KeyError:
641 # we might not have a vector, in this case continue
642 pass
643
644 if updated:
645- print("Refreshed %s" % (cvefile), file=sys.stderr)
646+ print(f"Refreshed {cvefile}", file=sys.stderr)
647
648
649 if args.refresh or args.score_refresh:
650@@ -1608,8 +1615,8 @@ for cve in new_cves:
651
652 if not experimental:
653 print('\n***********************************************************************')
654- print(' %s (%d/%d: %d%%)' % (cve, count, total, (count * 100 / total)))
655- print(' https://cve.mitre.org/cgi-bin/cvename.cgi?name=%s' % (cve))
656+ print(f" {cve} ({count}/{total}: {int(count * 100 / total)}%)")
657+ print(f" https://cve.mitre.org/cgi-bin/cvename.cgi?name={cve}")
658 print('***********************************************************************')
659 handler.display_cve(cve, file=fout)
660 (action, reason, packages) = handler.get_cve_suggestions(cve)
661@@ -1619,16 +1626,16 @@ for cve in new_cves:
662 else:
663 line_prefix = '# '
664
665- fout.write('%s%s\n#\n' % (line_prefix, cve))
666+ fout.write('{line_prefix}{cve}\n#\n')
667 handler.display_cve(cve, file=fout, line_prefix=line_prefix, wrap_desc=True)
668
669 (action, reason, packages) = handler.get_cve_suggestions(cve)
670- suggestion = '%s %s' % (cve, action)
671+ suggestion = f'{cve} {action}'
672 if reason:
673- suggestion += ' %s' % (reason)
674+ suggestion += f' {reason}'
675 elif action == 'add':
676- suggestion += ' untriaged %s' % (packages)
677- fout.write('%s\n\n' % (suggestion))
678+ suggestion += f' untriaged {packages}'
679+ fout.write(f'{suggestion}\n\n')
680
681 if experimental:
682 fout.flush()
683@@ -1636,7 +1643,7 @@ if experimental:
684 assert((total == 0 and count == 0) or (total > 0 and count >= 0))
685 # no need to spawn editor if no CVEs listed
686 if count > 0:
687- prompt_user('Asking user to handle %d CVEs...' % count)
688+ prompt_user(f'Asking user to handle {count} CVEs...')
689 _spawn_editor(fout.name)
690 else:
691 prompt_user('Not spawning editor as no CVEs to process')
692@@ -1645,8 +1652,7 @@ if experimental:
693 handler.process_command_file(fout, preprocess=True)
694 break
695 except Exception as e:
696- print('Error encountered while processing the command file!', file=sys.stderr)
697- print('%s' % e, file=sys.stderr)
698+ print(f'Error encountered while processing the command file!\n{e}', file=sys.stderr)
699 print('Enter "quit" to lose all work or anything else to re-edit and try again: ', end='', file=sys.stderr)
700 sys.stderr.flush()
701 response = sys.stdin.readline().strip().lower()

Subscribers

People subscribed via source and target branches