Merge ~andrey-fedoseev/launchpad:uct-import-export-break-fix into launchpad:master
- Git
- lp:~andrey-fedoseev/launchpad
- uct-import-export-break-fix
- Merge into master
Status: | Needs review |
---|---|
Proposed branch: | ~andrey-fedoseev/launchpad:uct-import-export-break-fix |
Merge into: | launchpad:master |
Prerequisite: | ~andrey-fedoseev/launchpad:bug-presense |
Diff against target: |
486 lines (+260/-4) 5 files modified
lib/lp/bugs/model/bugpresence.py (+3/-0) lib/lp/bugs/scripts/tests/test_uct.py (+102/-0) lib/lp/bugs/scripts/uct/models.py (+93/-4) lib/lp/bugs/scripts/uct/uctexport.py (+16/-0) lib/lp/bugs/scripts/uct/uctimport.py (+46/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Launchpad code reviewers | Pending | ||
Review via email: mp+432181@code.launchpad.net |
Commit message
UCT import/export: handle the `break-fix` entries
Description of the change
For each `break-fix` entry create a `BugPresence` instance linked to the default git repository of the project (if exists)
If a `break-fix` entry includes multiple git commits in the "fixed" section it means that either of them fixes the issue. So, we create multiple `BugPresence` instances, one per commit listed in the "fixed" section.
Items such as `local-
- d62597c... by Andrey Fedoseev
-
UCT import/export: handle the `break-fix` entries
For each `break-fix` entry create a `BugPresence` instance linked to the default git repository of the project (if exists)
If a `break-fix` entry includes multiple git commits in the "fixed" section it means that either of them fixes the issue. So, we create multiple `BugPresence` instances, one per commit listed in the "fixed" section.
Items such as `local-
CVE-2022- 23222-fix` are currently ignored
Unmerged commits
- d62597c... by Andrey Fedoseev
-
UCT import/export: handle the `break-fix` entries
For each `break-fix` entry create a `BugPresence` instance linked to the default git repository of the project (if exists)
If a `break-fix` entry includes multiple git commits in the "fixed" section it means that either of them fixes the issue. So, we create multiple `BugPresence` instances, one per commit listed in the "fixed" section.
Items such as `local-
CVE-2022- 23222-fix` are currently ignored -
docs:0 (build) lint:0 (build) mypy:0 (build) 1 → 3 of 3 results First • Previous • Next • Last - 460e925... by Andrey Fedoseev
-
Add `BugPresence` model
It represents a range of versions or git commits in which the bug was present.
-
docs:0 (build) lint:0 (build) mypy:0 (build) 1 → 3 of 3 results First • Previous • Next • Last
Preview Diff
1 | diff --git a/lib/lp/bugs/model/bugpresence.py b/lib/lp/bugs/model/bugpresence.py | |||
2 | index b21371e..4ca8128 100644 | |||
3 | --- a/lib/lp/bugs/model/bugpresence.py | |||
4 | +++ b/lib/lp/bugs/model/bugpresence.py | |||
5 | @@ -20,6 +20,9 @@ class BugPresence(StormBase): | |||
6 | 20 | """See `IBugPresence`.""" | 20 | """See `IBugPresence`.""" |
7 | 21 | 21 | ||
8 | 22 | __storm_table__ = "BugPresence" | 22 | __storm_table__ = "BugPresence" |
9 | 23 | __storm_order__ = [ | ||
10 | 24 | "id", | ||
11 | 25 | ] | ||
12 | 23 | 26 | ||
13 | 24 | id = Int(primary=True) | 27 | id = Int(primary=True) |
14 | 25 | 28 | ||
15 | diff --git a/lib/lp/bugs/scripts/tests/test_uct.py b/lib/lp/bugs/scripts/tests/test_uct.py | |||
16 | index 9813d86..3ce76b7 100644 | |||
17 | --- a/lib/lp/bugs/scripts/tests/test_uct.py | |||
18 | +++ b/lib/lp/bugs/scripts/tests/test_uct.py | |||
19 | @@ -6,10 +6,12 @@ from typing import List | |||
20 | 6 | 6 | ||
21 | 7 | from pytz import UTC | 7 | from pytz import UTC |
22 | 8 | from zope.component import getUtility | 8 | from zope.component import getUtility |
23 | 9 | from zope.security.proxy import removeSecurityProxy | ||
24 | 9 | 10 | ||
25 | 10 | from lp.app.enums import InformationType | 11 | from lp.app.enums import InformationType |
26 | 11 | from lp.app.interfaces.launchpad import ILaunchpadCelebrities | 12 | from lp.app.interfaces.launchpad import ILaunchpadCelebrities |
27 | 12 | from lp.bugs.enums import VulnerabilityStatus | 13 | from lp.bugs.enums import VulnerabilityStatus |
28 | 14 | from lp.bugs.interfaces.bugpresence import IBugPresenceSet | ||
29 | 13 | from lp.bugs.interfaces.bugtask import BugTaskImportance, BugTaskStatus | 15 | from lp.bugs.interfaces.bugtask import BugTaskImportance, BugTaskStatus |
30 | 14 | from lp.bugs.model.bug import Bug | 16 | from lp.bugs.model.bug import Bug |
31 | 15 | from lp.bugs.model.bugtask import BugTask | 17 | from lp.bugs.model.bugtask import BugTask |
32 | @@ -274,6 +276,20 @@ class TestCVE(TestCaseWithFactory): | |||
33 | 274 | tags=set(), | 276 | tags=set(), |
34 | 275 | patches=[ | 277 | patches=[ |
35 | 276 | UCTRecord.Patch( | 278 | UCTRecord.Patch( |
36 | 279 | patch_type="break-fix", | ||
37 | 280 | entry=( | ||
38 | 281 | "457f44363a8894135c85b7a9afd2bd8196db24ab " | ||
39 | 282 | "c25b2ae136039ffa820c26138ed4a5e5f3ab3841|" | ||
40 | 283 | "4969c06a0d83c9c3dc50b8efcdc8eeedfce896f6" | ||
41 | 284 | ), | ||
42 | 285 | ), | ||
43 | 286 | UCTRecord.Patch( | ||
44 | 287 | patch_type="break-fix", | ||
45 | 288 | entry=( | ||
46 | 289 | "- c25b2ae136039ffa820c26138ed4a5e5f3ab3841" | ||
47 | 290 | ), | ||
48 | 291 | ), | ||
49 | 292 | UCTRecord.Patch( | ||
50 | 277 | patch_type="upstream", | 293 | patch_type="upstream", |
51 | 278 | entry=( | 294 | entry=( |
52 | 279 | "https://github.com/389ds/389-ds-base/" | 295 | "https://github.com/389ds/389-ds-base/" |
53 | @@ -416,6 +432,30 @@ class TestCVE(TestCaseWithFactory): | |||
54 | 416 | importance=None, | 432 | importance=None, |
55 | 417 | status=BugTaskStatus.FIXRELEASED, | 433 | status=BugTaskStatus.FIXRELEASED, |
56 | 418 | status_explanation="reason 4", | 434 | status_explanation="reason 4", |
57 | 435 | break_fixes=[ | ||
58 | 436 | CVE.BreakFix( | ||
59 | 437 | broken_git_commit_sha1=( | ||
60 | 438 | "457f44363a8894135c85b7a9afd2bd8196db24ab" | ||
61 | 439 | ), | ||
62 | 440 | fixed_git_commit_sha1=( | ||
63 | 441 | "c25b2ae136039ffa820c26138ed4a5e5f3ab3841" | ||
64 | 442 | ), | ||
65 | 443 | ), | ||
66 | 444 | CVE.BreakFix( | ||
67 | 445 | broken_git_commit_sha1=( | ||
68 | 446 | "457f44363a8894135c85b7a9afd2bd8196db24ab" | ||
69 | 447 | ), | ||
70 | 448 | fixed_git_commit_sha1=( | ||
71 | 449 | "4969c06a0d83c9c3dc50b8efcdc8eeedfce896f6" | ||
72 | 450 | ), | ||
73 | 451 | ), | ||
74 | 452 | CVE.BreakFix( | ||
75 | 453 | broken_git_commit_sha1=None, | ||
76 | 454 | fixed_git_commit_sha1=( | ||
77 | 455 | "c25b2ae136039ffa820c26138ed4a5e5f3ab3841" | ||
78 | 456 | ), | ||
79 | 457 | ), | ||
80 | 458 | ], | ||
81 | 419 | ), | 459 | ), |
82 | 420 | CVE.UpstreamPackage( | 460 | CVE.UpstreamPackage( |
83 | 421 | target=product_2, | 461 | target=product_2, |
84 | @@ -423,6 +463,7 @@ class TestCVE(TestCaseWithFactory): | |||
85 | 423 | importance=None, | 463 | importance=None, |
86 | 424 | status=BugTaskStatus.FIXRELEASED, | 464 | status=BugTaskStatus.FIXRELEASED, |
87 | 425 | status_explanation="", | 465 | status_explanation="", |
88 | 466 | break_fixes=[], | ||
89 | 426 | ), | 467 | ), |
90 | 427 | ], | 468 | ], |
91 | 428 | importance=BugTaskImportance.CRITICAL, | 469 | importance=BugTaskImportance.CRITICAL, |
92 | @@ -564,6 +605,13 @@ class TestUCTImporterExporter(TestCaseWithFactory): | |||
93 | 564 | distroseries=self.esm_current_series, | 605 | distroseries=self.esm_current_series, |
94 | 565 | ).productseries.product | 606 | ).productseries.product |
95 | 566 | 607 | ||
96 | 608 | self.product_1_git_repo = self.factory.makeGitRepository( | ||
97 | 609 | target=self.product_1, target_default=True | ||
98 | 610 | ) | ||
99 | 611 | self.product_2_git_repo = self.factory.makeGitRepository( | ||
100 | 612 | target=self.product_2, target_default=True | ||
101 | 613 | ) | ||
102 | 614 | |||
103 | 567 | for series in ( | 615 | for series in ( |
104 | 568 | self.ubuntu_supported_series, | 616 | self.ubuntu_supported_series, |
105 | 569 | self.ubuntu_current_series, | 617 | self.ubuntu_current_series, |
106 | @@ -661,6 +709,24 @@ class TestUCTImporterExporter(TestCaseWithFactory): | |||
107 | 661 | importance=BugTaskImportance.HIGH, | 709 | importance=BugTaskImportance.HIGH, |
108 | 662 | status=BugTaskStatus.FIXRELEASED, | 710 | status=BugTaskStatus.FIXRELEASED, |
109 | 663 | status_explanation="fix released", | 711 | status_explanation="fix released", |
110 | 712 | break_fixes=[ | ||
111 | 713 | CVE.BreakFix( | ||
112 | 714 | broken_git_commit_sha1=( | ||
113 | 715 | "054623105728b06852f077299e2bf1bf3d5f2b0b" | ||
114 | 716 | ), | ||
115 | 717 | fixed_git_commit_sha1=( | ||
116 | 718 | "db7bee653859ef7179be933e7d1384644f795f26" | ||
117 | 719 | ), | ||
118 | 720 | ), | ||
119 | 721 | CVE.BreakFix( | ||
120 | 722 | broken_git_commit_sha1=( | ||
121 | 723 | "054623105728b06852f077299e2bf1bf3d5f2b0b" | ||
122 | 724 | ), | ||
123 | 725 | fixed_git_commit_sha1=( | ||
124 | 726 | "6e61dc9da0b7a0d91d57c2e20b5ea4fd2d4e7e53" | ||
125 | 727 | ), | ||
126 | 728 | ), | ||
127 | 729 | ], | ||
128 | 664 | ), | 730 | ), |
129 | 665 | CVE.UpstreamPackage( | 731 | CVE.UpstreamPackage( |
130 | 666 | target=self.product_2, | 732 | target=self.product_2, |
131 | @@ -668,6 +734,20 @@ class TestUCTImporterExporter(TestCaseWithFactory): | |||
132 | 668 | importance=BugTaskImportance.LOW, | 734 | importance=BugTaskImportance.LOW, |
133 | 669 | status=BugTaskStatus.WONTFIX, | 735 | status=BugTaskStatus.WONTFIX, |
134 | 670 | status_explanation="ignored", | 736 | status_explanation="ignored", |
135 | 737 | break_fixes=[ | ||
136 | 738 | CVE.BreakFix( | ||
137 | 739 | broken_git_commit_sha1=None, | ||
138 | 740 | fixed_git_commit_sha1=( | ||
139 | 741 | "6e61dc9da0b7a0d91d57c2e20b5ea4fd2d4e7e53" | ||
140 | 742 | ), | ||
141 | 743 | ), | ||
142 | 744 | CVE.BreakFix( | ||
143 | 745 | broken_git_commit_sha1=( | ||
144 | 746 | "4e9b4a6883dd97aff53ae3b08eb900716a5469dc" | ||
145 | 747 | ), | ||
146 | 748 | fixed_git_commit_sha1=None, | ||
147 | 749 | ), | ||
148 | 750 | ], | ||
149 | 671 | ), | 751 | ), |
150 | 672 | ], | 752 | ], |
151 | 673 | importance=BugTaskImportance.MEDIUM, | 753 | importance=BugTaskImportance.MEDIUM, |
152 | @@ -724,6 +804,7 @@ class TestUCTImporterExporter(TestCaseWithFactory): | |||
153 | 724 | self.assertEqual(sorted(cve.bug_urls), sorted(w.url for w in watches)) | 804 | self.assertEqual(sorted(cve.bug_urls), sorted(w.url for w in watches)) |
154 | 725 | 805 | ||
155 | 726 | self.checkBugAttachments(bug, cve) | 806 | self.checkBugAttachments(bug, cve) |
156 | 807 | self.checkBugPresence(bug, cve) | ||
157 | 727 | 808 | ||
158 | 728 | def checkBugTasks(self, bug: Bug, cve: CVE): | 809 | def checkBugTasks(self, bug: Bug, cve: CVE): |
159 | 729 | bug_tasks = bug.bugtasks # type: List[BugTask] | 810 | bug_tasks = bug.bugtasks # type: List[BugTask] |
160 | @@ -799,6 +880,27 @@ class TestUCTImporterExporter(TestCaseWithFactory): | |||
161 | 799 | ) | 880 | ) |
162 | 800 | self.assertEqual(expected_title, attachment.title) | 881 | self.assertEqual(expected_title, attachment.title) |
163 | 801 | 882 | ||
164 | 883 | def checkBugPresence(self, bug: Bug, cve: CVE): | ||
165 | 884 | expected_break_fixes = set() | ||
166 | 885 | for upstream_package in cve.upstream_packages: | ||
167 | 886 | for break_fix in upstream_package.break_fixes: | ||
168 | 887 | expected_break_fixes.add( | ||
169 | 888 | (upstream_package.target.name, break_fix) | ||
170 | 889 | ) | ||
171 | 890 | actual_break_fixes = set() | ||
172 | 891 | for bp in getUtility(IBugPresenceSet).getByBug(bug): | ||
173 | 892 | project = removeSecurityProxy(bp).git_repository.project | ||
174 | 893 | actual_break_fixes.add( | ||
175 | 894 | ( | ||
176 | 895 | project.name, | ||
177 | 896 | CVE.BreakFix( | ||
178 | 897 | broken_git_commit_sha1=bp.broken_git_commit_sha1, | ||
179 | 898 | fixed_git_commit_sha1=bp.fixed_git_commit_sha1, | ||
180 | 899 | ), | ||
181 | 900 | ) | ||
182 | 901 | ) | ||
183 | 902 | self.assertSetEqual(expected_break_fixes, actual_break_fixes) | ||
184 | 903 | |||
185 | 802 | def checkVulnerabilities(self, bug: Bug, cve: CVE): | 904 | def checkVulnerabilities(self, bug: Bug, cve: CVE): |
186 | 803 | vulnerabilities = bug.vulnerabilities | 905 | vulnerabilities = bug.vulnerabilities |
187 | 804 | 906 | ||
188 | diff --git a/lib/lp/bugs/scripts/uct/models.py b/lib/lp/bugs/scripts/uct/models.py | |||
189 | index fd77ea5..2540eda 100644 | |||
190 | --- a/lib/lp/bugs/scripts/uct/models.py | |||
191 | +++ b/lib/lp/bugs/scripts/uct/models.py | |||
192 | @@ -450,6 +450,14 @@ class CVE: | |||
193 | 450 | ), | 450 | ), |
194 | 451 | ) | 451 | ) |
195 | 452 | 452 | ||
196 | 453 | BreakFix = NamedTuple( | ||
197 | 454 | "BreakFix", | ||
198 | 455 | ( | ||
199 | 456 | ("broken_git_commit_sha1", Optional[str]), | ||
200 | 457 | ("fixed_git_commit_sha1", Optional[str]), | ||
201 | 458 | ), | ||
202 | 459 | ) | ||
203 | 460 | |||
204 | 453 | UpstreamPackage = NamedTuple( | 461 | UpstreamPackage = NamedTuple( |
205 | 454 | "UpstreamPackage", | 462 | "UpstreamPackage", |
206 | 455 | ( | 463 | ( |
207 | @@ -458,6 +466,7 @@ class CVE: | |||
208 | 458 | ("importance", Optional[BugTaskImportance]), | 466 | ("importance", Optional[BugTaskImportance]), |
209 | 459 | ("status", BugTaskStatus), | 467 | ("status", BugTaskStatus), |
210 | 460 | ("status_explanation", str), | 468 | ("status_explanation", str), |
211 | 469 | ("break_fixes", List[BreakFix]), | ||
212 | 461 | ), | 470 | ), |
213 | 462 | ) | 471 | ) |
214 | 463 | 472 | ||
215 | @@ -475,6 +484,7 @@ class CVE: | |||
216 | 475 | # https://github.com/389ds/389-ds-base/commit/123 (1.4.4) | 484 | # https://github.com/389ds/389-ds-base/commit/123 (1.4.4) |
217 | 476 | # https://github.com/389ds/389-ds-base/commit/345 | 485 | # https://github.com/389ds/389-ds-base/commit/345 |
218 | 477 | PATCH_URL_RE = re.compile(r"^(?P<url>.+?)(\s+\((?P<notes>.+)\))?$") | 486 | PATCH_URL_RE = re.compile(r"^(?P<url>.+?)(\s+\((?P<notes>.+)\))?$") |
219 | 487 | GIT_HASH_RE = re.compile(r"^[a-f0-9]{40}$") | ||
220 | 478 | 488 | ||
221 | 479 | PRIORITY_MAP = { | 489 | PRIORITY_MAP = { |
222 | 480 | UCTRecord.Priority.CRITICAL: BugTaskImportance.CRITICAL, | 490 | UCTRecord.Priority.CRITICAL: BugTaskImportance.CRITICAL, |
223 | @@ -563,6 +573,7 @@ class CVE: | |||
224 | 563 | distro_packages = [] | 573 | distro_packages = [] |
225 | 564 | series_packages = [] | 574 | series_packages = [] |
226 | 565 | patch_urls = [] | 575 | patch_urls = [] |
227 | 576 | break_fixes = {} # type: Dict[SourcePackageName, List[CVE.BreakFix]] | ||
228 | 566 | 577 | ||
229 | 567 | spn_set = getUtility(ISourcePackageNameSet) | 578 | spn_set = getUtility(ISourcePackageNameSet) |
230 | 568 | 579 | ||
231 | @@ -577,6 +588,10 @@ class CVE: | |||
232 | 577 | cls.get_patch_urls(source_package_name, uct_package.patches) | 588 | cls.get_patch_urls(source_package_name, uct_package.patches) |
233 | 578 | ) | 589 | ) |
234 | 579 | 590 | ||
235 | 591 | break_fixes[source_package_name] = cls.get_break_fixes( | ||
236 | 592 | uct_package.patches | ||
237 | 593 | ) | ||
238 | 594 | |||
239 | 580 | package_importance = ( | 595 | package_importance = ( |
240 | 581 | cls.PRIORITY_MAP[uct_package.priority] | 596 | cls.PRIORITY_MAP[uct_package.priority] |
241 | 582 | if uct_package.priority | 597 | if uct_package.priority |
242 | @@ -665,6 +680,7 @@ class CVE: | |||
243 | 665 | ), | 680 | ), |
244 | 666 | status=cls.BUG_TASK_STATUS_MAP[upstream_status.status], | 681 | status=cls.BUG_TASK_STATUS_MAP[upstream_status.status], |
245 | 667 | status_explanation=upstream_status.reason, | 682 | status_explanation=upstream_status.reason, |
246 | 683 | break_fixes=break_fixes[source_package_name], | ||
247 | 668 | ) | 684 | ) |
248 | 669 | ) | 685 | ) |
249 | 670 | 686 | ||
250 | @@ -786,15 +802,32 @@ class CVE: | |||
251 | 786 | patches=[], | 802 | patches=[], |
252 | 787 | ) | 803 | ) |
253 | 788 | 804 | ||
254 | 805 | grouped_break_fixes = OrderedDict() | ||
255 | 806 | for break_fix in upstream_package.break_fixes: | ||
256 | 807 | if break_fix.broken_git_commit_sha1 not in grouped_break_fixes: | ||
257 | 808 | grouped_break_fixes[break_fix.broken_git_commit_sha1] = [] | ||
258 | 809 | if break_fix.fixed_git_commit_sha1: | ||
259 | 810 | grouped_break_fixes[ | ||
260 | 811 | break_fix.broken_git_commit_sha1 | ||
261 | 812 | ].append(break_fix.fixed_git_commit_sha1) | ||
262 | 813 | |||
263 | 814 | for break_commit, fixed_commits in grouped_break_fixes.items(): | ||
264 | 815 | entry = "{} {}".format( | ||
265 | 816 | break_commit or "-", | ||
266 | 817 | "|".join(fixed_commits) or "-", | ||
267 | 818 | ) | ||
268 | 819 | packages_by_name[ | ||
269 | 820 | upstream_package.package_name.name | ||
270 | 821 | ].patches.append( | ||
271 | 822 | UCTRecord.Patch(patch_type="break-fix", entry=entry) | ||
272 | 823 | ) | ||
273 | 824 | |||
274 | 789 | for patch_url in self.patch_urls: | 825 | for patch_url in self.patch_urls: |
275 | 790 | entry = patch_url.url | 826 | entry = patch_url.url |
276 | 791 | if patch_url.notes: | 827 | if patch_url.notes: |
277 | 792 | entry = "{} ({})".format(entry, patch_url.notes) | 828 | entry = "{} ({})".format(entry, patch_url.notes) |
278 | 793 | packages_by_name[patch_url.package_name.name].patches.append( | 829 | packages_by_name[patch_url.package_name.name].patches.append( |
283 | 794 | UCTRecord.Patch( | 830 | UCTRecord.Patch(patch_type=patch_url.type, entry=entry) |
280 | 795 | patch_type=patch_url.type, | ||
281 | 796 | entry=entry, | ||
282 | 797 | ) | ||
284 | 798 | ) | 831 | ) |
285 | 799 | 832 | ||
286 | 800 | return UCTRecord( | 833 | return UCTRecord( |
287 | @@ -909,3 +942,59 @@ class CVE: | |||
288 | 909 | url=url, | 942 | url=url, |
289 | 910 | notes=notes, | 943 | notes=notes, |
290 | 911 | ) | 944 | ) |
291 | 945 | |||
292 | 946 | @classmethod | ||
293 | 947 | def get_break_fixes( | ||
294 | 948 | cls, | ||
295 | 949 | patches: List[UCTRecord.Patch], | ||
296 | 950 | ) -> List[BreakFix]: | ||
297 | 951 | |||
298 | 952 | break_fixes = [] | ||
299 | 953 | |||
300 | 954 | for patch in patches: | ||
301 | 955 | if patch.patch_type != "break-fix": | ||
302 | 956 | continue | ||
303 | 957 | |||
304 | 958 | try: | ||
305 | 959 | broken_entry, joint_fixed_entries = patch.entry.split() | ||
306 | 960 | except ValueError: | ||
307 | 961 | logger.error( | ||
308 | 962 | "Could not parse break-fix entry: %s", patch.entry | ||
309 | 963 | ) | ||
310 | 964 | continue | ||
311 | 965 | |||
312 | 966 | if broken_entry == "-": | ||
313 | 967 | broken_entry = None | ||
314 | 968 | elif not cls.GIT_HASH_RE.match(broken_entry): | ||
315 | 969 | logger.error( | ||
316 | 970 | "broken entry doesn't look like git commit SHA1: %s", | ||
317 | 971 | broken_entry, | ||
318 | 972 | ) | ||
319 | 973 | continue | ||
320 | 974 | |||
321 | 975 | if joint_fixed_entries == "-": | ||
322 | 976 | if broken_entry: | ||
323 | 977 | break_fixes.append( | ||
324 | 978 | cls.BreakFix( | ||
325 | 979 | broken_git_commit_sha1=broken_entry, | ||
326 | 980 | fixed_git_commit_sha1=None, | ||
327 | 981 | ) | ||
328 | 982 | ) | ||
329 | 983 | continue | ||
330 | 984 | |||
331 | 985 | for fixed_entry in joint_fixed_entries.split("|"): | ||
332 | 986 | # TODO: handle the with fixed_entry="local-CVE-2021-20177" | ||
333 | 987 | if cls.GIT_HASH_RE.match(fixed_entry): | ||
334 | 988 | break_fixes.append( | ||
335 | 989 | cls.BreakFix( | ||
336 | 990 | broken_git_commit_sha1=broken_entry, | ||
337 | 991 | fixed_git_commit_sha1=fixed_entry, | ||
338 | 992 | ) | ||
339 | 993 | ) | ||
340 | 994 | else: | ||
341 | 995 | logger.error( | ||
342 | 996 | "fixed entry doesn't look like git commit " "SHA1: %s", | ||
343 | 997 | fixed_entry, | ||
344 | 998 | ) | ||
345 | 999 | |||
346 | 1000 | return break_fixes | ||
347 | diff --git a/lib/lp/bugs/scripts/uct/uctexport.py b/lib/lp/bugs/scripts/uct/uctexport.py | |||
348 | index 8a1dd27..ff1a9c5 100644 | |||
349 | --- a/lib/lp/bugs/scripts/uct/uctexport.py | |||
350 | +++ b/lib/lp/bugs/scripts/uct/uctexport.py | |||
351 | @@ -12,6 +12,7 @@ from zope.security.proxy import removeSecurityProxy | |||
352 | 12 | 12 | ||
353 | 13 | from lp.bugs.interfaces.bug import IBugSet | 13 | from lp.bugs.interfaces.bug import IBugSet |
354 | 14 | from lp.bugs.interfaces.bugattachment import BugAttachmentType | 14 | from lp.bugs.interfaces.bugattachment import BugAttachmentType |
355 | 15 | from lp.bugs.interfaces.bugpresence import IBugPresenceSet | ||
356 | 15 | from lp.bugs.model.bug import Bug as BugModel | 16 | from lp.bugs.model.bug import Bug as BugModel |
357 | 16 | from lp.bugs.model.bugtask import BugTask | 17 | from lp.bugs.model.bugtask import BugTask |
358 | 17 | from lp.bugs.model.cve import Cve as CveModel | 18 | from lp.bugs.model.cve import Cve as CveModel |
359 | @@ -173,6 +174,13 @@ class UCTExporter: | |||
360 | 173 | ) | 174 | ) |
361 | 174 | ) | 175 | ) |
362 | 175 | 176 | ||
363 | 177 | bug_presence_by_product = defaultdict(list) | ||
364 | 178 | for bp in getUtility(IBugPresenceSet).getByBug(bug): | ||
365 | 179 | if bp.git_repository: | ||
366 | 180 | bug_presence_by_product[ | ||
367 | 181 | removeSecurityProxy(bp).git_repository.project | ||
368 | 182 | ].append(bp) | ||
369 | 183 | |||
370 | 176 | upstream_packages = [] | 184 | upstream_packages = [] |
371 | 177 | for bug_task in bug_tasks: | 185 | for bug_task in bug_tasks: |
372 | 178 | target = removeSecurityProxy(bug_task.target) | 186 | target = removeSecurityProxy(bug_task.target) |
373 | @@ -187,6 +195,7 @@ class UCTExporter: | |||
374 | 187 | package_name = package_name_by_product[target] | 195 | package_name = package_name_by_product[target] |
375 | 188 | up_importance = bug_task.importance | 196 | up_importance = bug_task.importance |
376 | 189 | package_importance = package_importances.get(target.name) | 197 | package_importance = package_importances.get(target.name) |
377 | 198 | bug_presences = bug_presence_by_product.get(target, []) | ||
378 | 190 | upstream_packages.append( | 199 | upstream_packages.append( |
379 | 191 | CVE.UpstreamPackage( | 200 | CVE.UpstreamPackage( |
380 | 192 | target=target, | 201 | target=target, |
381 | @@ -198,6 +207,13 @@ class UCTExporter: | |||
382 | 198 | ), | 207 | ), |
383 | 199 | status=bug_task.status, | 208 | status=bug_task.status, |
384 | 200 | status_explanation=bug_task.status_explanation, | 209 | status_explanation=bug_task.status_explanation, |
385 | 210 | break_fixes=[ | ||
386 | 211 | CVE.BreakFix( | ||
387 | 212 | broken_git_commit_sha1=bp.broken_git_commit_sha1, | ||
388 | 213 | fixed_git_commit_sha1=bp.fixed_git_commit_sha1, | ||
389 | 214 | ) | ||
390 | 215 | for bp in bug_presences | ||
391 | 216 | ], | ||
392 | 201 | ) | 217 | ) |
393 | 202 | ) | 218 | ) |
394 | 203 | 219 | ||
395 | diff --git a/lib/lp/bugs/scripts/uct/uctimport.py b/lib/lp/bugs/scripts/uct/uctimport.py | |||
396 | index 5bc8411..607dd2e 100644 | |||
397 | --- a/lib/lp/bugs/scripts/uct/uctimport.py | |||
398 | +++ b/lib/lp/bugs/scripts/uct/uctimport.py | |||
399 | @@ -25,6 +25,7 @@ Three types of bug tags are created: | |||
400 | 25 | status of the package in upstream. | 25 | status of the package in upstream. |
401 | 26 | """ | 26 | """ |
402 | 27 | import logging | 27 | import logging |
403 | 28 | from collections import defaultdict | ||
404 | 28 | from datetime import timezone | 29 | from datetime import timezone |
405 | 29 | from itertools import chain | 30 | from itertools import chain |
406 | 30 | from pathlib import Path | 31 | from pathlib import Path |
407 | @@ -39,6 +40,7 @@ from lp.app.interfaces.launchpad import ILaunchpadCelebrities | |||
408 | 39 | from lp.bugs.interfaces.bug import CreateBugParams, IBugSet | 40 | from lp.bugs.interfaces.bug import CreateBugParams, IBugSet |
409 | 40 | from lp.bugs.interfaces.bugactivity import IBugActivitySet | 41 | from lp.bugs.interfaces.bugactivity import IBugActivitySet |
410 | 41 | from lp.bugs.interfaces.bugattachment import BugAttachmentType | 42 | from lp.bugs.interfaces.bugattachment import BugAttachmentType |
411 | 43 | from lp.bugs.interfaces.bugpresence import IBugPresenceSet | ||
412 | 42 | from lp.bugs.interfaces.bugtask import BugTaskImportance, IBugTaskSet | 44 | from lp.bugs.interfaces.bugtask import BugTaskImportance, IBugTaskSet |
413 | 43 | from lp.bugs.interfaces.bugwatch import IBugWatchSet | 45 | from lp.bugs.interfaces.bugwatch import IBugWatchSet |
414 | 44 | from lp.bugs.interfaces.cve import ICveSet | 46 | from lp.bugs.interfaces.cve import ICveSet |
415 | @@ -48,6 +50,7 @@ from lp.bugs.model.bugtask import BugTask | |||
416 | 48 | from lp.bugs.model.cve import Cve as CveModel | 50 | from lp.bugs.model.cve import Cve as CveModel |
417 | 49 | from lp.bugs.model.vulnerability import Vulnerability | 51 | from lp.bugs.model.vulnerability import Vulnerability |
418 | 50 | from lp.bugs.scripts.uct.models import CVE, UCTRecord | 52 | from lp.bugs.scripts.uct.models import CVE, UCTRecord |
419 | 53 | from lp.code.interfaces.gitrepository import IGitRepositorySet | ||
420 | 51 | from lp.registry.model.distribution import Distribution | 54 | from lp.registry.model.distribution import Distribution |
421 | 52 | from lp.registry.model.person import Person | 55 | from lp.registry.model.person import Person |
422 | 53 | from lp.services.database.constants import UTC_NOW | 56 | from lp.services.database.constants import UTC_NOW |
423 | @@ -168,6 +171,7 @@ class UCTImporter: | |||
424 | 168 | 171 | ||
425 | 169 | self._update_external_bug_urls(bug, cve.bug_urls) | 172 | self._update_external_bug_urls(bug, cve.bug_urls) |
426 | 170 | self._update_patches(bug, cve.patch_urls) | 173 | self._update_patches(bug, cve.patch_urls) |
427 | 174 | self._update_bug_presence(bug, cve.upstream_packages) | ||
428 | 171 | 175 | ||
429 | 172 | self._create_bug_tasks( | 176 | self._create_bug_tasks( |
430 | 173 | bug, | 177 | bug, |
431 | @@ -225,6 +229,7 @@ class UCTImporter: | |||
432 | 225 | self._assign_bug_tasks(bug, cve.assignee) | 229 | self._assign_bug_tasks(bug, cve.assignee) |
433 | 226 | self._update_external_bug_urls(bug, cve.bug_urls) | 230 | self._update_external_bug_urls(bug, cve.bug_urls) |
434 | 227 | self._update_patches(bug, cve.patch_urls) | 231 | self._update_patches(bug, cve.patch_urls) |
435 | 232 | self._update_bug_presence(bug, cve.upstream_packages) | ||
436 | 228 | 233 | ||
437 | 229 | # Update or add new Vulnerabilities | 234 | # Update or add new Vulnerabilities |
438 | 230 | vulnerabilities_by_distro = { | 235 | vulnerabilities_by_distro = { |
439 | @@ -455,6 +460,47 @@ class UCTImporter: | |||
440 | 455 | description=title, | 460 | description=title, |
441 | 456 | ) | 461 | ) |
442 | 457 | 462 | ||
443 | 463 | def _update_bug_presence( | ||
444 | 464 | self, bug: BugModel, upstream_packages: List[CVE.UpstreamPackage] | ||
445 | 465 | ): | ||
446 | 466 | bug_presence_set = getUtility(IBugPresenceSet) | ||
447 | 467 | bug_presences_by_target = defaultdict(list) | ||
448 | 468 | for bp in bug_presence_set.getByBug(bug): | ||
449 | 469 | bug_presences_by_target[bp.target].append(bp) | ||
450 | 470 | for upstream_package in upstream_packages: | ||
451 | 471 | if not upstream_package.break_fixes: | ||
452 | 472 | continue | ||
453 | 473 | git_repo = getUtility(IGitRepositorySet).getDefaultRepository( | ||
454 | 474 | upstream_package.target | ||
455 | 475 | ) | ||
456 | 476 | |||
457 | 477 | if not git_repo: | ||
458 | 478 | logger.error( | ||
459 | 479 | "Could not find a git repository for %s " | ||
460 | 480 | "to save bug presence information", | ||
461 | 481 | upstream_package.target.name, | ||
462 | 482 | ) | ||
463 | 483 | continue | ||
464 | 484 | |||
465 | 485 | existing_break_fixes = set() | ||
466 | 486 | for bp in bug_presences_by_target.get(git_repo, []): | ||
467 | 487 | existing_break_fixes.add( | ||
468 | 488 | CVE.BreakFix( | ||
469 | 489 | broken_git_commit_sha1=bp.broken_git_commit_sha1, | ||
470 | 490 | fixed_git_commit_sha1=bp.fixed_git_commit_sha1, | ||
471 | 491 | ) | ||
472 | 492 | ) | ||
473 | 493 | |||
474 | 494 | for break_fix in upstream_package.break_fixes: | ||
475 | 495 | if break_fix is existing_break_fixes: | ||
476 | 496 | continue | ||
477 | 497 | bug_presence_set.new( | ||
478 | 498 | bug=bug, | ||
479 | 499 | target=git_repo, | ||
480 | 500 | broken_git_commit_sha1=break_fix.broken_git_commit_sha1, | ||
481 | 501 | fixed_git_commit_sha1=break_fix.fixed_git_commit_sha1, | ||
482 | 502 | ) | ||
483 | 503 | |||
484 | 458 | def _make_bug_description(self, cve: CVE) -> str: | 504 | def _make_bug_description(self, cve: CVE) -> str: |
485 | 459 | """ | 505 | """ |
486 | 460 | Some `CVE` fields can't be mapped to Launchpad models. | 506 | Some `CVE` fields can't be mapped to Launchpad models. |