Colin Watson has proposed merging ~cjwatson/launchpad:export-sshkey-getFullKeyText into launchpad:master.
Commit message: Export ISSHKey.getFullKeyText Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/446623 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. -- Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:export-sshkey-getFullKeyText into launchpad:master.
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): raise NotFoundError(name) return snap + @stepthrough("+ssh-keys") + def traverse_ssh_keys(self, id): + """Traverse to this person's SSH keys.""" + ssh_key = getUtility(ISSHKeySet).getByID(id) + if ssh_key is None or ssh_key.person != self.context: + return None + return ssh_key + class PersonSetNavigation(Navigation): 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 from lazr.enum import DBEnumeratedType, DBItem from lazr.restful.declarations import ( error_status, + export_read_operation, exported, exported_as_webservice_entry, + operation_for_version, ) from zope.interface import Interface from zope.schema import Choice, Int, TextLine @@ -107,6 +109,8 @@ class ISSHKey(Interface): def destroySelf(): """Remove this SSHKey from the database.""" + @export_read_operation() + @operation_for_version("devel") def getFullKeyText(): """Get the full text of the SSH key.""" 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 ( ISSHKeySet, SSHKeyAdditionError, ) -from lp.testing import TestCaseWithFactory, admin_logged_in, person_logged_in +from lp.services.webapp.interfaces import OAuthPermission +from lp.testing import ( + TestCaseWithFactory, + admin_logged_in, + api_url, + person_logged_in, +) from lp.testing.layers import DatabaseFunctionalLayer from lp.testing.mail_helpers import pop_notifications +from lp.testing.pages import webservice_for_person class TestSSHKey(TestCaseWithFactory): @@ -298,3 +305,22 @@ class TestSSHKeySet(TestCaseWithFactory): self.assertContentEqual( [person1_key1, person1_key2, person2_key1], keys ) + + +class TestSSHKeyWebservice(TestCaseWithFactory): + layer = DatabaseFunctionalLayer + + def test_getFullKeyText(self): + person = self.factory.makePerson() + with person_logged_in(person): + key = self.factory.makeSSHKey(person, "ssh-rsa") + key_url = api_url(key) + expected = "ssh-rsa %s %s" % (key.keytext, key.comment) + webservice = webservice_for_person( + person, + permission=OAuthPermission.READ_PUBLIC, + default_api_version="devel", + ) + response = webservice.named_get(key_url, "getFullKeyText") + self.assertEqual(200, response.status) + self.assertEqual(expected, response.jsonBody())
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp