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
1=== modified file 'lib/lp/services/config/schema-lazr.conf'
2--- lib/lp/services/config/schema-lazr.conf 2017-06-01 12:05:30 +0000
3+++ lib/lp/services/config/schema-lazr.conf 2017-06-14 08:12:16 +0000
4@@ -1804,6 +1804,11 @@
5 # datatype: string
6 tools_source: none
7
8+# Optional OpenPGP signing key fingerprint for the archive given in
9+# tools_source.
10+# datatype: string
11+tools_fingerprint: none
12+
13 # The store's primary URL endpoint.
14 store_url: none
15
16
17=== modified file 'lib/lp/snappy/tests/test_snapbuildbehaviour.py'
18--- lib/lp/snappy/tests/test_snapbuildbehaviour.py 2017-06-13 17:08:16 +0000
19+++ lib/lp/snappy/tests/test_snapbuildbehaviour.py 2017-06-14 08:12:16 +0000
20@@ -69,7 +69,7 @@
21
22 def setUp(self):
23 super(TestSnapBuildBehaviourBase, self).setUp()
24- self.pushConfig("snappy", tools_source=None)
25+ self.pushConfig("snappy", tools_source=None, tools_fingerprint=None)
26
27 def makeJob(self, archive=None, pocket=PackagePublishingPocket.UPDATES,
28 **kwargs):
29
30=== modified file 'lib/lp/soyuz/adapters/archivedependencies.py'
31--- lib/lp/soyuz/adapters/archivedependencies.py 2017-04-29 23:51:28 +0000
32+++ lib/lp/soyuz/adapters/archivedependencies.py 2017-06-14 08:12:16 +0000
33@@ -153,7 +153,8 @@
34
35
36 def expand_dependencies(archive, distro_arch_series, pocket, component,
37- source_package_name, tools_source=None, logger=None):
38+ source_package_name, tools_source=None,
39+ tools_fingerprint=None, logger=None):
40 """Return the set of dependency archives, pockets and components.
41
42 :param archive: the context `IArchive`.
43@@ -164,6 +165,8 @@
44 :param tools_source: if not None, a sources.list entry to use as an
45 additional dependency for build tools, just before the default
46 primary archive.
47+ :param tools_fingerprint: if not None, the OpenPGP signing key
48+ fingerprint for the archive given in `tools_source`.
49 :param logger: an optional logger.
50 :return: a list of (archive, distro_arch_series, pocket, [component]),
51 representing the dependencies defined by the given build context.
52@@ -201,7 +204,9 @@
53 # Consider build tools archive dependencies.
54 if tools_source is not None:
55 try:
56- deps.append(tools_source % {'series': distro_series.name})
57+ deps.append(
58+ (tools_source % {'series': distro_series.name},
59+ tools_fingerprint))
60 except Exception:
61 # Someone messed up the configuration; don't add it.
62 if logger is not None:
63@@ -240,7 +245,8 @@
64
65 @defer.inlineCallbacks
66 def get_sources_list_for_building(build, distroarchseries, sourcepackagename,
67- tools_source=None, logger=None):
68+ tools_source=None, tools_fingerprint=None,
69+ logger=None):
70 """Return sources.list entries and keys required to build the given item.
71
72 The sources.list entries are returned in the order that is most useful:
73@@ -257,6 +263,8 @@
74 :param tools_source: if not None, a sources.list entry to use as an
75 additional dependency for build tools, just before the default
76 primary archive.
77+ :param tools_fingerprint: if not None, the OpenPGP signing key
78+ fingerprint for the archive given in `tools_source`.
79 :param logger: an optional logger.
80 :return: a Deferred resolving to a tuple containing a list of deb
81 sources.list entries (lines) and a list of base64-encoded public
82@@ -265,7 +273,8 @@
83 deps = expand_dependencies(
84 build.archive, distroarchseries, build.pocket,
85 build.current_component, sourcepackagename,
86- tools_source=tools_source, logger=logger)
87+ tools_source=tools_source, tools_fingerprint=tools_fingerprint,
88+ logger=logger)
89 sources_list_lines, trusted_keys = (
90 yield _get_sources_list_for_dependencies(deps, logger=logger))
91
92@@ -360,8 +369,9 @@
93 # interaction.
94 gpghandler = removeSecurityProxy(getUtility(IGPGHandler))
95 for dep in dependencies:
96- if isinstance(dep, basestring):
97- sources_list_lines.append(dep)
98+ if len(dep) == 2:
99+ sources_list_line, fingerprint = dep
100+ sources_list_lines.append(sources_list_line)
101 else:
102 archive, distro_arch_series, pocket, components = dep
103 has_published_binaries = _has_published_binaries(
104@@ -379,23 +389,23 @@
105 archive, distro_arch_series, pocket, components)
106 sources_list_lines.append(sources_list_line)
107 fingerprint = archive.signing_key_fingerprint
108- if fingerprint is not None and fingerprint not in trusted_keys:
109- def get_key():
110- with default_timeout(15.0):
111- try:
112- return gpghandler.retrieveKey(fingerprint)
113- except GPGKeyNotFoundError as e:
114- # For now, just log this and proceed without the
115- # key. We'll have to fix any outstanding cases
116- # of this before we can switch to requiring
117- # authentication across the board.
118- if logger is not None:
119- logger.warning(str(e))
120- return None
121+ if fingerprint is not None and fingerprint not in trusted_keys:
122+ def get_key():
123+ with default_timeout(15.0):
124+ try:
125+ return gpghandler.retrieveKey(fingerprint)
126+ except GPGKeyNotFoundError as e:
127+ # For now, just log this and proceed without the
128+ # key. We'll have to fix any outstanding cases of
129+ # this before we can switch to requiring
130+ # authentication across the board.
131+ if logger is not None:
132+ logger.warning(str(e))
133+ return None
134
135- key = yield deferToThread(get_key)
136- if key is not None:
137- trusted_keys[fingerprint] = base64.b64encode(key.export())
138+ key = yield deferToThread(get_key)
139+ if key is not None:
140+ trusted_keys[fingerprint] = base64.b64encode(key.export())
141
142 defer.returnValue(
143 (sources_list_lines, [v for k, v in sorted(trusted_keys.items())]))
144
145=== modified file 'lib/lp/soyuz/adapters/tests/test_archivedependencies.py'
146--- lib/lp/soyuz/adapters/tests/test_archivedependencies.py 2017-06-13 17:22:44 +0000
147+++ lib/lp/soyuz/adapters/tests/test_archivedependencies.py 2017-06-14 08:12:16 +0000
148@@ -16,7 +16,9 @@
149 )
150 import transaction
151 from twisted.internet import defer
152+from twisted.internet.threads import deferToThread
153 from zope.component import getUtility
154+from zope.security.proxy import removeSecurityProxy
155
156 from lp.archivepublisher.interfaces.archivesigningkey import (
157 IArchiveSigningKey,
158@@ -24,6 +26,7 @@
159 from lp.registry.interfaces.distribution import IDistributionSet
160 from lp.registry.interfaces.pocket import PackagePublishingPocket
161 from lp.services.config import config
162+from lp.services.gpg.interfaces import IGPGHandler
163 from lp.services.log.logger import BufferLogger
164 from lp.soyuz.adapters.archivedependencies import (
165 default_component_dependency_name,
166@@ -522,6 +525,18 @@
167 # sources.list, which is useful for specialised build types.
168 ppa = yield self.makeArchive(publish_binary=True)
169 build = self.makeBuild(archive=ppa)
170+
171+ # Upload the tools archive key to the keyserver.
172+ tools_key_name = "ppa-sample-4096@canonical.com"
173+ tools_key_path = os.path.join(gpgkeysdir, "%s.sec" % tools_key_name)
174+ with open(tools_key_path) as tools_key_file:
175+ secret_key_export = tools_key_file.read()
176+ # Remove security proxy to avoid problems with running in a thread.
177+ gpghandler = removeSecurityProxy(getUtility(IGPGHandler))
178+ gpghandler.importSecretKey(secret_key_export)
179+ yield deferToThread(
180+ gpghandler.uploadPublicKey, self.fingerprints[tools_key_name])
181+
182 yield self.assertSourcesListAndKeys(
183 [(ppa, ["hoary main"]),
184 ("deb http://example.org", ["hoary main"]),
185@@ -531,8 +546,9 @@
186 "hoary-updates main restricted universe multiverse",
187 ]),
188 ],
189- ["ppa-sample@canonical.com"], build,
190- tools_source="deb http://example.org %(series)s main")
191+ ["ppa-sample@canonical.com", tools_key_name], build,
192+ tools_source="deb http://example.org %(series)s main",
193+ tools_fingerprint=self.fingerprints[tools_key_name])
194
195 @defer.inlineCallbacks
196 def test_build_tools_bad_formatting(self):
197
198=== modified file 'lib/lp/soyuz/tests/soyuz.py'
199--- lib/lp/soyuz/tests/soyuz.py 2017-04-29 23:51:28 +0000
200+++ lib/lp/soyuz/tests/soyuz.py 2017-06-14 08:12:16 +0000
201@@ -114,3 +114,6 @@
202 key = base64.b64decode(encoded_key)
203 return Equals(self.fingerprint).match(
204 getUtility(IGPGHandler).importPublicKey(key).fingerprint)
205+
206+ def __str__(self):
207+ return "Base64KeyMatches(%s)" % self.fingerprint