Merge ~cjwatson/launchpad:archive-subscriber-signing-key-fingerprint into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 8549286e05b54cba75b69b5bf63649043532cba9
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:archive-subscriber-signing-key-fingerprint
Merge into: launchpad:master
Diff against target: 154 lines (+88/-8)
2 files modified
lib/lp/soyuz/browser/tests/test_archive_webservice.py (+82/-1)
lib/lp/soyuz/interfaces/archive.py (+6/-7)
Reviewer Review Type Date Requested Status
Thiago F. Pappacena (community) Approve
Review via email: mp+384345@code.launchpad.net

Commit message

Allow subscribers to see Archive.signing_key_fingerprint

Description of the change

They can already use Archive.getSigningKeyData, and by definition they're allowed to use the archive via apt, so it doesn't make sense to stop them seeing the fingerprint.

To post a comment you must log in.
Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/soyuz/browser/tests/test_archive_webservice.py b/lib/lp/soyuz/browser/tests/test_archive_webservice.py
index 66be27d..b9ad921 100644
--- a/lib/lp/soyuz/browser/tests/test_archive_webservice.py
+++ b/lib/lp/soyuz/browser/tests/test_archive_webservice.py
@@ -1,4 +1,4 @@
1# Copyright 2010-2019 Canonical Ltd. This software is licensed under the1# Copyright 2010-2020 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4from __future__ import absolute_import, print_function, unicode_literals4from __future__ import absolute_import, print_function, unicode_literals
@@ -7,7 +7,9 @@ __metaclass__ = type
77
8from datetime import timedelta8from datetime import timedelta
9import json9import json
10import os.path
1011
12import responses
11from testtools.matchers import (13from testtools.matchers import (
12 Contains,14 Contains,
13 ContainsDict,15 ContainsDict,
@@ -18,9 +20,11 @@ from testtools.matchers import (
18 MatchesStructure,20 MatchesStructure,
19 )21 )
20from zope.component import getUtility22from zope.component import getUtility
23from zope.security.proxy import removeSecurityProxy
2124
22from lp.app.interfaces.launchpad import ILaunchpadCelebrities25from lp.app.interfaces.launchpad import ILaunchpadCelebrities
23from lp.registry.interfaces.pocket import PackagePublishingPocket26from lp.registry.interfaces.pocket import PackagePublishingPocket
27from lp.services.gpg.interfaces import IGPGHandler
24from lp.services.webapp.interfaces import OAuthPermission28from lp.services.webapp.interfaces import OAuthPermission
25from lp.soyuz.enums import (29from lp.soyuz.enums import (
26 ArchivePermissionType,30 ArchivePermissionType,
@@ -39,6 +43,7 @@ from lp.testing import (
39 record_two_runs,43 record_two_runs,
40 TestCaseWithFactory,44 TestCaseWithFactory,
41 )45 )
46from lp.testing.gpgkeys import gpgkeysdir
42from lp.testing.layers import DatabaseFunctionalLayer47from lp.testing.layers import DatabaseFunctionalLayer
43from lp.testing.matchers import HasQueryCount48from lp.testing.matchers import HasQueryCount
44from lp.testing.pages import (49from lp.testing.pages import (
@@ -134,6 +139,82 @@ class TestArchiveWebservice(TestCaseWithFactory):
134 self.assertEqual(401, ws.delete(ppa_url).status)139 self.assertEqual(401, ws.delete(ppa_url).status)
135140
136141
142class TestSigningKey(TestCaseWithFactory):
143 """Test signing-key-related information for archives.
144
145 We just use `responses` to mock the keyserver here; the details of its
146 implementation aren't especially important, we can't use
147 `InProcessKeyServerFixture` because the keyserver operations are
148 synchronous, and `responses` is much faster than `KeyServerTac`.
149 """
150
151 layer = DatabaseFunctionalLayer
152
153 def _setUpSigningKey(self, archive):
154 key_path = os.path.join(gpgkeysdir, "ppa-sample@canonical.com.sec")
155 gpghandler = getUtility(IGPGHandler)
156 with open(key_path, "rb") as key_file:
157 secret_key = gpghandler.importSecretKey(key_file.read())
158 public_key = gpghandler.retrieveKey(secret_key.fingerprint)
159 public_key_data = public_key.export()
160 removeSecurityProxy(archive).signing_key_fingerprint = (
161 public_key.fingerprint)
162 key_url = gpghandler.getURLForKeyInServer(
163 public_key.fingerprint, action="get")
164 responses.add("GET", key_url, body=public_key_data)
165 gpghandler.resetLocalState()
166 return public_key.fingerprint, public_key_data
167
168 @responses.activate
169 def test_signing_key_public(self):
170 # Anyone can read signing key information for public archives.
171 archive = self.factory.makeArchive()
172 fingerprint, public_key_data = self._setUpSigningKey(archive)
173 archive_url = api_url(archive)
174 ws = webservice_for_person(
175 self.factory.makePerson(), default_api_version="devel")
176 ws_archive = self.getWebserviceJSON(ws, archive_url)
177 self.assertEqual(fingerprint, ws_archive["signing_key_fingerprint"])
178 response = ws.named_get(archive_url, "getSigningKeyData")
179 self.assertEqual(200, response.status)
180 self.assertEqual(public_key_data, response.jsonBody())
181
182 @responses.activate
183 def test_signing_key_private_subscriber(self):
184 # Subscribers can read signing key information for private archives.
185 archive = self.factory.makeArchive(private=True)
186 fingerprint, public_key_data = self._setUpSigningKey(archive)
187 subscriber = self.factory.makePerson()
188 with person_logged_in(archive.owner):
189 archive.newSubscription(subscriber, archive.owner)
190 archive_url = api_url(archive)
191 ws = webservice_for_person(
192 subscriber, permission=OAuthPermission.READ_PRIVATE,
193 default_api_version="devel")
194 ws_archive = self.getWebserviceJSON(ws, archive_url)
195 self.assertEqual(fingerprint, ws_archive["signing_key_fingerprint"])
196 response = ws.named_get(archive_url, "getSigningKeyData")
197 self.assertEqual(200, response.status)
198 self.assertEqual(public_key_data, response.jsonBody())
199
200 @responses.activate
201 def test_signing_key_private_non_subscriber(self):
202 # Non-subscribers cannot read signing key information (or indeed
203 # anything else) for private archives.
204 archive = self.factory.makeArchive(private=True)
205 fingerprint, public_key_data = self._setUpSigningKey(archive)
206 archive_url = api_url(archive)
207 ws = webservice_for_person(
208 self.factory.makePerson(), permission=OAuthPermission.READ_PRIVATE,
209 default_api_version="devel")
210 ws_archive = self.getWebserviceJSON(ws, archive_url)
211 self.assertEqual(
212 "tag:launchpad.net:2008:redacted",
213 ws_archive["signing_key_fingerprint"])
214 response = ws.named_get(archive_url, "getSigningKeyData")
215 self.assertEqual(401, response.status)
216
217
137class TestExternalDependencies(TestCaseWithFactory):218class TestExternalDependencies(TestCaseWithFactory):
138219
139 layer = DatabaseFunctionalLayer220 layer = DatabaseFunctionalLayer
diff --git a/lib/lp/soyuz/interfaces/archive.py b/lib/lp/soyuz/interfaces/archive.py
index 6347193..8d34ec4 100644
--- a/lib/lp/soyuz/interfaces/archive.py
+++ b/lib/lp/soyuz/interfaces/archive.py
@@ -461,6 +461,12 @@ class IArchiveSubscriberView(Interface):
461 "explicit publish flag and any other constraints."))461 "explicit publish flag and any other constraints."))
462 series_with_sources = Attribute(462 series_with_sources = Attribute(
463 "DistroSeries to which this archive has published sources")463 "DistroSeries to which this archive has published sources")
464 signing_key_fingerprint = exported(
465 Text(
466 title=_("Archive signing key fingerprint"), required=False,
467 description=_("A OpenPGP signing key fingerprint (40 chars) "
468 "for this PPA or None if there is no signing "
469 "key available.")))
464 signing_key = Object(470 signing_key = Object(
465 title=_('Repository signing key.'), required=False, schema=IGPGKey)471 title=_('Repository signing key.'), required=False, schema=IGPGKey)
466472
@@ -1183,13 +1189,6 @@ class IArchiveView(IHasBuildRecords):
1183 description=_(1189 description=_(
1184 "The password used by the build farm to access the archive."))1190 "The password used by the build farm to access the archive."))
11851191
1186 signing_key_fingerprint = exported(
1187 Text(
1188 title=_("Archive signing key fingerprint"), required=False,
1189 description=_("A OpenPGP signing key fingerprint (40 chars) "
1190 "for this PPA or None if there is no signing "
1191 "key available.")))
1192
1193 @call_with(eager_load=True)1192 @call_with(eager_load=True)
1194 @rename_parameters_as(1193 @rename_parameters_as(
1195 name="binary_name", distroarchseries="distro_arch_series")1194 name="binary_name", distroarchseries="distro_arch_series")

Subscribers

People subscribed via source and target branches

to status/vote changes: