Merge ~cjwatson/launchpad:export-sshkey-getFullKeyText into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 1a520e5a6e8c9add2bbcb8bb534e61e6f1913cb8
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:export-sshkey-getFullKeyText
Merge into: launchpad:master
Diff against target: 88 lines (+39/-1)
3 files modified
lib/lp/registry/browser/person.py (+8/-0)
lib/lp/registry/interfaces/ssh.py (+4/-0)
lib/lp/registry/tests/test_ssh.py (+27/-1)
Reviewer Review Type Date Requested Status
Guruprasad Approve
Review via email: mp+446623@code.launchpad.net

Commit message

Export ISSHKey.getFullKeyText

Description of the change

There are currently several cron jobs on loganberry that export email and SSH key data for the members of several teams, using `scripts/list-team-members`; this information is used as part of various integrations such as lists.ubuntu.com posting privileges, the ability for Ubuntu members to upload files to people.ubuntu.com using SFTP, and so on. However, doing this with ad-hoc cron jobs on a Launchpad machine isn't ideal; it would be better if it were possible to get this information over the API, and then IS would only need a suitably-privileged bot account.

As far as I can see, the only API gap here is that we can only extract the raw key text for an SSH key, and not the "full" key text that's decorated with the key type and comment in a format suitable for adding to an OpenSSH `authorized_keys` file. That transformation isn't quite trivial, so export a method that does it on the webservice.

To post a comment you must log in.
Revision history for this message
Guruprasad (lgp171188) 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/registry/browser/person.py b/lib/lp/registry/browser/person.py
index 3c67245..3a61179 100644
--- a/lib/lp/registry/browser/person.py
+++ b/lib/lp/registry/browser/person.py
@@ -627,6 +627,14 @@ class PersonNavigation(BranchTraversalMixin, Navigation):
627 raise NotFoundError(name)627 raise NotFoundError(name)
628 return snap628 return snap
629629
630 @stepthrough("+ssh-keys")
631 def traverse_ssh_keys(self, id):
632 """Traverse to this person's SSH keys."""
633 ssh_key = getUtility(ISSHKeySet).getByID(id)
634 if ssh_key is None or ssh_key.person != self.context:
635 return None
636 return ssh_key
637
630638
631class PersonSetNavigation(Navigation):639class PersonSetNavigation(Navigation):
632 usedfor = IPersonSet640 usedfor = IPersonSet
diff --git a/lib/lp/registry/interfaces/ssh.py b/lib/lp/registry/interfaces/ssh.py
index 5590a99..5559526 100644
--- a/lib/lp/registry/interfaces/ssh.py
+++ b/lib/lp/registry/interfaces/ssh.py
@@ -16,8 +16,10 @@ import http.client
16from lazr.enum import DBEnumeratedType, DBItem16from lazr.enum import DBEnumeratedType, DBItem
17from lazr.restful.declarations import (17from lazr.restful.declarations import (
18 error_status,18 error_status,
19 export_read_operation,
19 exported,20 exported,
20 exported_as_webservice_entry,21 exported_as_webservice_entry,
22 operation_for_version,
21)23)
22from zope.interface import Interface24from zope.interface import Interface
23from zope.schema import Choice, Int, TextLine25from zope.schema import Choice, Int, TextLine
@@ -107,6 +109,8 @@ class ISSHKey(Interface):
107 def destroySelf():109 def destroySelf():
108 """Remove this SSHKey from the database."""110 """Remove this SSHKey from the database."""
109111
112 @export_read_operation()
113 @operation_for_version("devel")
110 def getFullKeyText():114 def getFullKeyText():
111 """Get the full text of the SSH key."""115 """Get the full text of the SSH key."""
112116
diff --git a/lib/lp/registry/tests/test_ssh.py b/lib/lp/registry/tests/test_ssh.py
index 3353e66..a3448bf 100644
--- a/lib/lp/registry/tests/test_ssh.py
+++ b/lib/lp/registry/tests/test_ssh.py
@@ -12,9 +12,16 @@ from lp.registry.interfaces.ssh import (
12 ISSHKeySet,12 ISSHKeySet,
13 SSHKeyAdditionError,13 SSHKeyAdditionError,
14)14)
15from lp.testing import TestCaseWithFactory, admin_logged_in, person_logged_in15from lp.services.webapp.interfaces import OAuthPermission
16from lp.testing import (
17 TestCaseWithFactory,
18 admin_logged_in,
19 api_url,
20 person_logged_in,
21)
16from lp.testing.layers import DatabaseFunctionalLayer22from lp.testing.layers import DatabaseFunctionalLayer
17from lp.testing.mail_helpers import pop_notifications23from lp.testing.mail_helpers import pop_notifications
24from lp.testing.pages import webservice_for_person
1825
1926
20class TestSSHKey(TestCaseWithFactory):27class TestSSHKey(TestCaseWithFactory):
@@ -298,3 +305,22 @@ class TestSSHKeySet(TestCaseWithFactory):
298 self.assertContentEqual(305 self.assertContentEqual(
299 [person1_key1, person1_key2, person2_key1], keys306 [person1_key1, person1_key2, person2_key1], keys
300 )307 )
308
309
310class TestSSHKeyWebservice(TestCaseWithFactory):
311 layer = DatabaseFunctionalLayer
312
313 def test_getFullKeyText(self):
314 person = self.factory.makePerson()
315 with person_logged_in(person):
316 key = self.factory.makeSSHKey(person, "ssh-rsa")
317 key_url = api_url(key)
318 expected = "ssh-rsa %s %s" % (key.keytext, key.comment)
319 webservice = webservice_for_person(
320 person,
321 permission=OAuthPermission.READ_PUBLIC,
322 default_api_version="devel",
323 )
324 response = webservice.named_get(key_url, "getFullKeyText")
325 self.assertEqual(200, response.status)
326 self.assertEqual(expected, response.jsonBody())

Subscribers

People subscribed via source and target branches

to status/vote changes: