Merge ~jugmac00/launchpad:allow_limiting_uct_imports into launchpad:master
- Git
- lp:~jugmac00/launchpad
- allow_limiting_uct_imports
- Merge into master
Proposed by
Jürgen Gmach
Status: | Merged |
---|---|
Approved by: | Jürgen Gmach |
Approved revision: | 9ba7fdfdea57839dc0b4fdbd4f5e3c2524a11356 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~jugmac00/launchpad:allow_limiting_uct_imports |
Merge into: | launchpad:master |
Diff against target: |
346 lines (+256/-53) 5 files modified
lib/lp/bugs/scripts/tests/sampledata/CVE-2007-0255 (+61/-0) lib/lp/bugs/scripts/tests/sampledata/CVE-2022-3219 (+43/-0) lib/lp/bugs/scripts/tests/test_uctimport.py (+88/-0) lib/lp/bugs/scripts/uctimport.py (+63/-0) scripts/uct-import.py (+1/-53) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Review via email: mp+436146@code.launchpad.net |
Commit message
Enable filtering for UCTImports
Description of the change
To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) wrote : | # |
Revision history for this message
Colin Watson (cjwatson) : | # |
review:
Approve
Revision history for this message
Colin Watson (cjwatson) wrote : | # |
Could you fix the commit message of this MP, since that will be used by the merge bot when landing this?
Revision history for this message
Jürgen Gmach (jugmac00) wrote : | # |
Thanks for the review!
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/bugs/scripts/tests/sampledata/CVE-2007-0255 b/lib/lp/bugs/scripts/tests/sampledata/CVE-2007-0255 | |||
2 | 0 | new file mode 100644 | 0 | new file mode 100644 |
3 | index 0000000..db2403d | |||
4 | --- /dev/null | |||
5 | +++ b/lib/lp/bugs/scripts/tests/sampledata/CVE-2007-0255 | |||
6 | @@ -0,0 +1,61 @@ | |||
7 | 1 | PublicDate: 2007-01-16 23:28:00 UTC | ||
8 | 2 | Candidate: CVE-2007-0255 | ||
9 | 3 | References: | ||
10 | 4 | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-0255 | ||
11 | 5 | http://xine.sourceforge.net/security | ||
12 | 6 | Description: | ||
13 | 7 | XINE 0.99.4 allows user-assisted remote attackers to cause a denial of | ||
14 | 8 | service (application crash) and possibly execute arbitrary code via a | ||
15 | 9 | certain M3U file that contains a long #EXTINF line and contains format | ||
16 | 10 | string specifiers in an invalid udp:// URI, possibly a variant of | ||
17 | 11 | CVE-2007-0017. | ||
18 | 12 | Ubuntu-Description: | ||
19 | 13 | Notes: | ||
20 | 14 | sbeattie> issue is unlisted on xine upstream website | ||
21 | 15 | Priority: medium | ||
22 | 16 | Bugs: | ||
23 | 17 | Discovered-by: | ||
24 | 18 | Assigned-to: | ||
25 | 19 | CVSS: | ||
26 | 20 | |||
27 | 21 | Patches_xine-ui: | ||
28 | 22 | upstream_xine-ui: needs-triage | ||
29 | 23 | dapper_xine-ui: ignored (reached end-of-life) | ||
30 | 24 | edgy_xine-ui: needed (reached end-of-life) | ||
31 | 25 | feisty_xine-ui: needed (reached end-of-life) | ||
32 | 26 | gutsy_xine-ui: needed (reached end-of-life) | ||
33 | 27 | hardy_xine-ui: ignored (reached end-of-life) | ||
34 | 28 | intrepid_xine-ui: needed (reached end-of-life) | ||
35 | 29 | jaunty_xine-ui: ignored (reached end-of-life) | ||
36 | 30 | karmic_xine-ui: ignored (reached end-of-life) | ||
37 | 31 | lucid_xine-ui: ignored (reached end-of-life) | ||
38 | 32 | maverick_xine-ui: ignored (reached end-of-life) | ||
39 | 33 | natty_xine-ui: ignored (reached end-of-life) | ||
40 | 34 | oneiric_xine-ui: ignored (reached end-of-life) | ||
41 | 35 | precise_xine-ui: ignored (reached end-of-life) | ||
42 | 36 | precise/esm_xine-ui: DNE (precise was needed) | ||
43 | 37 | quantal_xine-ui: ignored (reached end-of-life) | ||
44 | 38 | raring_xine-ui: ignored (reached end-of-life) | ||
45 | 39 | saucy_xine-ui: ignored (reached end-of-life) | ||
46 | 40 | trusty_xine-ui: ignored (reached end-of-life) | ||
47 | 41 | trusty/esm_xine-ui: DNE (trusty was needed) | ||
48 | 42 | utopic_xine-ui: ignored (reached end-of-life) | ||
49 | 43 | vivid_xine-ui: ignored (reached end-of-life) | ||
50 | 44 | vivid/stable-phone-overlay_xine-ui: DNE | ||
51 | 45 | vivid/ubuntu-core_xine-ui: DNE | ||
52 | 46 | wily_xine-ui: ignored (reached end-of-life) | ||
53 | 47 | xenial_xine-ui: ignored (end of standard support, was needed) | ||
54 | 48 | yakkety_xine-ui: ignored (reached end-of-life) | ||
55 | 49 | zesty_xine-ui: ignored (reached end-of-life) | ||
56 | 50 | artful_xine-ui: ignored (reached end-of-life) | ||
57 | 51 | bionic_xine-ui: needed | ||
58 | 52 | cosmic_xine-ui: ignored (reached end-of-life) | ||
59 | 53 | disco_xine-ui: ignored (reached end-of-life) | ||
60 | 54 | eoan_xine-ui: ignored (reached end-of-life) | ||
61 | 55 | focal_xine-ui: needed | ||
62 | 56 | groovy_xine-ui: ignored (reached end-of-life) | ||
63 | 57 | hirsute_xine-ui: ignored (reached end-of-life) | ||
64 | 58 | impish_xine-ui: ignored (reached end-of-life) | ||
65 | 59 | jammy_xine-ui: needed | ||
66 | 60 | kinetic_xine-ui: needed | ||
67 | 61 | devel_xine-ui: needed | ||
68 | 0 | \ No newline at end of file | 62 | \ No newline at end of file |
69 | diff --git a/lib/lp/bugs/scripts/tests/sampledata/CVE-2022-3219 b/lib/lp/bugs/scripts/tests/sampledata/CVE-2022-3219 | |||
70 | 1 | new file mode 100644 | 63 | new file mode 100644 |
71 | index 0000000..14aaa73 | |||
72 | --- /dev/null | |||
73 | +++ b/lib/lp/bugs/scripts/tests/sampledata/CVE-2022-3219 | |||
74 | @@ -0,0 +1,43 @@ | |||
75 | 1 | Candidate: CVE-2022-3219 | ||
76 | 2 | PublicDate: 2022-09-28 | ||
77 | 3 | References: | ||
78 | 4 | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-3219 | ||
79 | 5 | https://access.redhat.com/security/cve/CVE-2022-3219 | ||
80 | 6 | https://marc.info/?l=oss-security&m=165696590211434&w=4 | ||
81 | 7 | Description: | ||
82 | 8 | gnupg: denial of service issue (resource consumption) using compressed | ||
83 | 9 | packets | ||
84 | 10 | Ubuntu-Description: | ||
85 | 11 | Notes: | ||
86 | 12 | mdeslaur> per the upstream gnupg bug, the change will not be applied | ||
87 | 13 | mdeslaur> as of 2022-09-28, proposed patch has not been accepted by | ||
88 | 14 | mdeslaur> upstream developers | ||
89 | 15 | Mitigation: | ||
90 | 16 | Bugs: | ||
91 | 17 | https://dev.gnupg.org/T5993 | ||
92 | 18 | Priority: low | ||
93 | 19 | Discovered-by: | ||
94 | 20 | Assigned-to: | ||
95 | 21 | CVSS: | ||
96 | 22 | |||
97 | 23 | Patches_gnupg: | ||
98 | 24 | upstream_gnupg: needs-triage | ||
99 | 25 | esm-infra/xenial_gnupg: deferred (2022-09-28) | ||
100 | 26 | trusty_gnupg: ignored (out of standard support) | ||
101 | 27 | xenial_gnupg: ignored (out of standard support) | ||
102 | 28 | bionic_gnupg: DNE | ||
103 | 29 | focal_gnupg: DNE | ||
104 | 30 | jammy_gnupg: DNE | ||
105 | 31 | trusty/esm_gnupg: deferred (2022-09-28) | ||
106 | 32 | |||
107 | 33 | Patches_gnupg2: | ||
108 | 34 | other: https://dev.gnupg.org/D556 | ||
109 | 35 | upstream_gnupg2: needs-triage | ||
110 | 36 | esm-infra/xenial_gnupg2: deferred (2022-09-28) | ||
111 | 37 | trusty_gnupg2: ignored (out of standard support) | ||
112 | 38 | xenial_gnupg2: ignored (end of standard support) | ||
113 | 39 | bionic_gnupg2: deferred (2022-09-28) | ||
114 | 40 | focal_gnupg2: deferred (2022-09-28) | ||
115 | 41 | jammy_gnupg2: deferred (2022-09-28) | ||
116 | 42 | kinetic_gnupg2: deferred (2022-09-28) | ||
117 | 43 | devel_gnupg2: deferred (2022-09-28) | ||
118 | 0 | \ No newline at end of file | 44 | \ No newline at end of file |
119 | diff --git a/lib/lp/bugs/scripts/tests/test_uctimport.py b/lib/lp/bugs/scripts/tests/test_uctimport.py | |||
120 | 1 | new file mode 100644 | 45 | new file mode 100644 |
121 | index 0000000..2e36bb5 | |||
122 | --- /dev/null | |||
123 | +++ b/lib/lp/bugs/scripts/tests/test_uctimport.py | |||
124 | @@ -0,0 +1,88 @@ | |||
125 | 1 | from pathlib import Path | ||
126 | 2 | |||
127 | 3 | from lp.testing import TestCase | ||
128 | 4 | from lp.testing.layers import LaunchpadZopelessLayer | ||
129 | 5 | from lp.testing.script import run_script | ||
130 | 6 | |||
131 | 7 | |||
132 | 8 | class TestUCTImportScript(TestCase): | ||
133 | 9 | """Test the TestUCTImportScript class.""" | ||
134 | 10 | |||
135 | 11 | layer = LaunchpadZopelessLayer | ||
136 | 12 | |||
137 | 13 | def test_no_path_given(self): | ||
138 | 14 | """TestUCTImportScript errors when no path given""" | ||
139 | 15 | exit_code, out, err = run_script( | ||
140 | 16 | script="scripts/uct-import.py", | ||
141 | 17 | args=[], | ||
142 | 18 | ) | ||
143 | 19 | self.assertEqual(2, exit_code) | ||
144 | 20 | self.assertEqual("", out) | ||
145 | 21 | self.assertEqual( | ||
146 | 22 | "Usage: uct-import.py [options] PATH\n\nuct-import.py: " | ||
147 | 23 | "error: Please specify a path to import\n", | ||
148 | 24 | err, | ||
149 | 25 | ) | ||
150 | 26 | |||
151 | 27 | def test_load_from_file(self): | ||
152 | 28 | load_from = Path(__file__).parent / "sampledata" / "CVE-2022-23222" | ||
153 | 29 | exit_code, out, err = run_script( | ||
154 | 30 | script="scripts/uct-import.py", | ||
155 | 31 | args=[str(load_from)], | ||
156 | 32 | ) | ||
157 | 33 | self.assertEqual(0, exit_code) | ||
158 | 34 | self.assertEqual("", out) | ||
159 | 35 | self.assertIn("CVE-2022-23222 was imported successfully", err) | ||
160 | 36 | |||
161 | 37 | def test_load_from_directory(self): | ||
162 | 38 | load_from = Path(__file__).parent / "sampledata" | ||
163 | 39 | exit_code, out, err = run_script( | ||
164 | 40 | script="scripts/uct-import.py", | ||
165 | 41 | args=[str(load_from)], | ||
166 | 42 | ) | ||
167 | 43 | self.assertEqual(0, exit_code) | ||
168 | 44 | self.assertEqual("", out) | ||
169 | 45 | self.assertIn("CVE-2007-0255 was imported successfully", err) | ||
170 | 46 | self.assertIn("CVE-2022-3219 was imported successfully", err) | ||
171 | 47 | self.assertIn("CVE-2022-23222 was imported successfully", err) | ||
172 | 48 | |||
173 | 49 | def test_dry_run_does_not_crash(self): | ||
174 | 50 | load_from = Path(__file__).parent / "sampledata" / "CVE-2022-23222" | ||
175 | 51 | exit_code, out, err = run_script( | ||
176 | 52 | script="scripts/uct-import.py", | ||
177 | 53 | args=[str(load_from), "--dry-run"], | ||
178 | 54 | ) | ||
179 | 55 | self.assertEqual(0, exit_code) | ||
180 | 56 | self.assertEqual("", out) | ||
181 | 57 | self.assertRegex(err, r"^INFO Importing.*CVE-2022-23222.*") | ||
182 | 58 | |||
183 | 59 | def test_filter_cve(self): | ||
184 | 60 | load_from = Path(__file__).parent / "sampledata" | ||
185 | 61 | exit_code, out, err = run_script( | ||
186 | 62 | script="scripts/uct-import.py", | ||
187 | 63 | args=[str(load_from), "--filter", "2007*"], | ||
188 | 64 | ) | ||
189 | 65 | self.assertEqual(0, exit_code) | ||
190 | 66 | self.assertEqual("", out) | ||
191 | 67 | self.assertNotIn("CVE-2022-23222 was imported successfully", err) | ||
192 | 68 | self.assertIn("CVE-2007-0255 was imported successfully", err) | ||
193 | 69 | |||
194 | 70 | exit_code, out, err = run_script( | ||
195 | 71 | script="scripts/uct-import.py", | ||
196 | 72 | args=[str(load_from), "--filter", "2022*"], | ||
197 | 73 | ) | ||
198 | 74 | self.assertEqual(0, exit_code) | ||
199 | 75 | self.assertEqual("", out) | ||
200 | 76 | self.assertIn("CVE-2022-23222 was imported successfully", err) | ||
201 | 77 | self.assertIn("CVE-2022-3219 was imported successfully", err) | ||
202 | 78 | self.assertNotIn("CVE-2007-0255 was imported successfully", err) | ||
203 | 79 | |||
204 | 80 | exit_code, out, err = run_script( | ||
205 | 81 | script="scripts/uct-import.py", | ||
206 | 82 | args=[str(load_from), "--filter", "20[02][27]*"], | ||
207 | 83 | ) | ||
208 | 84 | self.assertEqual(0, exit_code) | ||
209 | 85 | self.assertEqual("", out) | ||
210 | 86 | self.assertIn("CVE-2022-23222 was imported successfully", err) | ||
211 | 87 | self.assertIn("CVE-2022-3219 was imported successfully", err) | ||
212 | 88 | self.assertIn("CVE-2007-0255 was imported successfully", err) | ||
213 | diff --git a/lib/lp/bugs/scripts/uctimport.py b/lib/lp/bugs/scripts/uctimport.py | |||
214 | 0 | new file mode 100644 | 89 | new file mode 100644 |
215 | index 0000000..aed11c3 | |||
216 | --- /dev/null | |||
217 | +++ b/lib/lp/bugs/scripts/uctimport.py | |||
218 | @@ -0,0 +1,63 @@ | |||
219 | 1 | import logging | ||
220 | 2 | from pathlib import Path | ||
221 | 3 | |||
222 | 4 | from lp.app.validators.cve import CVEREF_PATTERN | ||
223 | 5 | from lp.bugs.scripts.uct import UCTImporter | ||
224 | 6 | from lp.services.scripts.base import LaunchpadScript | ||
225 | 7 | |||
226 | 8 | logger = logging.getLogger(__name__) | ||
227 | 9 | |||
228 | 10 | |||
229 | 11 | class UCTImportScript(LaunchpadScript): | ||
230 | 12 | """CLI for UCTImport | ||
231 | 13 | |||
232 | 14 | Command line options: | ||
233 | 15 | The filter option takes a glob-style pattern. | ||
234 | 16 | Example: `2007*` filters all CVEs from the year 2007. | ||
235 | 17 | """ | ||
236 | 18 | |||
237 | 19 | usage = "usage: %prog [options] PATH" | ||
238 | 20 | description = ( | ||
239 | 21 | "Import bugs into Launchpad from CVE entries in ubuntu-cve-tracker. " | ||
240 | 22 | "PATH is either path to a CVE file, or path to a directory " | ||
241 | 23 | "containing the CVE files." | ||
242 | 24 | ) | ||
243 | 25 | loglevel = logging.INFO | ||
244 | 26 | |||
245 | 27 | def add_my_options(self): | ||
246 | 28 | self.parser.add_option( | ||
247 | 29 | "--dry-run", | ||
248 | 30 | action="store_true", | ||
249 | 31 | dest="dry_run", | ||
250 | 32 | default=False, | ||
251 | 33 | help="Don't commit changes to the DB.", | ||
252 | 34 | ) | ||
253 | 35 | self.parser.add_option( | ||
254 | 36 | "--filter", | ||
255 | 37 | action="store", | ||
256 | 38 | dest="filter", | ||
257 | 39 | default="*", | ||
258 | 40 | help="Apply given glob-style pattern to filter CVEs.", | ||
259 | 41 | ) | ||
260 | 42 | |||
261 | 43 | def main(self): | ||
262 | 44 | if len(self.args) != 1: | ||
263 | 45 | self.parser.error("Please specify a path to import") | ||
264 | 46 | path = Path(self.args[0]) | ||
265 | 47 | if path.is_dir(): | ||
266 | 48 | logger.info( | ||
267 | 49 | "Importing CVE files from directory: %s", path.resolve() | ||
268 | 50 | ) | ||
269 | 51 | cve_paths = sorted( | ||
270 | 52 | p | ||
271 | 53 | for p in path.rglob("CVE-%s" % self.options.filter) | ||
272 | 54 | if p.is_file() and CVEREF_PATTERN.match(p.name) | ||
273 | 55 | ) | ||
274 | 56 | if not cve_paths: | ||
275 | 57 | logger.warning("Could not find CVE files in %s", path) | ||
276 | 58 | return | ||
277 | 59 | else: | ||
278 | 60 | cve_paths = [path] | ||
279 | 61 | importer = UCTImporter(dry_run=self.options.dry_run) | ||
280 | 62 | for cve_path in cve_paths: | ||
281 | 63 | importer.import_cve_from_file(cve_path) | ||
282 | diff --git a/scripts/uct-import.py b/scripts/uct-import.py | |||
283 | index 489d6ea..9ade412 100755 | |||
284 | --- a/scripts/uct-import.py | |||
285 | +++ b/scripts/uct-import.py | |||
286 | @@ -4,59 +4,7 @@ | |||
287 | 4 | # GNU Affero General Public License version 3 (see the file LICENSE). | 4 | # GNU Affero General Public License version 3 (see the file LICENSE). |
288 | 5 | import _pythonpath # noqa: F401 | 5 | import _pythonpath # noqa: F401 |
289 | 6 | 6 | ||
343 | 7 | import logging | 7 | from lp.bugs.scripts.uctimport import UCTImportScript |
291 | 8 | from pathlib import Path | ||
292 | 9 | |||
293 | 10 | from lp.app.validators.cve import CVEREF_PATTERN | ||
294 | 11 | from lp.bugs.scripts.uct import UCTImporter | ||
295 | 12 | from lp.services.scripts.base import LaunchpadScript | ||
296 | 13 | |||
297 | 14 | logger = logging.getLogger(__name__) | ||
298 | 15 | |||
299 | 16 | |||
300 | 17 | class UCTImportScript(LaunchpadScript): | ||
301 | 18 | |||
302 | 19 | usage = "usage: %prog [options] PATH" | ||
303 | 20 | description = ( | ||
304 | 21 | "Import bugs into Launchpad from CVE entries in ubuntu-cve-tracker. " | ||
305 | 22 | "PATH is either path to a CVE file, or path to a directory " | ||
306 | 23 | "containing the CVE files" | ||
307 | 24 | ) | ||
308 | 25 | loglevel = logging.INFO | ||
309 | 26 | |||
310 | 27 | def add_my_options(self): | ||
311 | 28 | self.parser.add_option( | ||
312 | 29 | "--dry-run", | ||
313 | 30 | action="store_true", | ||
314 | 31 | dest="dry_run", | ||
315 | 32 | default=False, | ||
316 | 33 | help="Don't commit changes to the DB.", | ||
317 | 34 | ) | ||
318 | 35 | |||
319 | 36 | def main(self): | ||
320 | 37 | if len(self.args) != 1: | ||
321 | 38 | self.parser.error("Please specify a path to import") | ||
322 | 39 | |||
323 | 40 | path = Path(self.args[0]) | ||
324 | 41 | if path.is_dir(): | ||
325 | 42 | logger.info( | ||
326 | 43 | "Importing CVE files from directory: %s", path.resolve() | ||
327 | 44 | ) | ||
328 | 45 | cve_paths = sorted( | ||
329 | 46 | p | ||
330 | 47 | for p in path.rglob("CVE-*") | ||
331 | 48 | if p.is_file() and CVEREF_PATTERN.match(p.name) | ||
332 | 49 | ) | ||
333 | 50 | if not cve_paths: | ||
334 | 51 | logger.warning("Could not find CVE files in %s", path) | ||
335 | 52 | return | ||
336 | 53 | else: | ||
337 | 54 | cve_paths = [path] | ||
338 | 55 | |||
339 | 56 | importer = UCTImporter(dry_run=self.options.dry_run) | ||
340 | 57 | for cve_path in cve_paths: | ||
341 | 58 | importer.import_cve_from_file(cve_path) | ||
342 | 59 | |||
344 | 60 | 8 | ||
345 | 61 | if __name__ == "__main__": | 9 | if __name__ == "__main__": |
346 | 62 | script = UCTImportScript("lp.services.scripts.uctimport") | 10 | script = UCTImportScript("lp.services.scripts.uctimport") |
Enable filtering for UCTImports