← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/gpgkey-fks-read into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/gpgkey-fks-read into lp:launchpad with lp:~wgrant/launchpad/gpgkey-fks-no-garbo as a prerequisite.

Commit message:
Read GPGKey fingerprint columns rather than the integer FK.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/gpgkey-fks-read/+merge/287804

Read GPGKey fingerprint columns rather than the integer FK.

Still setting the old columns until everything reads from the new.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/gpgkey-fks-read into lp:launchpad.
=== modified file 'lib/lp/archivepublisher/archivesigningkey.py'
--- lib/lp/archivepublisher/archivesigningkey.py	2016-03-02 17:51:59 +0000
+++ lib/lp/archivepublisher/archivesigningkey.py	2016-03-02 17:51:59 +0000
@@ -27,6 +27,7 @@
     GPGKeyAlgorithm,
     IGPGHandler,
     )
+from lp.services.propertycache import get_property_cache
 
 
 @implementer(IArchiveSigningKey)
@@ -71,9 +72,10 @@
             if default_ppa.signing_key is None:
                 IArchiveSigningKey(default_ppa).generateSigningKey()
             key = default_ppa.signing_key
-            self.archive.signing_key = key
+            self.archive._signing_key = key
             self.archive.signing_key_owner = key.owner
-            self.archive._signing_key_fingerprint = key.fingerprint
+            self.archive.signing_key_fingerprint = key.fingerprint
+            del get_property_cache(self.archive).signing_key
             return
 
         key_displayname = (
@@ -111,9 +113,10 @@
         key = getUtility(IGPGKeySet).new(
             key_owner, pub_key.keyid, pub_key.fingerprint, pub_key.keysize,
             algorithm, active=True, can_encrypt=pub_key.can_encrypt)
-        self.archive.signing_key = key
+        self.archive._signing_key = key
         self.archive.signing_key_owner = key.owner
-        self.archive._signing_key_fingerprint = key.fingerprint
+        self.archive.signing_key_fingerprint = key.fingerprint
+        del get_property_cache(self.archive).signing_key
 
     def signRepository(self, suite):
         """See `IArchiveSigningKey`."""

=== modified file 'lib/lp/archivepublisher/tests/archive-signing.txt'
--- lib/lp/archivepublisher/tests/archive-signing.txt	2015-10-01 10:25:19 +0000
+++ lib/lp/archivepublisher/tests/archive-signing.txt	2016-03-02 17:51:59 +0000
@@ -104,8 +104,8 @@
 
 And use it as the Mark's PPA signing key.
 
-    >>> mark.archive.signing_key = a_key
-
+    >>> mark.archive.signing_key_owner = a_key.owner
+    >>> mark.archive.signing_key_fingerprint = a_key.fingerprint
     >>> print mark.archive.signing_key_fingerprint
     ABCDEF0123456789ABCDDCBA0000111112345678
 
@@ -286,8 +286,11 @@
 simulating the situation when a the default PPA and a named-ppas get
 created within the same cycle of the key-generator process.
 
+    >>> from lp.services.propertycache import get_property_cache
     >>> login('foo.bar@xxxxxxxxxxxxx')
-    >>> named_ppa.signing_key = None
+    >>> named_ppa.signing_key_owner = None
+    >>> named_ppa.signing_key_fingerprint = None
+    >>> del get_property_cache(named_ppa).signing_key
     >>> login(ANONYMOUS)
 
     >>> print named_ppa.signing_key
@@ -312,8 +315,12 @@
 We will reset the signing-keys for both PPA of Celso.
 
     >>> login('foo.bar@xxxxxxxxxxxxx')
-    >>> cprov.archive.signing_key = None
-    >>> named_ppa.signing_key = None
+    >>> cprov.archive.signing_key_owner = None
+    >>> cprov.archive.signing_key_fingerprint = None
+    >>> del get_property_cache(cprov.archive).signing_key
+    >>> named_ppa.signing_key_owner = None
+    >>> named_ppa.signing_key_fingerprint = None
+    >>> del get_property_cache(named_ppa).signing_key
     >>> login(ANONYMOUS)
 
     >>> print cprov.archive.signing_key
@@ -365,7 +372,9 @@
 Celso's default PPA will uses the testing signing key.
 
     >>> login('foo.bar@xxxxxxxxxxxxx')
-    >>> cprov.archive.signing_key = signing_key
+    >>> cprov.archive.signing_key_owner = signing_key.owner
+    >>> cprov.archive.signing_key_fingerprint = signing_key.fingerprint
+    >>> del get_property_cache(cprov.archive).signing_key
     >>> login(ANONYMOUS)
 
 When signing repositores we assert they contain the right format and
@@ -437,7 +446,9 @@
 Finally, if we try to sign a repository for which the archive doesn't
 have a 'signing_key' set,  it raises an error.
 
-    >>> cprov.archive.signing_key = None
+    >>> cprov.archive.signing_key_owner = None
+    >>> cprov.archive.signing_key_fingerprint = None
+    >>> del get_property_cache(cprov.archive).signing_key
 
     >>> archive_signing_key.signRepository(test_suite)
     Traceback (most recent call last):

=== modified file 'lib/lp/archivepublisher/tests/test_publishdistro.py'
--- lib/lp/archivepublisher/tests/test_publishdistro.py	2016-02-04 19:46:52 +0000
+++ lib/lp/archivepublisher/tests/test_publishdistro.py	2016-03-02 17:51:59 +0000
@@ -246,7 +246,9 @@
         self.addCleanup(tac.tearDown)
         key_path = os.path.join(gpgkeysdir, 'ppa-sample@xxxxxxxxxxxxxxxxx')
         IArchiveSigningKey(cprov.archive).setSigningKey(key_path)
-        name16.archive.signing_key = cprov.archive.signing_key
+        name16.archive.signing_key_owner = cprov.archive.signing_key_owner
+        name16.archive.signing_key_fingerprint = (
+            cprov.archive.signing_key_fingerprint)
 
         self.layer.txn.commit()
 

=== modified file 'lib/lp/archiveuploader/tests/upload-karma.txt'
--- lib/lp/archiveuploader/tests/upload-karma.txt	2016-03-01 12:40:37 +0000
+++ lib/lp/archiveuploader/tests/upload-karma.txt	2016-03-02 17:51:59 +0000
@@ -51,8 +51,16 @@
     >>> from lp.registry.interfaces.gpg import IGPGKeySet
     >>> from lp.registry.interfaces.person import IPersonSet
     >>> name16 = getUtility(IPersonSet).getByName('name16')
+<<<<<<< TREE
     >>> key = getUtility(IGPGKeySet).getGPGKeysForPerson(name16)[0]
     >>> removeSecurityProxy(foo_src.queue_root).signing_key = key
+=======
+    >>> key = getUtility(IGPGKeySet).getGPGKeysForPeople([name16])[0]
+    >>> removeSecurityProxy(foo_src.queue_root).signing_key_owner = (
+    ...     key.owner)
+    >>> removeSecurityProxy(foo_src.queue_root).signing_key_fingerprint = (
+    ...     key.fingerprint)
+>>>>>>> MERGE-SOURCE
     >>> transaction.commit()
     >>> foo_src.queue_root.acceptFromQueue()
     Karma added: action=distributionuploadaccepted, distribution=ubuntu

=== modified file 'lib/lp/registry/browser/tests/test_codeofconduct.py'
--- lib/lp/registry/browser/tests/test_codeofconduct.py	2012-11-08 10:48:29 +0000
+++ lib/lp/registry/browser/tests/test_codeofconduct.py	2016-03-02 17:51:59 +0000
@@ -70,7 +70,8 @@
     def sign_coc(self, user, gpg_key):
         """Return a SignedCodeOfConduct using dummy text."""
         signed_coc = SignedCodeOfConduct(
-            owner=user, signingkey=gpg_key,
+            owner=user, signing_key_fingerprint=gpg_key.fingerprint,
+            signing_key_owner=gpg_key.owner,
             signedcode="Dummy CoC signed text.", active=True)
         return signed_coc
 

=== modified file 'lib/lp/registry/browser/tests/test_distroseries.py'
--- lib/lp/registry/browser/tests/test_distroseries.py	2016-01-26 15:47:37 +0000
+++ lib/lp/registry/browser/tests/test_distroseries.py	2016-03-02 17:51:59 +0000
@@ -941,8 +941,11 @@
                             sourcename=spr.sourcepackagename.name,
                             distroseries=derived_series))
                 else:
-                    removeSecurityProxy(spr).dscsigningkey = (
-                        self.factory.makeGPGKey(owner=spr.creator))
+                    key = self.factory.makeGPGKey(owner=spr.creator)
+                    removeSecurityProxy(spr).signing_key_owner = key.owner
+                    removeSecurityProxy(spr).signing_key_fingerprint = (
+                        key.fingerprint)
+                    del get_property_cache(spr).dscsigningkey
 
         def flush_and_render():
             flush_database_caches()
@@ -1357,8 +1360,12 @@
         # each difference row.
         dsd = self.makePackageUpgrade()
         uploader = self.factory.makePerson()
-        removeSecurityProxy(dsd.source_package_release).dscsigningkey = (
-            self.factory.makeGPGKey(uploader))
+        key = self.factory.makeGPGKey(uploader)
+        naked_spr = removeSecurityProxy(
+            dsd.source_package_release.sourcepackagerelease)
+        naked_spr.signing_key_fingerprint = key.fingerprint
+        naked_spr.signing_key_owner = key.owner
+        del get_property_cache(naked_spr).dscsigningkey
         view = self.makeView(dsd.derived_series)
         root = html.fromstring(view())
         [creator_cell] = root.cssselect(
@@ -2433,8 +2440,12 @@
         dsd = self.factory.makeDistroSeriesDifference(
             difference_type=missing_type)
         uploader = self.factory.makePerson()
-        naked_spr = removeSecurityProxy(dsd.parent_source_package_release)
-        naked_spr.dscsigningkey = self.factory.makeGPGKey(uploader)
+        key = self.factory.makeGPGKey(uploader)
+        naked_spr = removeSecurityProxy(
+            dsd.parent_source_package_release.sourcepackagerelease)
+        naked_spr.signing_key_fingerprint = key.fingerprint
+        naked_spr.signing_key_owner = key.owner
+        del get_property_cache(naked_spr).dscsigningkey
         with person_logged_in(self.simple_user):
             view = create_initialized_view(
                 dsd.derived_series, '+missingpackages',

=== modified file 'lib/lp/registry/interfaces/gpg.py'
--- lib/lp/registry/interfaces/gpg.py	2016-03-01 14:15:26 +0000
+++ lib/lp/registry/interfaces/gpg.py	2016-03-02 17:51:59 +0000
@@ -78,8 +78,16 @@
         inactive ones.
         """
 
+<<<<<<< TREE
     def getGPGKeysForPerson(person, active=True):
         """Return OpenGPG keys for a person.
+=======
+    def getByFingerprints(fingerprints):
+        """Get multiple OpenPGP keys by their fingerprints."""
+
+    def getGPGKeys(ownerid=None, active=True):
+        """Return OpenPGP keys ordered by id.
+>>>>>>> MERGE-SOURCE
 
         :returns: a list of IGPGKey instances.
         """

=== modified file 'lib/lp/registry/model/codeofconduct.py'
--- lib/lp/registry/model/codeofconduct.py	2016-03-02 17:51:59 +0000
+++ lib/lp/registry/model/codeofconduct.py	2016-03-02 17:51:59 +0000
@@ -49,6 +49,7 @@
     format_address,
     simple_sendmail,
     )
+from lp.services.propertycache import cachedproperty
 from lp.services.webapp import canonical_url
 
 
@@ -180,7 +181,7 @@
 
     signedcode = StringCol(dbName='signedcode', notNull=False, default=None)
 
-    signingkey = ForeignKey(foreignKey="GPGKey", dbName="signingkey",
+    _signingkey = ForeignKey(foreignKey="GPGKey", dbName="signingkey",
                             notNull=False, default=None)
     signing_key_fingerprint = Unicode()
 
@@ -195,6 +196,12 @@
 
     active = BoolCol(dbName='active', notNull=True, default=False)
 
+    @cachedproperty
+    def signingkey(self):
+        if self.signing_key_fingerprint is not None:
+            return getUtility(IGPGKeySet).getByFingerprint(
+                self.signing_key_fingerprint)
+
     @property
     def displayname(self):
         """Build a Fancy Title for CoC."""
@@ -308,7 +315,7 @@
 
         # Store the signature
         signed = SignedCodeOfConduct(
-            owner=user, signingkey=gpg,
+            owner=user, _signingkey=gpg,
             signing_key_fingerprint=gpg.fingerprint if gpg else None,
             signedcode=signedcode, active=True)
 

=== modified file 'lib/lp/registry/model/distroseries.py'
--- lib/lp/registry/model/distroseries.py	2016-03-02 17:51:59 +0000
+++ lib/lp/registry/model/distroseries.py	2016-03-02 17:51:59 +0000
@@ -1164,7 +1164,7 @@
             architecturehintlist=architecturehintlist, component=component,
             creator=creator, urgency=urgency, changelog=changelog,
             changelog_entry=changelog_entry, dsc=dsc,
-            dscsigningkey=dscsigningkey,
+            _dscsigningkey=dscsigningkey,
             signing_key_owner=dscsigningkey.owner if dscsigningkey else None,
             signing_key_fingerprint=(
                 dscsigningkey.fingerprint if dscsigningkey else None),
@@ -1353,7 +1353,7 @@
         return PackageUpload(
             distroseries=self, status=PackageUploadStatus.NEW,
             pocket=pocket, archive=archive, changesfile=changes_file_alias,
-            signing_key=signing_key,
+            _signing_key=signing_key,
             signing_key_owner=signing_key.owner if signing_key else None,
             signing_key_fingerprint=(
                 signing_key.fingerprint if signing_key else None),

=== modified file 'lib/lp/registry/model/distroseriesdifference.py'
--- lib/lp/registry/model/distroseriesdifference.py	2015-07-08 16:05:11 +0000
+++ lib/lp/registry/model/distroseriesdifference.py	2016-03-02 17:51:59 +0000
@@ -330,17 +330,13 @@
         SourcePackageRecipeBuild, sprs,
         ("source_package_recipe_build_id",))
 
-    # SourcePackageRelease.uploader can end up getting the owner of
-    # the DSC signing key.
-    gpgkeys = bulk.load_related(GPGKey, sprs, ("dscsigningkeyID",))
-
     # Load DistroSeriesDifferenceComment owners, SourcePackageRecipeBuild
     # requesters, GPGKey owners, and SourcePackageRelease creators.
     person_ids = set().union(
         (dsdc.message.ownerID for dsdc in latest_comments),
         (sprb.requester_id for sprb in sprbs),
-        (gpgkey.ownerID for gpgkey in gpgkeys),
-        (spr.creatorID for spr in sprs))
+        (spr.creatorID for spr in sprs),
+        (spr.signing_key_owner_id for spr in sprs))
     uploaders = getUtility(IPersonSet).getPrecachedPersonsFromIDs(
         person_ids, need_validity=True)
     list(uploaders)

=== modified file 'lib/lp/registry/model/gpgkey.py'
--- lib/lp/registry/model/gpgkey.py	2016-03-01 14:15:26 +0000
+++ lib/lp/registry/model/gpgkey.py	2016-03-02 17:51:59 +0000
@@ -19,6 +19,7 @@
     IGPGKeySet,
     )
 from lp.services.database.enumcol import EnumCol
+from lp.services.database.interfaces import IStore
 from lp.services.database.sqlbase import (
     SQLBase,
     sqlvalues,
@@ -95,7 +96,24 @@
             return default
         return result
 
+<<<<<<< TREE
     def getGPGKeysForPerson(self, owner, active=True):
+=======
+    def getByFingerprints(self, fingerprints):
+        """See `IGPGKeySet`"""
+        return IStore(GPGKey).find(
+            GPGKey, GPGKey.fingerprint.is_in(fingerprints))
+
+    def getGPGKeysForPeople(self, people):
+        """See `IGPGKeySet`"""
+        return GPGKey.select("""
+            GPGKey.owner IN %s AND
+            GPGKey.active = True
+            """ % sqlvalues([person.id for person in people]))
+
+    def getGPGKeys(self, ownerid=None, active=True):
+        """See `IGPGKeySet`"""
+>>>>>>> MERGE-SOURCE
         if active is False:
             query = """
                 active = false

=== modified file 'lib/lp/soyuz/configure.zcml'
--- lib/lp/soyuz/configure.zcml	2016-03-02 17:51:59 +0000
+++ lib/lp/soyuz/configure.zcml	2016-03-02 17:51:59 +0000
@@ -389,9 +389,9 @@
             set_schema="lp.soyuz.interfaces.archive.IArchiveRestricted"/>
         <require
             permission="launchpad.InternalScriptsOnly"
-            attributes="signing_key_owner _signing_key_fingerprint"
-            set_attributes="distribution signing_key signing_key_owner
-                            _signing_key_fingerprint"/>
+            attributes="signing_key_owner"
+            set_attributes="distribution _signing_key signing_key_owner
+                            signing_key_fingerprint"/>
     </class>
     <adapter
         for="lp.soyuz.interfaces.archive.IArchive"

=== modified file 'lib/lp/soyuz/doc/distroseriesqueue-notify.txt'
--- lib/lp/soyuz/doc/distroseriesqueue-notify.txt	2016-02-29 18:48:23 +0000
+++ lib/lp/soyuz/doc/distroseriesqueue-notify.txt	2016-03-02 17:51:59 +0000
@@ -109,8 +109,15 @@
 
     >>> from zope.security.proxy import removeSecurityProxy
     >>> from lp.registry.interfaces.gpg import IGPGKeySet
+<<<<<<< TREE
     >>> gpgkey = getUtility(IGPGKeySet).getByFingerprint('ABCDEF0123456789ABCDDCBA0000111112345678')
     >>> removeSecurityProxy(netapplet_upload).signing_key = gpgkey
+=======
+    >>> gpgkey = getUtility(IGPGKeySet).get(1)
+    >>> removeSecurityProxy(netapplet_upload).signing_key_owner = gpgkey.owner
+    >>> removeSecurityProxy(netapplet_upload).signing_key_fingerprint = (
+    ...     gpgkey.fingerprint)
+>>>>>>> MERGE-SOURCE
 
 Now request the email:
 

=== modified file 'lib/lp/soyuz/doc/publishing.txt'
--- lib/lp/soyuz/doc/publishing.txt	2015-02-19 01:35:33 +0000
+++ lib/lp/soyuz/doc/publishing.txt	2016-03-02 17:51:59 +0000
@@ -23,7 +23,9 @@
     >>> from lp.registry.model.gpgkey import GPGKey
     >>> name16 = getUtility(IPersonSet).getByName('name16')
     >>> fake_signer = GPGKey.selectOneBy(owner=name16)
-    >>> spph.sourcepackagerelease.dscsigningkey = fake_signer
+    >>> spph.sourcepackagerelease.signing_key_owner = fake_signer.owner
+    >>> spph.sourcepackagerelease.signing_key_fingerprint = (
+    ...     fake_signer.fingerprint)
 
 Verify if the object follows its interface contracts:
 
@@ -86,7 +88,10 @@
 
 The signer can also be None for packages that were synced (e.g. from Debian):
 
-    >>> spph.sourcepackagerelease.dscsigningkey = None
+    >>> from lp.services.propertycache import get_property_cache
+    >>> spph.sourcepackagerelease.signing_key_owner = None
+    >>> spph.sourcepackagerelease.signing_key_fingerprint = None
+    >>> del get_property_cache(spph.sourcepackagerelease).dscsigningkey
     >>> print spph.package_signer
     None
 

=== modified file 'lib/lp/soyuz/model/archive.py'
--- lib/lp/soyuz/model/archive.py	2016-03-02 17:51:59 +0000
+++ lib/lp/soyuz/model/archive.py	2016-03-02 17:51:59 +0000
@@ -77,6 +77,7 @@
 from lp.registry.errors import NoSuchDistroSeries
 from lp.registry.interfaces.distroseries import IDistroSeriesSet
 from lp.registry.interfaces.distroseriesparent import IDistroSeriesParentSet
+from lp.registry.interfaces.gpg import IGPGKeySet
 from lp.registry.interfaces.person import (
     IPersonSet,
     validate_person,
@@ -338,11 +339,11 @@
 
     date_created = UtcDateTimeCol(dbName='date_created')
 
-    signing_key = ForeignKey(
+    _signing_key = ForeignKey(
         foreignKey='GPGKey', dbName='signing_key', notNull=False)
     signing_key_owner_id = Int(name="signing_key_owner")
     signing_key_owner = Reference(signing_key_owner_id, 'Person.id')
-    _signing_key_fingerprint = Unicode(name="signing_key_fingerprint")
+    signing_key_fingerprint = Unicode()
 
     relative_build_score = IntCol(
         dbName='relative_build_score', notNull=True, default=0)
@@ -391,6 +392,13 @@
         """See `IArchive`."""
         return self.displayname
 
+    @cachedproperty
+    def signing_key(self):
+        """See `IArchive`."""
+        if self.signing_key_fingerprint is not None:
+            return getUtility(IGPGKeySet).getByFingerprint(
+                self.signing_key_fingerprint)
+
     @property
     def is_ppa(self):
         """See `IArchive`."""
@@ -518,13 +526,6 @@
         return urlappend(
             db_pubconf.base_url, self.distribution.name + postfix)
 
-    @property
-    def signing_key_fingerprint(self):
-        if self.signing_key is not None:
-            return self.signing_key.fingerprint
-
-        return None
-
     def getBuildRecords(self, build_state=None, name=None, pocket=None,
                         arch_tag=None, user=None, binary_only=True):
         """See IHasBuildRecords"""
@@ -679,7 +680,6 @@
         def eager_load(rows):
             # \o/ circular imports.
             from lp.registry.model.distroseries import DistroSeries
-            from lp.registry.model.gpgkey import GPGKey
             ids = set(map(attrgetter('distroseriesID'), rows))
             ids.discard(None)
             if ids:
@@ -698,10 +698,14 @@
             ids.discard(None)
             if ids:
                 list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(ids))
-            ids = set(map(attrgetter('dscsigningkeyID'), releases))
-            ids.discard(None)
-            if ids:
-                list(store.find(GPGKey, GPGKey.id.is_in(ids)))
+            keys = {
+                key.fingerprint: key for key in
+                getUtility(IGPGKeySet).getByFingerprints(
+                    set(map(attrgetter('signing_key_fingerprint'), releases))
+                    - set([None]))}
+            for spr in releases:
+                get_property_cache(spr).dscsigningkey = keys.get(
+                    spr.signing_key_fingerprint)
         return DecoratedResultSet(resultset, pre_iter_hook=eager_load)
 
     def getSourcesForDeletion(self, name=None, status=None, distroseries=None):
@@ -2537,9 +2541,9 @@
         new_archive = Archive(
             owner=owner, distribution=distribution, name=name,
             displayname=displayname, description=description,
-            purpose=purpose, publish=publish, signing_key=signing_key,
+            purpose=purpose, publish=publish, _signing_key=signing_key,
             signing_key_owner=signing_key.owner if signing_key else None,
-            _signing_key_fingerprint=(
+            signing_key_fingerprint=(
                 signing_key.fingerprint if signing_key else None),
             require_virtualized=require_virtualized)
 
@@ -2631,8 +2635,8 @@
                  SourcePackagePublishingHistory.archive == Archive.id))
         results = IStore(Archive).using(*origin).find(
             Archive,
-            Archive.signing_key == None, Archive.purpose == ArchivePurpose.PPA,
-            Archive._enabled == True)
+            Archive.signing_key_fingerprint == None,
+            Archive.purpose == ArchivePurpose.PPA, Archive._enabled == True)
         results.order_by(Archive.date_created)
         return results.config(distinct=True)
 

=== modified file 'lib/lp/soyuz/model/queue.py'
--- lib/lp/soyuz/model/queue.py	2016-03-02 17:51:59 +0000
+++ lib/lp/soyuz/model/queue.py	2016-03-02 17:51:59 +0000
@@ -46,6 +46,7 @@
 from lp.archivepublisher.config import getPubConfig
 from lp.archivepublisher.customupload import CustomUploadError
 from lp.archiveuploader.tagfiles import parse_tagfile_content
+from lp.registry.interfaces.gpg import IGPGKeySet
 from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.registry.model.sourcepackagename import SourcePackageName
 from lp.services.auditor.client import AuditorClient
@@ -184,7 +185,7 @@
 
     archive = ForeignKey(dbName="archive", foreignKey="Archive", notNull=True)
 
-    signing_key = ForeignKey(
+    _signing_key = ForeignKey(
         foreignKey='GPGKey', dbName='signing_key', notNull=False)
     signing_key_owner_id = Int(name="signing_key_owner")
     signing_key_owner = Reference(signing_key_owner_id, 'Person.id')
@@ -291,6 +292,12 @@
                 })
         return properties
 
+    @cachedproperty
+    def signing_key(self):
+        if self.signing_key_fingerprint is not None:
+            return getUtility(IGPGKeySet).getByFingerprint(
+                self.signing_key_fingerprint)
+
     @property
     def copy_source_archive(self):
         """See `IPackageUpload`."""

=== modified file 'lib/lp/soyuz/model/sourcepackagerelease.py'
--- lib/lp/soyuz/model/sourcepackagerelease.py	2016-03-02 17:51:59 +0000
+++ lib/lp/soyuz/model/sourcepackagerelease.py	2016-03-02 17:51:59 +0000
@@ -35,10 +35,12 @@
 from storm.store import Store
 from zope.component import getUtility
 from zope.interface import implementer
+from zope.security.proxy import removeSecurityProxy
 
 from lp.app.errors import NotFoundError
 from lp.archiveuploader.utils import determine_source_file_type
 from lp.buildmaster.enums import BuildStatus
+from lp.registry.interfaces.gpg import IGPGKeySet
 from lp.registry.interfaces.person import validate_public_person
 from lp.registry.interfaces.sourcepackage import (
     SourcePackageType,
@@ -89,7 +91,7 @@
     maintainer = ForeignKey(
         dbName='maintainer', foreignKey='Person',
         storm_validator=validate_public_person, notNull=True)
-    dscsigningkey = ForeignKey(foreignKey='GPGKey', dbName='dscsigningkey')
+    _dscsigningkey = ForeignKey(foreignKey='GPGKey', dbName='dscsigningkey')
     signing_key_owner_id = Int(name="signing_key_owner")
     signing_key_owner = Reference(signing_key_owner_id, 'Person.id')
     signing_key_fingerprint = Unicode()
@@ -172,6 +174,15 @@
             "UPDATE sourcepackagerelease SET copyright=%s WHERE id=%s",
             (content, self.id))
 
+    @cachedproperty
+    def dscsigningkey(self):
+        if self.signing_key_fingerprint is not None:
+            # Stripping proxy as some tests expect this former FK to
+            # hold an unsecured object. self is always proxied by things
+            # that hold it, so no issue here.
+            return removeSecurityProxy(getUtility(IGPGKeySet).getByFingerprint(
+                self.signing_key_fingerprint))
+
     @property
     def user_defined_fields(self):
         """See `IBinaryPackageRelease`."""
@@ -364,8 +375,8 @@
         """See `ISourcePackageRelease`"""
         if self.source_package_recipe_build is not None:
             return self.source_package_recipe_build.requester
-        if self.dscsigningkey is not None:
-            return self.dscsigningkey.owner
+        if self.signing_key_owner is not None:
+            return self.signing_key_owner
         return None
 
     @property

=== modified file 'lib/lp/soyuz/scripts/gina/handlers.py'
--- lib/lp/soyuz/scripts/gina/handlers.py	2016-03-02 17:51:59 +0000
+++ lib/lp/soyuz/scripts/gina/handlers.py	2016-03-02 17:51:59 +0000
@@ -615,7 +615,7 @@
             component=componentID,
             sourcepackagename=name.id,
             maintainer=maintainer.id,
-            dscsigningkey=key,
+            _dscsigningkey=key,
             signing_key_owner=key.owner if key else None,
             signing_key_fingerprint=key.fingerprint if key else None,
             urgency=ChangesFile.urgency_map[src.urgency],

=== modified file 'lib/lp/soyuz/scripts/tests/test_ppakeygenerator.py'
--- lib/lp/soyuz/scripts/tests/test_ppakeygenerator.py	2016-02-29 18:48:23 +0000
+++ lib/lp/soyuz/scripts/tests/test_ppakeygenerator.py	2016-03-02 17:51:59 +0000
@@ -10,6 +10,7 @@
 from lp.registry.interfaces.distribution import IDistributionSet
 from lp.registry.interfaces.gpg import IGPGKeySet
 from lp.registry.interfaces.person import IPersonSet
+from lp.services.propertycache import get_property_cache
 from lp.services.scripts.base import LaunchpadScriptFailure
 from lp.soyuz.interfaces.archive import IArchiveSet
 from lp.soyuz.scripts.ppakeygenerator import PPAKeyGenerator
@@ -50,9 +51,16 @@
         key_generator.txn = txn
 
         def fake_key_generation(archive):
+<<<<<<< TREE
             a_key = getUtility(IGPGKeySet).getByFingerprint(
                 'ABCDEF0123456789ABCDDCBA0000111112345678')
             archive.signing_key = a_key
+=======
+            a_key = getUtility(IGPGKeySet).get(1)
+            archive.signing_key_fingerprint = a_key.fingerprint
+            archive.signing_key_owner = a_key.owner
+            del get_property_cache(archive).signing_key
+>>>>>>> MERGE-SOURCE
 
         key_generator.generateKey = fake_key_generation
 
@@ -69,9 +77,15 @@
     def testPPAAlreadyHasSigningKey(self):
         """Raises an error if the specified PPA already has a signing_key."""
         cprov = getUtility(IPersonSet).getByName('cprov')
+<<<<<<< TREE
         a_key = getUtility(IGPGKeySet).getByFingerprint(
             'ABCDEF0123456789ABCDDCBA0000111112345678')
         cprov.archive.signing_key = a_key
+=======
+        a_key = getUtility(IGPGKeySet).get(1)
+        cprov.archive.signing_key_fingerprint = a_key.fingerprint
+        cprov.archive.signing_key_owner = a_key.owner
+>>>>>>> MERGE-SOURCE
 
         key_generator = self._getKeyGenerator(
             archive_reference='~cprov/ubuntu/ppa')

=== modified file 'lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt'
--- lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt	2015-04-09 05:16:37 +0000
+++ lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt	2016-03-02 17:51:59 +0000
@@ -23,7 +23,9 @@
     >>> cprov_ppa = cprov_db.archive
     >>> for pub in cprov_ppa.getPublishedSources():
     ...     pub = removeSecurityProxy(pub)
-    ...     pub.sourcepackagerelease.dscsigningkey = fake_signer
+    ...     pub.sourcepackagerelease.signing_key_owner = fake_signer.owner
+    ...     pub.sourcepackagerelease.signing_key_fingerprint = (
+    ...         fake_signer.fingerprint)
     >>> logout()
     >>> cprov_webservice = webservice_for_person(
     ...     cprov_db, permission=OAuthPermission.WRITE_PUBLIC)
@@ -159,7 +161,8 @@
     >>> login("foo.bar@xxxxxxxxxxxxx")
     >>> for pub in cprov_ppa.getPublishedSources():
     ...     pub = removeSecurityProxy(pub)
-    ...     pub.sourcepackagerelease.dscsigningkey = None
+    ...     pub.sourcepackagerelease.signing_key_owner = None
+    ...     pub.sourcepackagerelease.signing_key_fingerprint = None
     >>> logout()
 
 Query the source again:

=== modified file 'lib/lp/soyuz/tests/test_archive.py'
--- lib/lp/soyuz/tests/test_archive.py	2016-01-05 15:06:24 +0000
+++ lib/lp/soyuz/tests/test_archive.py	2016-03-02 17:51:59 +0000
@@ -42,7 +42,10 @@
 from lp.services.database.interfaces import IStore
 from lp.services.database.sqlbase import sqlvalues
 from lp.services.job.interfaces.job import JobStatus
-from lp.services.propertycache import clear_property_cache
+from lp.services.propertycache import (
+    clear_property_cache,
+    get_property_cache,
+    )
 from lp.services.webapp.interfaces import OAuthPermission
 from lp.services.worlddata.interfaces.country import ICountrySet
 from lp.soyuz.adapters.archivedependencies import (
@@ -3456,7 +3459,11 @@
             owner=person, purpose=ArchivePurpose.PPA, name="ppa")
         self.assertEqual(ppa, person.archive)
         self.factory.makeGPGKey(person)
-        removeSecurityProxy(person.archive).signing_key = person.gpg_keys[0]
+        key = person.gpg_keys[0]
+        removeSecurityProxy(person.archive).signing_key_owner = key.owner
+        removeSecurityProxy(person.archive).signing_key_fingerprint = (
+            key.fingerprint)
+        del get_property_cache(person.archive).signing_key
         ppa_with_key = self.factory.makeArchive(
             owner=person, purpose=ArchivePurpose.PPA)
         self.assertEqual(person.gpg_keys[0], ppa_with_key.signing_key)

=== modified file 'lib/lp/soyuz/tests/test_build_notify.py'
--- lib/lp/soyuz/tests/test_build_notify.py	2015-09-11 12:20:23 +0000
+++ lib/lp/soyuz/tests/test_build_notify.py	2016-03-02 17:51:59 +0000
@@ -15,6 +15,7 @@
 from lp.registry.interfaces.person import IPersonSet
 from lp.services.config import config
 from lp.services.mail.sendmail import format_address_for_person
+from lp.services.propertycache import get_property_cache
 from lp.services.webapp import canonical_url
 from lp.soyuz.enums import ArchivePurpose
 from lp.soyuz.interfaces.publishing import PackagePublishingPocket
@@ -83,7 +84,11 @@
                     self.factory.getUniqueInteger(), status.value),
                 distroseries=self.distroseries, architecturehintlist='any',
                 creator=self.creator, archive=archive)
-            spph.sourcepackagerelease.dscsigningkey = self.gpgkey
+            spph.sourcepackagerelease._dscsigningkey = self.gpgkey
+            spph.sourcepackagerelease.signing_key_fingerprint = (
+                self.gpgkey.fingerprint)
+            spph.sourcepackagerelease.signing_key_owner = (
+                self.gpgkey.owner)
             [build] = spph.createMissingBuilds()
             with person_logged_in(self.admin):
                 build.updateStatus(BuildStatus.BUILDING, builder=self.builder)
@@ -432,7 +437,9 @@
         build = self.builds[BuildStatus.FAILEDTOBUILD.value]
         spr = build.current_source_publication.sourcepackagerelease
         # Push past the security proxy
-        removeSecurityProxy(spr).dscsigningkey = key
+        removeSecurityProxy(spr).signing_key_owner = key.owner
+        removeSecurityProxy(spr).signing_key_fingerprint = key.fingerprint
+        del get_property_cache(spr).dscsigningkey
         with dbuser(config.builddmaster.dbuser):
             build.notify()
         expected_reasons = [