Merge lp:~cjwatson/launchpad/snap-tools-fingerprint into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18408
Proposed branch: lp:~cjwatson/launchpad/snap-tools-fingerprint
Merge into: lp:launchpad
Diff against target: 207 lines (+59/-25)
5 files modified
lib/lp/services/config/schema-lazr.conf (+5/-0)
lib/lp/snappy/tests/test_snapbuildbehaviour.py (+1/-1)
lib/lp/soyuz/adapters/archivedependencies.py (+32/-22)
lib/lp/soyuz/adapters/tests/test_archivedependencies.py (+18/-2)
lib/lp/soyuz/tests/soyuz.py (+3/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad/snap-tools-fingerprint
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+325620@code.launchpad.net

Commit message

Allow configuring a fingerprint for the archive given in snappy.tools_source.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/services/config/schema-lazr.conf'
--- lib/lp/services/config/schema-lazr.conf 2017-06-01 12:05:30 +0000
+++ lib/lp/services/config/schema-lazr.conf 2017-06-14 08:12:16 +0000
@@ -1804,6 +1804,11 @@
1804# datatype: string1804# datatype: string
1805tools_source: none1805tools_source: none
18061806
1807# Optional OpenPGP signing key fingerprint for the archive given in
1808# tools_source.
1809# datatype: string
1810tools_fingerprint: none
1811
1807# The store's primary URL endpoint.1812# The store's primary URL endpoint.
1808store_url: none1813store_url: none
18091814
18101815
=== modified file 'lib/lp/snappy/tests/test_snapbuildbehaviour.py'
--- lib/lp/snappy/tests/test_snapbuildbehaviour.py 2017-06-13 17:08:16 +0000
+++ lib/lp/snappy/tests/test_snapbuildbehaviour.py 2017-06-14 08:12:16 +0000
@@ -69,7 +69,7 @@
6969
70 def setUp(self):70 def setUp(self):
71 super(TestSnapBuildBehaviourBase, self).setUp()71 super(TestSnapBuildBehaviourBase, self).setUp()
72 self.pushConfig("snappy", tools_source=None)72 self.pushConfig("snappy", tools_source=None, tools_fingerprint=None)
7373
74 def makeJob(self, archive=None, pocket=PackagePublishingPocket.UPDATES,74 def makeJob(self, archive=None, pocket=PackagePublishingPocket.UPDATES,
75 **kwargs):75 **kwargs):
7676
=== modified file 'lib/lp/soyuz/adapters/archivedependencies.py'
--- lib/lp/soyuz/adapters/archivedependencies.py 2017-04-29 23:51:28 +0000
+++ lib/lp/soyuz/adapters/archivedependencies.py 2017-06-14 08:12:16 +0000
@@ -153,7 +153,8 @@
153153
154154
155def expand_dependencies(archive, distro_arch_series, pocket, component,155def expand_dependencies(archive, distro_arch_series, pocket, component,
156 source_package_name, tools_source=None, logger=None):156 source_package_name, tools_source=None,
157 tools_fingerprint=None, logger=None):
157 """Return the set of dependency archives, pockets and components.158 """Return the set of dependency archives, pockets and components.
158159
159 :param archive: the context `IArchive`.160 :param archive: the context `IArchive`.
@@ -164,6 +165,8 @@
164 :param tools_source: if not None, a sources.list entry to use as an165 :param tools_source: if not None, a sources.list entry to use as an
165 additional dependency for build tools, just before the default166 additional dependency for build tools, just before the default
166 primary archive.167 primary archive.
168 :param tools_fingerprint: if not None, the OpenPGP signing key
169 fingerprint for the archive given in `tools_source`.
167 :param logger: an optional logger.170 :param logger: an optional logger.
168 :return: a list of (archive, distro_arch_series, pocket, [component]),171 :return: a list of (archive, distro_arch_series, pocket, [component]),
169 representing the dependencies defined by the given build context.172 representing the dependencies defined by the given build context.
@@ -201,7 +204,9 @@
201 # Consider build tools archive dependencies.204 # Consider build tools archive dependencies.
202 if tools_source is not None:205 if tools_source is not None:
203 try:206 try:
204 deps.append(tools_source % {'series': distro_series.name})207 deps.append(
208 (tools_source % {'series': distro_series.name},
209 tools_fingerprint))
205 except Exception:210 except Exception:
206 # Someone messed up the configuration; don't add it.211 # Someone messed up the configuration; don't add it.
207 if logger is not None:212 if logger is not None:
@@ -240,7 +245,8 @@
240245
241@defer.inlineCallbacks246@defer.inlineCallbacks
242def get_sources_list_for_building(build, distroarchseries, sourcepackagename,247def get_sources_list_for_building(build, distroarchseries, sourcepackagename,
243 tools_source=None, logger=None):248 tools_source=None, tools_fingerprint=None,
249 logger=None):
244 """Return sources.list entries and keys required to build the given item.250 """Return sources.list entries and keys required to build the given item.
245251
246 The sources.list entries are returned in the order that is most useful:252 The sources.list entries are returned in the order that is most useful:
@@ -257,6 +263,8 @@
257 :param tools_source: if not None, a sources.list entry to use as an263 :param tools_source: if not None, a sources.list entry to use as an
258 additional dependency for build tools, just before the default264 additional dependency for build tools, just before the default
259 primary archive.265 primary archive.
266 :param tools_fingerprint: if not None, the OpenPGP signing key
267 fingerprint for the archive given in `tools_source`.
260 :param logger: an optional logger.268 :param logger: an optional logger.
261 :return: a Deferred resolving to a tuple containing a list of deb269 :return: a Deferred resolving to a tuple containing a list of deb
262 sources.list entries (lines) and a list of base64-encoded public270 sources.list entries (lines) and a list of base64-encoded public
@@ -265,7 +273,8 @@
265 deps = expand_dependencies(273 deps = expand_dependencies(
266 build.archive, distroarchseries, build.pocket,274 build.archive, distroarchseries, build.pocket,
267 build.current_component, sourcepackagename,275 build.current_component, sourcepackagename,
268 tools_source=tools_source, logger=logger)276 tools_source=tools_source, tools_fingerprint=tools_fingerprint,
277 logger=logger)
269 sources_list_lines, trusted_keys = (278 sources_list_lines, trusted_keys = (
270 yield _get_sources_list_for_dependencies(deps, logger=logger))279 yield _get_sources_list_for_dependencies(deps, logger=logger))
271280
@@ -360,8 +369,9 @@
360 # interaction.369 # interaction.
361 gpghandler = removeSecurityProxy(getUtility(IGPGHandler))370 gpghandler = removeSecurityProxy(getUtility(IGPGHandler))
362 for dep in dependencies:371 for dep in dependencies:
363 if isinstance(dep, basestring):372 if len(dep) == 2:
364 sources_list_lines.append(dep)373 sources_list_line, fingerprint = dep
374 sources_list_lines.append(sources_list_line)
365 else:375 else:
366 archive, distro_arch_series, pocket, components = dep376 archive, distro_arch_series, pocket, components = dep
367 has_published_binaries = _has_published_binaries(377 has_published_binaries = _has_published_binaries(
@@ -379,23 +389,23 @@
379 archive, distro_arch_series, pocket, components)389 archive, distro_arch_series, pocket, components)
380 sources_list_lines.append(sources_list_line)390 sources_list_lines.append(sources_list_line)
381 fingerprint = archive.signing_key_fingerprint391 fingerprint = archive.signing_key_fingerprint
382 if fingerprint is not None and fingerprint not in trusted_keys:392 if fingerprint is not None and fingerprint not in trusted_keys:
383 def get_key():393 def get_key():
384 with default_timeout(15.0):394 with default_timeout(15.0):
385 try:395 try:
386 return gpghandler.retrieveKey(fingerprint)396 return gpghandler.retrieveKey(fingerprint)
387 except GPGKeyNotFoundError as e:397 except GPGKeyNotFoundError as e:
388 # For now, just log this and proceed without the398 # For now, just log this and proceed without the
389 # key. We'll have to fix any outstanding cases399 # key. We'll have to fix any outstanding cases of
390 # of this before we can switch to requiring400 # this before we can switch to requiring
391 # authentication across the board.401 # authentication across the board.
392 if logger is not None:402 if logger is not None:
393 logger.warning(str(e))403 logger.warning(str(e))
394 return None404 return None
395405
396 key = yield deferToThread(get_key)406 key = yield deferToThread(get_key)
397 if key is not None:407 if key is not None:
398 trusted_keys[fingerprint] = base64.b64encode(key.export())408 trusted_keys[fingerprint] = base64.b64encode(key.export())
399409
400 defer.returnValue(410 defer.returnValue(
401 (sources_list_lines, [v for k, v in sorted(trusted_keys.items())]))411 (sources_list_lines, [v for k, v in sorted(trusted_keys.items())]))
402412
=== modified file 'lib/lp/soyuz/adapters/tests/test_archivedependencies.py'
--- lib/lp/soyuz/adapters/tests/test_archivedependencies.py 2017-06-13 17:22:44 +0000
+++ lib/lp/soyuz/adapters/tests/test_archivedependencies.py 2017-06-14 08:12:16 +0000
@@ -16,7 +16,9 @@
16 )16 )
17import transaction17import transaction
18from twisted.internet import defer18from twisted.internet import defer
19from twisted.internet.threads import deferToThread
19from zope.component import getUtility20from zope.component import getUtility
21from zope.security.proxy import removeSecurityProxy
2022
21from lp.archivepublisher.interfaces.archivesigningkey import (23from lp.archivepublisher.interfaces.archivesigningkey import (
22 IArchiveSigningKey,24 IArchiveSigningKey,
@@ -24,6 +26,7 @@
24from lp.registry.interfaces.distribution import IDistributionSet26from lp.registry.interfaces.distribution import IDistributionSet
25from lp.registry.interfaces.pocket import PackagePublishingPocket27from lp.registry.interfaces.pocket import PackagePublishingPocket
26from lp.services.config import config28from lp.services.config import config
29from lp.services.gpg.interfaces import IGPGHandler
27from lp.services.log.logger import BufferLogger30from lp.services.log.logger import BufferLogger
28from lp.soyuz.adapters.archivedependencies import (31from lp.soyuz.adapters.archivedependencies import (
29 default_component_dependency_name,32 default_component_dependency_name,
@@ -522,6 +525,18 @@
522 # sources.list, which is useful for specialised build types.525 # sources.list, which is useful for specialised build types.
523 ppa = yield self.makeArchive(publish_binary=True)526 ppa = yield self.makeArchive(publish_binary=True)
524 build = self.makeBuild(archive=ppa)527 build = self.makeBuild(archive=ppa)
528
529 # Upload the tools archive key to the keyserver.
530 tools_key_name = "ppa-sample-4096@canonical.com"
531 tools_key_path = os.path.join(gpgkeysdir, "%s.sec" % tools_key_name)
532 with open(tools_key_path) as tools_key_file:
533 secret_key_export = tools_key_file.read()
534 # Remove security proxy to avoid problems with running in a thread.
535 gpghandler = removeSecurityProxy(getUtility(IGPGHandler))
536 gpghandler.importSecretKey(secret_key_export)
537 yield deferToThread(
538 gpghandler.uploadPublicKey, self.fingerprints[tools_key_name])
539
525 yield self.assertSourcesListAndKeys(540 yield self.assertSourcesListAndKeys(
526 [(ppa, ["hoary main"]),541 [(ppa, ["hoary main"]),
527 ("deb http://example.org", ["hoary main"]),542 ("deb http://example.org", ["hoary main"]),
@@ -531,8 +546,9 @@
531 "hoary-updates main restricted universe multiverse",546 "hoary-updates main restricted universe multiverse",
532 ]),547 ]),
533 ],548 ],
534 ["ppa-sample@canonical.com"], build,549 ["ppa-sample@canonical.com", tools_key_name], build,
535 tools_source="deb http://example.org %(series)s main")550 tools_source="deb http://example.org %(series)s main",
551 tools_fingerprint=self.fingerprints[tools_key_name])
536552
537 @defer.inlineCallbacks553 @defer.inlineCallbacks
538 def test_build_tools_bad_formatting(self):554 def test_build_tools_bad_formatting(self):
539555
=== modified file 'lib/lp/soyuz/tests/soyuz.py'
--- lib/lp/soyuz/tests/soyuz.py 2017-04-29 23:51:28 +0000
+++ lib/lp/soyuz/tests/soyuz.py 2017-06-14 08:12:16 +0000
@@ -114,3 +114,6 @@
114 key = base64.b64decode(encoded_key)114 key = base64.b64decode(encoded_key)
115 return Equals(self.fingerprint).match(115 return Equals(self.fingerprint).match(
116 getUtility(IGPGHandler).importPublicKey(key).fingerprint)116 getUtility(IGPGHandler).importPublicKey(key).fingerprint)
117
118 def __str__(self):
119 return "Base64KeyMatches(%s)" % self.fingerprint