Merge ~eslerm/ubuntu-cve-tracker:check-cves-f-strings into ubuntu-cve-tracker:master
- Git
- lp:~eslerm/ubuntu-cve-tracker
- check-cves-f-strings
- Merge into master
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) |
Related bugs: |
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:/
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.
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(
> if dpkg_compare_
> if rel == cve_lib.
> rel = 'devel'
> - fixed_in += ",%s,%s" % (rel, version)
> + fixed_in += f",{rel},{version}"
> break
> elif self.debian[
> len(self.
> # capture that debian believes their version is unaffected
> - not_affected.
> - cmd += ['-p', "%s%s" % (pkg, fixed_in)]
> + not_affected.
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:/
and have merged your changes with it to master.
Thanks!
--
Steve Beattie
<email address hidden>
Marc Deslauriers (mdeslaur) wrote : | # |
Oh, nice catch, I didn't notice that one.
Mark Esler (eslerm) wrote : | # |
Thank you for the thorough review and merge!
Preview Diff
1 | diff --git a/scripts/check-cves b/scripts/check-cves |
2 | index 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() |
These changes LGTM. Thanks for breaking down all your refactoring into reviewable changes!