Merge ~cjwatson/launchpad:issue-private-archive-macaroons into launchpad:master
- Git
- lp:~cjwatson/launchpad
- issue-private-archive-macaroons
- Merge into master
Proposed by
Colin Watson
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Colin Watson | ||||
Approved revision: | c7054367d530f8d2188f5330a9ebbf0163ce88fe | ||||
Merge reported by: | Otto Co-Pilot | ||||
Merged at revision: | not available | ||||
Proposed branch: | ~cjwatson/launchpad:issue-private-archive-macaroons | ||||
Merge into: | launchpad:master | ||||
Prerequisite: | ~cjwatson/launchpad:get-sources-list-accept-behaviour | ||||
Diff against target: |
402 lines (+147/-24) 10 files modified
lib/lp/buildmaster/interfaces/buildfarmjobbehaviour.py (+9/-0) lib/lp/buildmaster/model/buildfarmjobbehaviour.py (+4/-0) lib/lp/oci/model/ocirecipebuildbehaviour.py (+9/-5) lib/lp/snappy/model/snapbuildbehaviour.py (+8/-4) lib/lp/snappy/tests/test_snapbuildbehaviour.py (+55/-0) lib/lp/soyuz/adapters/archivedependencies.py (+11/-8) lib/lp/soyuz/model/binarypackagebuildbehaviour.py (+10/-0) lib/lp/soyuz/model/livefsbuildbehaviour.py (+9/-0) lib/lp/soyuz/tests/test_archive.py (+29/-7) system-packages.txt (+3/-0) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ioana Lasc (community) | Approve | ||
Review via email: mp+401323@code.launchpad.net |
Commit message
Dispatch sources.list entries for private archives using macaroons
Description of the change
This allows snap base archive dependencies on private archives to work (for 16.04 ESM), and also takes a significant step towards abolishing `Archive.
The old buildd secret is still used in the file map passed to builders to fetch the source package for binary package builds in private archives, so it can't yet be removed entirely.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/buildmaster/interfaces/buildfarmjobbehaviour.py b/lib/lp/buildmaster/interfaces/buildfarmjobbehaviour.py | |||
2 | index 4d768d8..d210d64 100644 | |||
3 | --- a/lib/lp/buildmaster/interfaces/buildfarmjobbehaviour.py | |||
4 | +++ b/lib/lp/buildmaster/interfaces/buildfarmjobbehaviour.py | |||
5 | @@ -46,6 +46,15 @@ class IBuildFarmJobBehaviour(Interface): | |||
6 | 46 | 'password' (optional): password to authenticate with | 46 | 'password' (optional): password to authenticate with |
7 | 47 | """ | 47 | """ |
8 | 48 | 48 | ||
9 | 49 | def issueMacaroon(): | ||
10 | 50 | """Issue a macaroon to access private resources for this build. | ||
11 | 51 | |||
12 | 52 | :raises NotImplementedError: if the build type does not support | ||
13 | 53 | accessing private resources. | ||
14 | 54 | :return: A Deferred that calls back with a serialized macaroon or a | ||
15 | 55 | fault. | ||
16 | 56 | """ | ||
17 | 57 | |||
18 | 49 | def extraBuildArgs(logger=None): | 58 | def extraBuildArgs(logger=None): |
19 | 50 | """Return extra arguments required by the builder for this build. | 59 | """Return extra arguments required by the builder for this build. |
20 | 51 | 60 | ||
21 | diff --git a/lib/lp/buildmaster/model/buildfarmjobbehaviour.py b/lib/lp/buildmaster/model/buildfarmjobbehaviour.py | |||
22 | index f8b5034..e0d5380 100644 | |||
23 | --- a/lib/lp/buildmaster/model/buildfarmjobbehaviour.py | |||
24 | +++ b/lib/lp/buildmaster/model/buildfarmjobbehaviour.py | |||
25 | @@ -89,6 +89,10 @@ class BuildFarmJobBehaviourBase: | |||
26 | 89 | """The default behaviour is to send no files.""" | 89 | """The default behaviour is to send no files.""" |
27 | 90 | return {} | 90 | return {} |
28 | 91 | 91 | ||
29 | 92 | def issueMacaroon(self): | ||
30 | 93 | raise NotImplementedError( | ||
31 | 94 | "This build type does not support accessing private resources.") | ||
32 | 95 | |||
33 | 92 | def extraBuildArgs(self, logger=None): | 96 | def extraBuildArgs(self, logger=None): |
34 | 93 | """The default behaviour is to send only common extra arguments.""" | 97 | """The default behaviour is to send only common extra arguments.""" |
35 | 94 | args = {} | 98 | args = {} |
36 | diff --git a/lib/lp/oci/model/ocirecipebuildbehaviour.py b/lib/lp/oci/model/ocirecipebuildbehaviour.py | |||
37 | index e8a60f5..0ca766d 100644 | |||
38 | --- a/lib/lp/oci/model/ocirecipebuildbehaviour.py | |||
39 | +++ b/lib/lp/oci/model/ocirecipebuildbehaviour.py | |||
40 | @@ -80,6 +80,14 @@ class OCIRecipeBuildBehaviour(SnapProxyMixin, BuildFarmJobBehaviourBase): | |||
41 | 80 | raise CannotBuild( | 80 | raise CannotBuild( |
42 | 81 | "Missing chroot for %s" % build.distro_arch_series.displayname) | 81 | "Missing chroot for %s" % build.distro_arch_series.displayname) |
43 | 82 | 82 | ||
44 | 83 | def issueMacaroon(self): | ||
45 | 84 | """See `IBuildFarmJobBehaviour`.""" | ||
46 | 85 | return cancel_on_timeout( | ||
47 | 86 | self._authserver.callRemote( | ||
48 | 87 | "issueMacaroon", | ||
49 | 88 | "oci-recipe-build", "OCIRecipeBuild", self.build.id), | ||
50 | 89 | config.builddmaster.authentication_timeout) | ||
51 | 90 | |||
52 | 83 | def _getBuildInfoArgs(self): | 91 | def _getBuildInfoArgs(self): |
53 | 84 | def format_user(user): | 92 | def format_user(user): |
54 | 85 | if user is None: | 93 | if user is None: |
55 | @@ -142,11 +150,7 @@ class OCIRecipeBuildBehaviour(SnapProxyMixin, BuildFarmJobBehaviourBase): | |||
56 | 142 | 150 | ||
57 | 143 | if build.recipe.git_ref is not None: | 151 | if build.recipe.git_ref is not None: |
58 | 144 | if build.recipe.git_repository.private: | 152 | if build.recipe.git_repository.private: |
64 | 145 | macaroon_raw = yield cancel_on_timeout( | 153 | macaroon_raw = yield self.issueMacaroon() |
60 | 146 | self._authserver.callRemote( | ||
61 | 147 | "issueMacaroon", | ||
62 | 148 | "oci-recipe-build", "OCIRecipeBuild", build.id), | ||
63 | 149 | config.builddmaster.authentication_timeout) | ||
65 | 150 | url = build.recipe.git_repository.getCodebrowseUrl( | 154 | url = build.recipe.git_repository.getCodebrowseUrl( |
66 | 151 | username=None, password=macaroon_raw) | 155 | username=None, password=macaroon_raw) |
67 | 152 | args["git_repository"] = url | 156 | args["git_repository"] = url |
68 | diff --git a/lib/lp/snappy/model/snapbuildbehaviour.py b/lib/lp/snappy/model/snapbuildbehaviour.py | |||
69 | index dda949b..0057670 100644 | |||
70 | --- a/lib/lp/snappy/model/snapbuildbehaviour.py | |||
71 | +++ b/lib/lp/snappy/model/snapbuildbehaviour.py | |||
72 | @@ -145,6 +145,13 @@ class SnapBuildBehaviour(SnapProxyMixin, BuildFarmJobBehaviourBase): | |||
73 | 145 | raise CannotBuild( | 145 | raise CannotBuild( |
74 | 146 | "Missing chroot for %s" % build.distro_arch_series.displayname) | 146 | "Missing chroot for %s" % build.distro_arch_series.displayname) |
75 | 147 | 147 | ||
76 | 148 | def issueMacaroon(self): | ||
77 | 149 | """See `IBuildFarmJobBehaviour`.""" | ||
78 | 150 | return cancel_on_timeout( | ||
79 | 151 | self._authserver.callRemote( | ||
80 | 152 | "issueMacaroon", "snap-build", "SnapBuild", self.build.id), | ||
81 | 153 | config.builddmaster.authentication_timeout) | ||
82 | 154 | |||
83 | 148 | @defer.inlineCallbacks | 155 | @defer.inlineCallbacks |
84 | 149 | def extraBuildArgs(self, logger=None): | 156 | def extraBuildArgs(self, logger=None): |
85 | 150 | """ | 157 | """ |
86 | @@ -186,10 +193,7 @@ class SnapBuildBehaviour(SnapProxyMixin, BuildFarmJobBehaviourBase): | |||
87 | 186 | if build.snap.git_ref.repository_url is not None: | 193 | if build.snap.git_ref.repository_url is not None: |
88 | 187 | args["git_repository"] = build.snap.git_ref.repository_url | 194 | args["git_repository"] = build.snap.git_ref.repository_url |
89 | 188 | elif build.snap.git_repository.private: | 195 | elif build.snap.git_repository.private: |
94 | 189 | macaroon_raw = yield cancel_on_timeout( | 196 | macaroon_raw = yield self.issueMacaroon() |
91 | 190 | self._authserver.callRemote( | ||
92 | 191 | "issueMacaroon", "snap-build", "SnapBuild", build.id), | ||
93 | 192 | config.builddmaster.authentication_timeout) | ||
95 | 193 | url = build.snap.git_repository.getCodebrowseUrl( | 197 | url = build.snap.git_repository.getCodebrowseUrl( |
96 | 194 | username=None, password=macaroon_raw) | 198 | username=None, password=macaroon_raw) |
97 | 195 | args["git_repository"] = url | 199 | args["git_repository"] = url |
98 | diff --git a/lib/lp/snappy/tests/test_snapbuildbehaviour.py b/lib/lp/snappy/tests/test_snapbuildbehaviour.py | |||
99 | index 1d80326..0deebed 100644 | |||
100 | --- a/lib/lp/snappy/tests/test_snapbuildbehaviour.py | |||
101 | +++ b/lib/lp/snappy/tests/test_snapbuildbehaviour.py | |||
102 | @@ -14,6 +14,7 @@ from textwrap import dedent | |||
103 | 14 | import time | 14 | import time |
104 | 15 | import uuid | 15 | import uuid |
105 | 16 | 16 | ||
106 | 17 | from aptsources.sourceslist import SourceEntry | ||
107 | 17 | import fixtures | 18 | import fixtures |
108 | 18 | from pymacaroons import Macaroon | 19 | from pymacaroons import Macaroon |
109 | 19 | import pytz | 20 | import pytz |
110 | @@ -77,6 +78,7 @@ from lp.services.log.logger import ( | |||
111 | 77 | BufferLogger, | 78 | BufferLogger, |
112 | 78 | DevNullLogger, | 79 | DevNullLogger, |
113 | 79 | ) | 80 | ) |
114 | 81 | from lp.services.macaroons.testing import MacaroonVerifies | ||
115 | 80 | from lp.services.statsd.tests import StatsMixin | 82 | from lp.services.statsd.tests import StatsMixin |
116 | 81 | from lp.services.webapp import canonical_url | 83 | from lp.services.webapp import canonical_url |
117 | 82 | from lp.snappy.interfaces.snap import ( | 84 | from lp.snappy.interfaces.snap import ( |
118 | @@ -790,6 +792,59 @@ class TestAsyncSnapBuildBehaviour(StatsMixin, TestSnapBuildBehaviourBase): | |||
119 | 790 | self.assertEqual(expected_archives, args["archives"]) | 792 | self.assertEqual(expected_archives, args["archives"]) |
120 | 791 | 793 | ||
121 | 792 | @defer.inlineCallbacks | 794 | @defer.inlineCallbacks |
122 | 795 | def test_extraBuildArgs_snap_base_with_private_archive_dependencies(self): | ||
123 | 796 | # If the build is using a snap base that has archive dependencies on | ||
124 | 797 | # private PPAs, extraBuildArgs sends them. | ||
125 | 798 | self.useFixture(InProcessAuthServerFixture()) | ||
126 | 799 | self.pushConfig( | ||
127 | 800 | "launchpad", internal_macaroon_secret_key="some-secret") | ||
128 | 801 | snap_base = self.factory.makeSnapBase() | ||
129 | 802 | job = self.makeJob(snap_base=snap_base) | ||
130 | 803 | dependency = self.factory.makeArchive( | ||
131 | 804 | distribution=job.archive.distribution, private=True) | ||
132 | 805 | snap_base.addArchiveDependency( | ||
133 | 806 | dependency, PackagePublishingPocket.RELEASE, | ||
134 | 807 | getUtility(IComponentSet)["main"]) | ||
135 | 808 | self.factory.makeBinaryPackagePublishingHistory( | ||
136 | 809 | archive=dependency, distroarchseries=job.build.distro_arch_series, | ||
137 | 810 | pocket=PackagePublishingPocket.RELEASE, | ||
138 | 811 | status=PackagePublishingStatus.PUBLISHED) | ||
139 | 812 | with dbuser(config.builddmaster.dbuser): | ||
140 | 813 | args = yield job.extraBuildArgs() | ||
141 | 814 | job.build.updateStatus(BuildStatus.BUILDING) | ||
142 | 815 | self.assertThat( | ||
143 | 816 | [SourceEntry(item) for item in args["archives"]], | ||
144 | 817 | MatchesListwise([ | ||
145 | 818 | MatchesStructure( | ||
146 | 819 | type=Equals("deb"), | ||
147 | 820 | uri=AfterPreprocessing(urlsplit, MatchesStructure( | ||
148 | 821 | scheme=Equals("http"), | ||
149 | 822 | username=Equals("buildd"), | ||
150 | 823 | password=MacaroonVerifies("snap-build", dependency), | ||
151 | 824 | hostname=Equals("private-ppa.launchpad.test"), | ||
152 | 825 | path=Equals("/%s/%s/%s" % ( | ||
153 | 826 | dependency.owner.name, dependency.name, | ||
154 | 827 | dependency.distribution.name)))), | ||
155 | 828 | dist=Equals(job.build.distro_series.name), | ||
156 | 829 | comps=Equals(["main"])), | ||
157 | 830 | MatchesStructure.byEquality( | ||
158 | 831 | type="deb", | ||
159 | 832 | uri=job.archive.archive_url, | ||
160 | 833 | dist=job.build.distro_series.name, | ||
161 | 834 | comps=["main", "universe"]), | ||
162 | 835 | MatchesStructure.byEquality( | ||
163 | 836 | type="deb", | ||
164 | 837 | uri=job.archive.archive_url, | ||
165 | 838 | dist="%s-security" % job.build.distro_series.name, | ||
166 | 839 | comps=["main", "universe"]), | ||
167 | 840 | MatchesStructure.byEquality( | ||
168 | 841 | type="deb", | ||
169 | 842 | uri=job.archive.archive_url, | ||
170 | 843 | dist="%s-updates" % job.build.distro_series.name, | ||
171 | 844 | comps=["main", "universe"]), | ||
172 | 845 | ])) | ||
173 | 846 | |||
174 | 847 | @defer.inlineCallbacks | ||
175 | 793 | def test_extraBuildArgs_ppa_and_snap_base_with_archive_dependencies(self): | 848 | def test_extraBuildArgs_ppa_and_snap_base_with_archive_dependencies(self): |
176 | 794 | # If the build is using a PPA and a snap base that both have archive | 849 | # If the build is using a PPA and a snap base that both have archive |
177 | 795 | # dependencies, extraBuildArgs sends them all. | 850 | # dependencies, extraBuildArgs sends them all. |
178 | diff --git a/lib/lp/soyuz/adapters/archivedependencies.py b/lib/lp/soyuz/adapters/archivedependencies.py | |||
179 | index ff1d117..685a82e 100644 | |||
180 | --- a/lib/lp/soyuz/adapters/archivedependencies.py | |||
181 | +++ b/lib/lp/soyuz/adapters/archivedependencies.py | |||
182 | @@ -290,7 +290,8 @@ def get_sources_list_for_building(behaviour, distroarchseries, | |||
183 | 290 | tools_source=tools_source, tools_fingerprint=tools_fingerprint, | 290 | tools_source=tools_source, tools_fingerprint=tools_fingerprint, |
184 | 291 | logger=logger) | 291 | logger=logger) |
185 | 292 | sources_list_lines, trusted_keys = ( | 292 | sources_list_lines, trusted_keys = ( |
187 | 293 | yield _get_sources_list_for_dependencies(deps, logger=logger)) | 293 | yield _get_sources_list_for_dependencies( |
188 | 294 | behaviour, deps, logger=logger)) | ||
189 | 294 | 295 | ||
190 | 295 | external_dep_lines = [] | 296 | external_dep_lines = [] |
191 | 296 | # Append external sources.list lines for this build if specified. No | 297 | # Append external sources.list lines for this build if specified. No |
192 | @@ -343,7 +344,8 @@ def _has_published_binaries(archive, distroarchseries, pocket): | |||
193 | 343 | return not published_binaries.is_empty() | 344 | return not published_binaries.is_empty() |
194 | 344 | 345 | ||
195 | 345 | 346 | ||
197 | 346 | def _get_binary_sources_list_line(archive, distroarchseries, pocket, | 347 | @defer.inlineCallbacks |
198 | 348 | def _get_binary_sources_list_line(behaviour, archive, distroarchseries, pocket, | ||
199 | 347 | components): | 349 | components): |
200 | 348 | """Return the correponding binary sources_list line.""" | 350 | """Return the correponding binary sources_list line.""" |
201 | 349 | # Encode the private PPA repository password in the | 351 | # Encode the private PPA repository password in the |
202 | @@ -351,23 +353,24 @@ def _get_binary_sources_list_line(archive, distroarchseries, pocket, | |||
203 | 351 | # sanitized to not expose it. | 353 | # sanitized to not expose it. |
204 | 352 | if archive.private: | 354 | if archive.private: |
205 | 353 | uri = URI(archive.archive_url) | 355 | uri = URI(archive.archive_url) |
208 | 354 | uri = uri.replace( | 356 | macaroon_raw = yield behaviour.issueMacaroon() |
209 | 355 | userinfo="buildd:%s" % archive.buildd_secret) | 357 | uri = uri.replace(userinfo="buildd:%s" % macaroon_raw) |
210 | 356 | url = str(uri) | 358 | url = str(uri) |
211 | 357 | else: | 359 | else: |
212 | 358 | url = archive.archive_url | 360 | url = archive.archive_url |
213 | 359 | 361 | ||
214 | 360 | suite = distroarchseries.distroseries.name + pocketsuffix[pocket] | 362 | suite = distroarchseries.distroseries.name + pocketsuffix[pocket] |
216 | 361 | return 'deb %s %s %s' % (url, suite, ' '.join(components)) | 363 | defer.returnValue('deb %s %s %s' % (url, suite, ' '.join(components))) |
217 | 362 | 364 | ||
218 | 363 | 365 | ||
219 | 364 | @defer.inlineCallbacks | 366 | @defer.inlineCallbacks |
221 | 365 | def _get_sources_list_for_dependencies(dependencies, logger=None): | 367 | def _get_sources_list_for_dependencies(behaviour, dependencies, logger=None): |
222 | 366 | """Return sources.list entries and keys. | 368 | """Return sources.list entries and keys. |
223 | 367 | 369 | ||
224 | 368 | Process the given list of dependency tuples for the given | 370 | Process the given list of dependency tuples for the given |
225 | 369 | `DistroArchseries`. | 371 | `DistroArchseries`. |
226 | 370 | 372 | ||
227 | 373 | :param behaviour: the build's `IBuildFarmJobBehaviour`. | ||
228 | 371 | :param dependencies: list of 3 elements tuples as: | 374 | :param dependencies: list of 3 elements tuples as: |
229 | 372 | (`IArchive`, `IDistroArchSeries`, `PackagePublishingPocket`, | 375 | (`IArchive`, `IDistroArchSeries`, `PackagePublishingPocket`, |
230 | 373 | list of `IComponent` names) | 376 | list of `IComponent` names) |
231 | @@ -399,8 +402,8 @@ def _get_sources_list_for_dependencies(dependencies, logger=None): | |||
232 | 399 | components = [ | 402 | components = [ |
233 | 400 | component for component in components | 403 | component for component in components |
234 | 401 | if component in archive_components] | 404 | if component in archive_components] |
237 | 402 | sources_list_line = _get_binary_sources_list_line( | 405 | sources_list_line = yield _get_binary_sources_list_line( |
238 | 403 | archive, distro_arch_series, pocket, components) | 406 | behaviour, archive, distro_arch_series, pocket, components) |
239 | 404 | sources_list_lines.append(sources_list_line) | 407 | sources_list_lines.append(sources_list_line) |
240 | 405 | fingerprint = archive.signing_key_fingerprint | 408 | fingerprint = archive.signing_key_fingerprint |
241 | 406 | if fingerprint is not None and fingerprint not in trusted_keys: | 409 | if fingerprint is not None and fingerprint not in trusted_keys: |
242 | diff --git a/lib/lp/soyuz/model/binarypackagebuildbehaviour.py b/lib/lp/soyuz/model/binarypackagebuildbehaviour.py | |||
243 | index 6b74f46..2876ac0 100644 | |||
244 | --- a/lib/lp/soyuz/model/binarypackagebuildbehaviour.py | |||
245 | +++ b/lib/lp/soyuz/model/binarypackagebuildbehaviour.py | |||
246 | @@ -22,6 +22,8 @@ from lp.buildmaster.model.buildfarmjobbehaviour import ( | |||
247 | 22 | BuildFarmJobBehaviourBase, | 22 | BuildFarmJobBehaviourBase, |
248 | 23 | ) | 23 | ) |
249 | 24 | from lp.registry.interfaces.pocket import PackagePublishingPocket | 24 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
250 | 25 | from lp.services.config import config | ||
251 | 26 | from lp.services.twistedsupport import cancel_on_timeout | ||
252 | 25 | from lp.services.webapp import urlappend | 27 | from lp.services.webapp import urlappend |
253 | 26 | from lp.soyuz.adapters.archivedependencies import ( | 28 | from lp.soyuz.adapters.archivedependencies import ( |
254 | 27 | get_primary_current_component, | 29 | get_primary_current_component, |
255 | @@ -131,6 +133,14 @@ class BinaryPackageBuildBehaviour(BuildFarmJobBehaviourBase): | |||
256 | 131 | (build.title, build.id, build.pocket.name, | 133 | (build.title, build.id, build.pocket.name, |
257 | 132 | build.distro_series.name)) | 134 | build.distro_series.name)) |
258 | 133 | 135 | ||
259 | 136 | def issueMacaroon(self): | ||
260 | 137 | """See `IBuildFarmJobBehaviour`.""" | ||
261 | 138 | return cancel_on_timeout( | ||
262 | 139 | self._authserver.callRemote( | ||
263 | 140 | "issueMacaroon", "binary-package-build", "BinaryPackageBuild", | ||
264 | 141 | self.build.id), | ||
265 | 142 | config.builddmaster.authentication_timeout) | ||
266 | 143 | |||
267 | 134 | @defer.inlineCallbacks | 144 | @defer.inlineCallbacks |
268 | 135 | def extraBuildArgs(self, logger=None): | 145 | def extraBuildArgs(self, logger=None): |
269 | 136 | """ | 146 | """ |
270 | diff --git a/lib/lp/soyuz/model/livefsbuildbehaviour.py b/lib/lp/soyuz/model/livefsbuildbehaviour.py | |||
271 | index c439559..0f93d39 100644 | |||
272 | --- a/lib/lp/soyuz/model/livefsbuildbehaviour.py | |||
273 | +++ b/lib/lp/soyuz/model/livefsbuildbehaviour.py | |||
274 | @@ -25,6 +25,8 @@ from lp.buildmaster.model.buildfarmjobbehaviour import ( | |||
275 | 25 | BuildFarmJobBehaviourBase, | 25 | BuildFarmJobBehaviourBase, |
276 | 26 | ) | 26 | ) |
277 | 27 | from lp.registry.interfaces.series import SeriesStatus | 27 | from lp.registry.interfaces.series import SeriesStatus |
278 | 28 | from lp.services.config import config | ||
279 | 29 | from lp.services.twistedsupport import cancel_on_timeout | ||
280 | 28 | from lp.soyuz.adapters.archivedependencies import ( | 30 | from lp.soyuz.adapters.archivedependencies import ( |
281 | 29 | get_sources_list_for_building, | 31 | get_sources_list_for_building, |
282 | 30 | ) | 32 | ) |
283 | @@ -78,6 +80,13 @@ class LiveFSBuildBehaviour(BuildFarmJobBehaviourBase): | |||
284 | 78 | raise CannotBuild( | 80 | raise CannotBuild( |
285 | 79 | "Missing chroot for %s" % build.distro_arch_series.displayname) | 81 | "Missing chroot for %s" % build.distro_arch_series.displayname) |
286 | 80 | 82 | ||
287 | 83 | def issueMacaroon(self): | ||
288 | 84 | """See `IBuildFarmJobBehaviour`.""" | ||
289 | 85 | return cancel_on_timeout( | ||
290 | 86 | self._authserver.callRemote( | ||
291 | 87 | "issueMacaroon", "livefs-build", "LiveFSBuild", self.build.id), | ||
292 | 88 | config.builddmaster.authentication_timeout) | ||
293 | 89 | |||
294 | 81 | @defer.inlineCallbacks | 90 | @defer.inlineCallbacks |
295 | 82 | def extraBuildArgs(self, logger=None): | 91 | def extraBuildArgs(self, logger=None): |
296 | 83 | """ | 92 | """ |
297 | diff --git a/lib/lp/soyuz/tests/test_archive.py b/lib/lp/soyuz/tests/test_archive.py | |||
298 | index a49ccd3..2d53207 100644 | |||
299 | --- a/lib/lp/soyuz/tests/test_archive.py | |||
300 | +++ b/lib/lp/soyuz/tests/test_archive.py | |||
301 | @@ -13,22 +13,28 @@ from datetime import ( | |||
302 | 13 | import doctest | 13 | import doctest |
303 | 14 | import os.path | 14 | import os.path |
304 | 15 | 15 | ||
305 | 16 | from aptsources.sourceslist import SourceEntry | ||
306 | 16 | from pytz import UTC | 17 | from pytz import UTC |
307 | 17 | import responses | 18 | import responses |
308 | 18 | import six | 19 | import six |
309 | 19 | from six.moves import http_client | 20 | from six.moves import http_client |
310 | 21 | from six.moves.urllib.parse import urlsplit | ||
311 | 20 | from storm.store import Store | 22 | from storm.store import Store |
312 | 21 | from testtools.matchers import ( | 23 | from testtools.matchers import ( |
313 | 24 | AfterPreprocessing, | ||
314 | 22 | AllMatch, | 25 | AllMatch, |
315 | 23 | DocTestMatches, | 26 | DocTestMatches, |
316 | 27 | Equals, | ||
317 | 24 | LessThan, | 28 | LessThan, |
318 | 25 | MatchesListwise, | 29 | MatchesListwise, |
319 | 26 | MatchesPredicate, | 30 | MatchesPredicate, |
320 | 27 | MatchesRegex, | ||
321 | 28 | MatchesStructure, | 31 | MatchesStructure, |
322 | 29 | ) | 32 | ) |
323 | 30 | from testtools.testcase import ExpectedException | 33 | from testtools.testcase import ExpectedException |
325 | 31 | from testtools.twistedsupport import AsynchronousDeferredRunTest | 34 | from testtools.twistedsupport import ( |
326 | 35 | AsynchronousDeferredRunTest, | ||
327 | 36 | AsynchronousDeferredRunTestForBrokenTwisted, | ||
328 | 37 | ) | ||
329 | 32 | import transaction | 38 | import transaction |
330 | 33 | from twisted.internet import defer | 39 | from twisted.internet import defer |
331 | 34 | from zope.component import getUtility | 40 | from zope.component import getUtility |
332 | @@ -57,6 +63,7 @@ from lp.registry.interfaces.person import IPersonSet | |||
333 | 57 | from lp.registry.interfaces.pocket import PackagePublishingPocket | 63 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
334 | 58 | from lp.registry.interfaces.series import SeriesStatus | 64 | from lp.registry.interfaces.series import SeriesStatus |
335 | 59 | from lp.registry.interfaces.teammembership import TeamMembershipStatus | 65 | from lp.registry.interfaces.teammembership import TeamMembershipStatus |
336 | 66 | from lp.services.authserver.testing import InProcessAuthServerFixture | ||
337 | 60 | from lp.services.database.interfaces import IStore | 67 | from lp.services.database.interfaces import IStore |
338 | 61 | from lp.services.database.sqlbase import sqlvalues | 68 | from lp.services.database.sqlbase import sqlvalues |
339 | 62 | from lp.services.features import getFeatureFlag | 69 | from lp.services.features import getFeatureFlag |
340 | @@ -67,6 +74,7 @@ from lp.services.gpg.interfaces import ( | |||
341 | 67 | IGPGHandler, | 74 | IGPGHandler, |
342 | 68 | ) | 75 | ) |
343 | 69 | from lp.services.job.interfaces.job import JobStatus | 76 | from lp.services.job.interfaces.job import JobStatus |
344 | 77 | from lp.services.macaroons.testing import MacaroonVerifies | ||
345 | 70 | from lp.services.propertycache import ( | 78 | from lp.services.propertycache import ( |
346 | 71 | clear_property_cache, | 79 | clear_property_cache, |
347 | 72 | get_property_cache, | 80 | get_property_cache, |
348 | @@ -1866,11 +1874,15 @@ class TestAddArchiveDependencies(TestCaseWithFactory): | |||
349 | 1866 | class TestArchiveDependencies(TestCaseWithFactory): | 1874 | class TestArchiveDependencies(TestCaseWithFactory): |
350 | 1867 | 1875 | ||
351 | 1868 | layer = LaunchpadZopelessLayer | 1876 | layer = LaunchpadZopelessLayer |
353 | 1869 | run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=30) | 1877 | run_tests_with = AsynchronousDeferredRunTestForBrokenTwisted.make_factory( |
354 | 1878 | timeout=30) | ||
355 | 1870 | 1879 | ||
356 | 1871 | @defer.inlineCallbacks | 1880 | @defer.inlineCallbacks |
357 | 1872 | def test_private_sources_list(self): | 1881 | def test_private_sources_list(self): |
358 | 1873 | """Entries for private dependencies include credentials.""" | 1882 | """Entries for private dependencies include credentials.""" |
359 | 1883 | self.useFixture(InProcessAuthServerFixture()) | ||
360 | 1884 | self.pushConfig( | ||
361 | 1885 | "launchpad", internal_macaroon_secret_key="some-secret") | ||
362 | 1874 | p3a = self.factory.makeArchive(name='p3a', private=True) | 1886 | p3a = self.factory.makeArchive(name='p3a', private=True) |
363 | 1875 | yield self.useFixture(InProcessKeyServerFixture()).start() | 1887 | yield self.useFixture(InProcessKeyServerFixture()).start() |
364 | 1876 | key_path = os.path.join(gpgkeysdir, 'ppa-sample@canonical.com.sec') | 1888 | key_path = os.path.join(gpgkeysdir, 'ppa-sample@canonical.com.sec') |
365 | @@ -1890,10 +1902,20 @@ class TestArchiveDependencies(TestCaseWithFactory): | |||
366 | 1890 | sources_list, trusted_keys = yield get_sources_list_for_building( | 1902 | sources_list, trusted_keys = yield get_sources_list_for_building( |
367 | 1891 | behaviour, build.distro_arch_series, | 1903 | behaviour, build.distro_arch_series, |
368 | 1892 | build.source_package_release.name) | 1904 | build.source_package_release.name) |
373 | 1893 | matches = MatchesRegex( | 1905 | # Mark the build as building so that we can verify its macaroons. |
374 | 1894 | "deb http://buildd:sekrit@private-ppa.launchpad.test/" | 1906 | build.updateStatus(BuildStatus.BUILDING) |
375 | 1895 | "person-name-.*/dependency/ubuntu distroseries-.* main") | 1907 | self.assertThat(SourceEntry(sources_list[0]), MatchesStructure( |
376 | 1896 | self.assertThat(sources_list[0], matches) | 1908 | type=Equals("deb"), |
377 | 1909 | uri=AfterPreprocessing(urlsplit, MatchesStructure( | ||
378 | 1910 | scheme=Equals("http"), | ||
379 | 1911 | username=Equals("buildd"), | ||
380 | 1912 | password=MacaroonVerifies("binary-package-build", p3a), | ||
381 | 1913 | hostname=Equals("private-ppa.launchpad.test"), | ||
382 | 1914 | path=Equals("/%s/dependency/ubuntu" % p3a.owner.name), | ||
383 | 1915 | )), | ||
384 | 1916 | dist=Equals(build.distro_series.getSuite(build.pocket)), | ||
385 | 1917 | comps=Equals(["main"]), | ||
386 | 1918 | )) | ||
387 | 1897 | self.assertThat(trusted_keys, MatchesListwise([ | 1919 | self.assertThat(trusted_keys, MatchesListwise([ |
388 | 1898 | Base64KeyMatches("0D57E99656BEFB0897606EE9A022DD1F5001B46D"), | 1920 | Base64KeyMatches("0D57E99656BEFB0897606EE9A022DD1F5001B46D"), |
389 | 1899 | ])) | 1921 | ])) |
390 | diff --git a/system-packages.txt b/system-packages.txt | |||
391 | index 84a8548..56a1291 100644 | |||
392 | --- a/system-packages.txt | |||
393 | +++ b/system-packages.txt | |||
394 | @@ -19,6 +19,9 @@ apt | |||
395 | 19 | apt_inst | 19 | apt_inst |
396 | 20 | apt_pkg | 20 | apt_pkg |
397 | 21 | 21 | ||
398 | 22 | # Used by tests to parse sources.list entries. | ||
399 | 23 | aptsources | ||
400 | 24 | |||
401 | 22 | # utilities/js-deps | 25 | # utilities/js-deps |
402 | 23 | convoy | 26 | convoy |
403 | 24 | 27 |
LGTM