← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~thomir/launchpad/devel-add-read-ff into lp:launchpad

 

Thomi Richards has proposed merging lp:~thomir/launchpad/devel-add-read-ff into lp:launchpad with lp:~thomir/launchpad/devel-start-integration as a prerequisite.

Commit message:
Add feature flag to read GPG keys from gpgservice.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~thomir/launchpad/devel-add-read-ff/+merge/287695

Add feature flag to read GPG keys from gpgservice.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~thomir/launchpad/devel-add-read-ff into lp:launchpad.
=== modified file 'buildout.cfg'
--- buildout.cfg	2016-02-15 00:54:24 +0000
+++ buildout.cfg	2016-03-01 19:25:45 +0000
@@ -31,7 +31,7 @@
 
 prefer-final = true
 
-develop = .
+develop = . /home/thomi/code/canonical/canonical-gpg-service
 
 [configuration]
 instance_name = development

=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml	2016-02-05 20:28:29 +0000
+++ lib/lp/registry/configure.zcml	2016-03-01 19:25:45 +0000
@@ -1284,6 +1284,14 @@
             permission="launchpad.Edit"
             set_attributes="active can_encrypt"/>
     </class>
+    <class
+        class="lp.registry.model.gpgkey.GPGServiceKey">
+        <allow
+            interface="lp.registry.interfaces.gpg.IGPGKey"/>
+        <require
+            permission="launchpad.Edit"
+            set_attributes="active can_encrypt"/>
+    </class>
 
     <!-- GPGKeySet -->
 

=== modified file 'lib/lp/registry/interfaces/gpg.py'
--- lib/lp/registry/interfaces/gpg.py	2016-03-01 19:25:45 +0000
+++ lib/lp/registry/interfaces/gpg.py	2016-03-01 19:25:45 +0000
@@ -73,37 +73,22 @@
             reactivated an existing key.
         """
 
-<<<<<<< TREE
-=======
     def deactivate(key):
         """Deactivate a key.
 
         :param key: An IGPGKey instance.
         """
 
-    def get(key_id, default=None):
-        """Return the GPGKey object for the given id.
-
-        Return the given default if there's no object with the given id.
-        """
-
->>>>>>> MERGE-SOURCE
     def getByFingerprint(fingerprint, default=None):
         """Return UNIQUE result for a given Key fingerprint including
         inactive ones.
         """
 
+    def getOwnerIdForPerson(person):
+        """return an owner id string suitable for sending to gpgservice."""
+
     def getGPGKeysForPerson(person, active=True):
         """Return OpenGPG keys for a person.
 
         :returns: a list of IGPGKey instances.
         """
-<<<<<<< TREE
-=======
-
-    def getGPGKeysForPeople(people):
-        """Return OpenPGP keys for a set of people."""
-
-    def getOwnerIdForPerson(person):
-        """return an owner id string suitable for sending to gpgservice."""
->>>>>>> MERGE-SOURCE

=== modified file 'lib/lp/registry/model/gpgkey.py'
--- lib/lp/registry/model/gpgkey.py	2016-03-01 19:25:45 +0000
+++ lib/lp/registry/model/gpgkey.py	2016-03-01 19:25:45 +0000
@@ -18,6 +18,7 @@
     IGPGKey,
     IGPGKeySet,
     )
+from lp.registry.interfaces.person import IPersonSet
 from lp.services.database.enumcol import EnumCol
 from lp.services.database.sqlbase import (
     SQLBase,
@@ -26,6 +27,7 @@
 from lp.services.features import getFeatureFlag
 from lp.services.gpg.interfaces import (
     GPG_WRITE_TO_GPGSERVICE_FEATURE_FLAG,
+    GPG_READ_FROM_GPGSERVICE_FEATURE_FLAG,
     GPGKeyAlgorithm,
     IGPGClient,
     IGPGHandler,
@@ -64,6 +66,53 @@
         return '%s%s/%s' % (self.keysize, self.algorithm.title, self.keyid)
 
 
+@implementer(IGPGKey)
+class GPGServiceKey:
+
+    def __init__(self, key_data):
+        self._key_data = key_data
+        self.active = key_data['enabled']
+
+    @property
+    def keysize(self):
+        return self._key_data['size']
+
+    @property
+    def algorithm(self):
+        return GPGKeyAlgorithm.items[self._key_data['algorithm']]
+
+    @property
+    def keyid(self):
+        return self._key_data['id']
+
+    @property
+    def fingerprint(self):
+        return self._key_data['fingerprint']
+
+    @property
+    def displayname(self):
+        return '%s%s/%s' % (self.keysize, self.algorithm.title, self.keyid)
+
+    @property
+    def keyserverURL(self):
+        return getUtility(
+            IGPGHandler).getURLForKeyInServer(self.fingerprint, public=True)
+
+    @property
+    def can_encrypt(self):
+        return self._key_data['can_encrypt']
+
+    @property
+    def owner(self):
+        return getUtility(IPersonSet).getByOpenIDIdentifier(
+            self._key_data['owner'])
+
+    @property
+    def ownerID(self):
+        return self.owner.id
+
+
+
 @implementer(IGPGKeySet)
 class GPGKeySet:
 
@@ -109,33 +158,39 @@
 
     def getByFingerprint(self, fingerprint, default=None):
         """See `IGPGKeySet`"""
-        result = GPGKey.selectOneBy(fingerprint=fingerprint)
-        if result is None:
-            return default
-        return result
+        if getFeatureFlag(GPG_READ_FROM_GPGSERVICE_FEATURE_FLAG):
+            key_data = getUtility(IGPGClient).getKeyByFingerprint(fingerprint)
+            return GPGServiceKey(key_data) if key_data else default
+        else:
+            result = GPGKey.selectOneBy(fingerprint=fingerprint)
+            if result is None:
+                return default
+            return result
 
     def getGPGKeysForPerson(self, owner, active=True):
-        if active is False:
-            query = """
-                active = false
-                AND fingerprint NOT IN
-                    (SELECT fingerprint FROM LoginToken
-                     WHERE fingerprint IS NOT NULL
-                           AND requester = %s
-                           AND date_consumed is NULL
-                    )
-                """ % sqlvalues(owner.id)
+        if getFeatureFlag(GPG_READ_FROM_GPGSERVICE_FEATURE_FLAG):
+            client = getUtility(IGPGClient)
+            owner_id = self.getOwnerIdForPerson(owner)
+            keys = client.getKeysForOwner(owner_id)['keys']
+            return [GPGServiceKey(d) for d in keys if d['enabled'] == active]
         else:
-            query = 'active=true'
-
-        query += ' AND owner=%s' % sqlvalues(owner.id)
-
-<<<<<<< TREE
-        return list(GPGKey.select(query, orderBy='id'))
-=======
-        return GPGKey.select(query, orderBy='id')
+            if active is False:
+                query = """
+                    active = false
+                    AND fingerprint NOT IN
+                        (SELECT fingerprint FROM LoginToken
+                         WHERE fingerprint IS NOT NULL
+                               AND requester = %s
+                               AND date_consumed is NULL
+                        )
+                    """ % sqlvalues(owner.id)
+            else:
+                query = 'active=true'
+
+            query += ' AND owner=%s' % sqlvalues(owner.id)
+
+            return list(GPGKey.select(query, orderBy='id'))
 
     def getOwnerIdForPerson(self, owner):
         """See IGPGKeySet."""
         return IOpenIDPersistentIdentity(owner).openid_identity_url
->>>>>>> MERGE-SOURCE

=== modified file 'lib/lp/services/gpg/interfaces.py'
--- lib/lp/services/gpg/interfaces.py	2016-03-01 19:25:45 +0000
+++ lib/lp/services/gpg/interfaces.py	2016-03-01 19:25:45 +0000
@@ -3,6 +3,7 @@
 
 __all__ = [
     'GPG_DATABASE_READONLY_FEATURE_FLAG',
+    'GPG_READ_FROM_GPGSERVICE_FEATURE_FLAG',
     'GPG_WRITE_TO_GPGSERVICE_FEATURE_FLAG',
     'GPGKeyAlgorithm',
     'GPGKeyDoesNotExistOnServer',
@@ -52,6 +53,7 @@
 
 GPG_DATABASE_READONLY_FEATURE_FLAG = u"gpg.database_read_only"
 GPG_WRITE_TO_GPGSERVICE_FEATURE_FLAG = u"gpg.write_to_gpgservice"
+GPG_READ_FROM_GPGSERVICE_FEATURE_FLAG = u"gpg.read_from_gpgservice"
 
 
 def valid_fingerprint(fingerprint):

=== modified file 'lib/lp/services/gpg/tests/test_gpghandler.py'
--- lib/lp/services/gpg/tests/test_gpghandler.py	2016-03-01 19:25:45 +0000
+++ lib/lp/services/gpg/tests/test_gpghandler.py	2016-03-01 19:25:45 +0000
@@ -16,6 +16,7 @@
 from zope.security.proxy import removeSecurityProxy
 
 from lp.registry.interfaces.gpg import IGPGKeySet
+from lp.registry.interfaces.person import IPersonSet
 from lp.services.config.fixture import (
     ConfigFixture,
     ConfigUseFixture,
@@ -254,7 +255,9 @@
 
     def test_get_key_for_user_with_sampledata(self):
         client = getUtility(IGPGClient)
-        data = client.getKeysForOwner('name16_oid')
+        person = getUtility(IPersonSet).getByName('name16')
+        openid_id = getUtility(IGPGKeySet).getOwnerIdForPerson(person)
+        data = client.getKeysForOwner(openid_id)
         self.assertThat(data, ContainsDict({'keys': HasLength(1)}))
 
     def test_get_key_for_unknown_user(self):

=== modified file 'lib/lp/testing/gpgservice/_fixture.py'
--- lib/lp/testing/gpgservice/_fixture.py	2016-02-16 05:36:37 +0000
+++ lib/lp/testing/gpgservice/_fixture.py	2016-03-01 19:25:45 +0000
@@ -99,7 +99,7 @@
         test_data = {
             'keys': [
                 {
-                    'owner': 'name16_oid',
+                    'owner': config.launchpad.openid_provider_root + '+id/name16_oid',
                     'id': '12345678',
                     'fingerprint': 'ABCDEF0123456789ABCDDCBA0000111112345678',
                     'size': 1024,

=== modified file 'lib/lp/testing/gpgservice/tests/test_fixture.py'
--- lib/lp/testing/gpgservice/tests/test_fixture.py	2016-03-01 19:25:45 +0000
+++ lib/lp/testing/gpgservice/tests/test_fixture.py	2016-03-01 19:25:45 +0000
@@ -47,7 +47,8 @@
     def test_fixture_can_create_test_data(self):
         fixture = self.useFixture(GPGKeyServiceFixture())
         conn = httplib.HTTPConnection(fixture.bind_address)
-        user = base64.b64encode('name16_oid', altchars='-_')
+        user = base64.b64encode(
+        config.launchpad.openid_provider_root + '+id/name16_oid', altchars='-_')
         conn.request('GET', '/users/%s/keys' % user)
         resp = conn.getresponse()
         self.assertEqual(200, resp.status)

=== modified file 'versions.cfg'
--- versions.cfg	2016-03-01 19:25:45 +0000
+++ versions.cfg	2016-03-01 19:25:45 +0000
@@ -38,7 +38,7 @@
 flask = 0.10.1
 FormEncode = 1.2.4
 funkload = 1.16.1
-gpgservice = 0.1.1
+gpgservice = 0.1.2
 grokcore.component = 1.6
 gunicorn = 19.4.5
 html5browser = 0.0.9


Follow ups