← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~stevenk/launchpad/bugs-use-information_type-redux into lp:launchpad

 

Steve Kowalik has proposed merging lp:~stevenk/launchpad/bugs-use-information_type-redux into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~stevenk/launchpad/bugs-use-information_type-redux/+merge/99236

Resurrect the rollback of using IBug.information_type that happened in r15006. The original MPs description is as follows:

Rename IBug.{private,security_related} to IBug._{private,security_related} as the next step in switching to information_type. This branch also adds IBug.{private,security_related} back as a property that depends on information_type if it is set.

Fixed some tests that assumed that IBug.{private,security_related} was something they could set directly.

I cleaned up a small amount of lint.


Further to those changes, I have created a new method, convert_to_information_type, which returns the relevant InformationType given a private and security_related parameter, which allows me to remove IBug._setInformationType() and to set the information_type of the bug right at the initial insert. I have added a test which checks that case.
-- 
https://code.launchpad.net/~stevenk/launchpad/bugs-use-information_type-redux/+merge/99236
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/bugs-use-information_type-redux into lp:launchpad.
=== modified file 'lib/lp/bugs/adapters/bug.py'
--- lib/lp/bugs/adapters/bug.py	2010-08-20 20:31:18 +0000
+++ lib/lp/bugs/adapters/bug.py	2012-03-25 23:40:26 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Resources having to do with Launchpad bugs."""
@@ -7,11 +7,14 @@
 __all__ = [
     'bugcomment_to_entry',
     'bugtask_to_privacy',
+    'convert_to_information_type',
     ]
 
 from lazr.restful.interfaces import IEntry
 from zope.component import getMultiAdapter
 
+from lp.registry.enums import InformationType
+
 
 def bugcomment_to_entry(comment, version):
     """Will adapt to the bugcomment to the real IMessage.
@@ -22,9 +25,21 @@
     return getMultiAdapter(
         (comment.bugtask.bug.messages[comment.index], version), IEntry)
 
+
 def bugtask_to_privacy(bugtask):
     """Adapt the bugtask to the underlying bug (which implements IPrivacy).
 
     Needed because IBugTask does not implement IPrivacy.
     """
     return bugtask.bug
+
+
+def convert_to_information_type(private, security_related):
+    if private and security_related:
+        return InformationType.EMBARGOEDSECURITY
+    elif security_related:
+        return InformationType.UNEMBARGOEDSECURITY
+    elif private:
+        return InformationType.USERDATA
+    else:
+        return InformationType.PUBLIC

=== modified file 'lib/lp/bugs/browser/tests/test_bugsubscription_views.py'
--- lib/lp/bugs/browser/tests/test_bugsubscription_views.py	2012-03-24 04:42:32 +0000
+++ lib/lp/bugs/browser/tests/test_bugsubscription_views.py	2012-03-25 23:40:26 +0000
@@ -40,10 +40,6 @@
 from lp.testing.views import create_initialized_view
 
 
-ON = 'on'
-OFF = None
-
-
 class BugsubscriptionPrivacyTests(TestCaseWithFactory):
 
     layer = LaunchpadFunctionalLayer
@@ -52,7 +48,7 @@
         super(BugsubscriptionPrivacyTests, self).setUp()
         self.user = self.factory.makePerson()
         self.bug = self.factory.makeBug(owner=self.user)
-        removeSecurityProxy(self.bug).private = True
+        removeSecurityProxy(self.bug).setPrivate(True, self.user)
 
     def _assert_subscription_fails(self, team):
         with person_logged_in(self.user):

=== modified file 'lib/lp/bugs/mail/tests/test_handler.py'
--- lib/lp/bugs/mail/tests/test_handler.py	2012-03-24 04:42:32 +0000
+++ lib/lp/bugs/mail/tests/test_handler.py	2012-03-25 23:40:26 +0000
@@ -287,7 +287,7 @@
         notification = self.getLatestBugNotification()
         bug = notification.bug
         self.assertEqual('unsecure code', bug.title)
-        self.assertEqual(True, bug.security_related)
+        self.assertTrue(bug.security_related)
         self.assertEqual(['ajax'], bug.tags)
         self.assertEqual(1, len(bug.bugtasks))
         self.assertEqual(project, bug.bugtasks[0].target)
@@ -310,7 +310,7 @@
         notification = self.getLatestBugNotification()
         bug = notification.bug
         self.assertEqual('security issue', bug.title)
-        self.assertEqual(True, bug.security_related)
+        self.assertTrue(bug.security_related)
         self.assertEqual(1, len(bug.bugtasks))
         self.assertEqual(project, bug.bugtasks[0].target)
         recipients = set()

=== modified file 'lib/lp/bugs/model/bug.py'
--- lib/lp/bugs/model/bug.py	2012-03-24 04:42:32 +0000
+++ lib/lp/bugs/model/bug.py	2012-03-25 23:40:26 +0000
@@ -89,6 +89,7 @@
     )
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.app.validators import LaunchpadValidationError
+from lp.bugs.adapters.bug import convert_to_information_type
 from lp.bugs.adapters.bugchange import (
     BranchLinkedToBug,
     BranchUnlinkedFromBug,
@@ -157,7 +158,11 @@
     )
 from lp.code.interfaces.branchcollection import IAllBranches
 from lp.hardwaredb.interfaces.hwdb import IHWSubmissionBugSet
-from lp.registry.enums import InformationType
+from lp.registry.enums import (
+    InformationType,
+    PRIVATE_INFORMATION_TYPES,
+    SECURITY_INFORMATION_TYPES,
+    )
 from lp.registry.interfaces.distribution import IDistribution
 from lp.registry.interfaces.distroseries import IDistroSeries
 from lp.registry.interfaces.person import (
@@ -347,12 +352,13 @@
         dbName='duplicateof', foreignKey='Bug', default=None)
     datecreated = UtcDateTimeCol(notNull=True, default=UTC_NOW)
     date_last_updated = UtcDateTimeCol(notNull=True, default=UTC_NOW)
-    private = BoolCol(notNull=True, default=False)
+    _private = BoolCol(dbName='private', notNull=True, default=False)
     date_made_private = UtcDateTimeCol(notNull=False, default=None)
     who_made_private = ForeignKey(
         dbName='who_made_private', foreignKey='Person',
         storm_validator=validate_public_person, default=None)
-    security_related = BoolCol(notNull=True, default=False)
+    _security_related = BoolCol(
+        dbName='security_related', notNull=True, default=False)
     information_type = EnumCol(
         enum=InformationType, default=InformationType.PUBLIC)
 
@@ -389,6 +395,20 @@
     heat_last_updated = UtcDateTimeCol(default=None)
     latest_patch_uploaded = UtcDateTimeCol(default=None)
 
+    @property
+    def private(self):
+        if self.information_type:
+            return self.information_type in PRIVATE_INFORMATION_TYPES
+        else:
+            return self._private
+
+    @property
+    def security_related(self):
+        if self.information_type:
+            return self.information_type in SECURITY_INFORMATION_TYPES
+        else:
+            return self._security_related
+
     @cachedproperty
     def _subscriber_cache(self):
         """Caches known subscribers."""
@@ -1697,16 +1717,6 @@
 
         return bugtask
 
-    def _setInformationType(self):
-        if self.private and self.security_related:
-            self.information_type = InformationType.EMBARGOEDSECURITY
-        elif self.private:
-            self.information_type = InformationType.USERDATA
-        elif self.security_related:
-            self.information_type = InformationType.UNEMBARGOEDSECURITY
-        else:
-            self.information_type = InformationType.PUBLIC
-
     def setPrivacyAndSecurityRelated(self, private, security_related, who):
         """ See `IBug`."""
         private_changed = False
@@ -1734,7 +1744,7 @@
                     raise BugCannotBePrivate(
                         "Multi-pillar bugs cannot be private.")
             private_changed = True
-            self.private = private
+            self._private = private
 
             if private:
                 self.who_made_private = who
@@ -1750,14 +1760,15 @@
 
         if self.security_related != security_related:
             security_related_changed = True
-            self.security_related = security_related
+            self._security_related = security_related
 
         if private_changed or security_related_changed:
             # Correct the heat for the bug immediately, so that we don't have
             # to wait for the next calculation job for the adjusted heat.
             self.updateHeat()
 
-        self._setInformationType()
+        self.information_type = convert_to_information_type(
+            self._private, self._security_related)
 
         if private_changed or security_related_changed:
             changed_fields = []
@@ -2829,9 +2840,6 @@
                 bug.subscribe(params.product.bug_supervisor, params.owner)
             else:
                 bug.subscribe(params.product.owner, params.owner)
-        else:
-            # nothing to do
-            pass
 
         # Create the task on a product if one was passed.
         if params.product:
@@ -2858,8 +2866,6 @@
         if notify_event:
             notify(event)
 
-        bug._setInformationType()
-
         # Calculate the bug's initial heat.
         bug.updateHeat()
 
@@ -2906,11 +2912,14 @@
                 date_made_private=params.datecreated,
                 who_made_private=params.owner)
 
+        information_type = convert_to_information_type(
+            params.private, params.security_related)
         bug = Bug(
             title=params.title, description=params.description,
-            private=params.private, owner=params.owner,
+            _private=params.private, owner=params.owner,
             datecreated=params.datecreated,
-            security_related=params.security_related,
+            _security_related=params.security_related,
+            information_type=information_type,
             **extra_params)
 
         if params.subscribe_owner:

=== modified file 'lib/lp/bugs/model/tests/test_bug.py'
--- lib/lp/bugs/model/tests/test_bug.py	2012-03-14 12:39:42 +0000
+++ lib/lp/bugs/model/tests/test_bug.py	2012-03-25 23:40:26 +0000
@@ -9,6 +9,7 @@
     )
 
 from pytz import UTC
+from storm.expr import Join
 from storm.store import Store
 from testtools.testcase import ExpectedException
 from zope.component import getUtility
@@ -970,6 +971,22 @@
             bug.setPrivate(True, bug.owner)
         self.assertEqual(InformationType.USERDATA, bug.information_type)
 
+    def test_information_type_does_not_leak(self):
+        product = self.factory.makeProduct()
+        with person_logged_in(product.owner):
+            product.addSubscription(product.owner, product.owner)
+        reporter = self.factory.makePerson()
+        bug = self.factory.makeBug(
+            private=True, product=product, owner=reporter)
+        recipients = Store.of(bug).using(
+            BugNotificationRecipient,
+            Join(BugNotification, BugNotification.bugID == bug.id)).find(
+            BugNotificationRecipient,
+            BugNotificationRecipient.bug_notificationID ==
+                BugNotification.id)
+        self.assertEqual(
+            [reporter], [recipient.person for recipient in recipients])
+
 
 class TestBugPrivateAndSecurityRelatedUpdatesPrivateProject(
         TestBugPrivateAndSecurityRelatedUpdatesMixin, TestCaseWithFactory):

=== modified file 'lib/lp/bugs/tests/test_bug_mirror_access_triggers.py'
--- lib/lp/bugs/tests/test_bug_mirror_access_triggers.py	2012-03-24 04:42:32 +0000
+++ lib/lp/bugs/tests/test_bug_mirror_access_triggers.py	2012-03-25 23:40:26 +0000
@@ -136,7 +136,7 @@
         bug = self.makeBugAndPolicies(private=True)
         self.assertIsNot(
             None, getUtility(IAccessArtifactSource).find([bug]).one())
-        bug.private = False
+        removeSecurityProxy(bug).setPrivate(False, bug.owner)
         self.assertIs(
             None, getUtility(IAccessArtifactSource).find([bug]).one())
 
@@ -144,7 +144,7 @@
         bug = self.makeBugAndPolicies(private=False)
         self.assertIs(
             None, getUtility(IAccessArtifactSource).find([bug]).one())
-        bug.private = True
+        removeSecurityProxy(bug).setPrivate(True, bug.owner)
         self.assertIsNot(
             None, getUtility(IAccessArtifactSource).find([bug]).one())
         self.assertEqual((1, 1), self.assertMirrored(bug))
@@ -158,7 +158,7 @@
         self.assertContentEqual(
             [InformationType.USERDATA],
             self.getPolicyTypesForArtifact(artifact))
-        bug.security_related = True
+        removeSecurityProxy(bug).setSecurityRelated(True, bug.owner)
         self.assertEqual((1, 1), self.assertMirrored(bug))
         self.assertContentEqual(
             [InformationType.EMBARGOEDSECURITY],

=== modified file 'lib/lp/registry/enums.py'
--- lib/lp/registry/enums.py	2012-03-24 04:42:32 +0000
+++ lib/lp/registry/enums.py	2012-03-25 23:40:26 +0000
@@ -9,7 +9,9 @@
     'DistroSeriesDifferenceType',
     'InformationType',
     'PersonTransferJobType',
+    'PRIVATE_INFORMATION_TYPES',
     'ProductJobType',
+    'SECURITY_INFORMATION_TYPES',
     'SharingPermission',
     ]
 
@@ -61,6 +63,15 @@
         """)
 
 
+PRIVATE_INFORMATION_TYPES = (
+    InformationType.EMBARGOEDSECURITY, InformationType.USERDATA,
+    InformationType.PROPRIETARY)
+
+
+SECURITY_INFORMATION_TYPES = (
+    InformationType.UNEMBARGOEDSECURITY, InformationType.EMBARGOEDSECURITY)
+
+
 class SharingPermission(DBEnumeratedType):
     """Sharing permission.
 

=== modified file 'lib/lp/registry/model/person.py'
--- lib/lp/registry/model/person.py	2012-03-24 04:42:32 +0000
+++ lib/lp/registry/model/person.py	2012-03-25 23:40:26 +0000
@@ -1744,14 +1744,14 @@
                     Bug,
                     Join(BugSubscription, BugSubscription.bug_id == Bug.id)),
                 where=And(
-                    Bug.private == True,
+                    Bug._private == True,
                     BugSubscription.person_id == self.id)),
             Select(
                 Bug.id,
                 tables=(
                     Bug,
                     Join(BugTask, BugTask.bugID == Bug.id)),
-                where=And(Bug.private == True, BugTask.assignee == self.id)),
+                where=And(Bug._private == True, BugTask.assignee == self.id)),
             limit=1))
         if private_bugs_involved.rowcount:
             raise TeamSubscriptionPolicyError(

=== modified file 'lib/lp/services/feeds/stories/xx-security.txt'
--- lib/lp/services/feeds/stories/xx-security.txt	2012-03-24 04:42:32 +0000
+++ lib/lp/services/feeds/stories/xx-security.txt	2012-03-25 23:40:26 +0000
@@ -1,16 +1,16 @@
-== Feeds do not display private bugs ==
+Feeds do not display private bugs
+=================================
 
 Feeds never contain private bugs, as we are serving feeds over HTTP.
 First, set all the bugs to private.
 
     >>> from zope.security.interfaces import Unauthorized
     >>> from BeautifulSoup import BeautifulStoneSoup as BSS
+    >>> from lp.services.database.lpstorm import IStore
+    >>> import transaction
     >>> from lp.bugs.model.bug import Bug
-    >>> bugs = Bug.select()
-    >>> for bug in bugs:
-    ...     bug.private = True
-    >>> from lp.services.database.sqlbase import flush_database_updates
-    >>> flush_database_updates()
+    >>> IStore(Bug).find(Bug).set(_private=True)
+    >>> transaction.commit()
 
 There should be zero entries in these feeds, since all the bugs are private.
 
@@ -26,7 +26,8 @@
     >>> BSS(browser.contents)('entry')
     []
 
-    >>> browser.open('http://feeds.launchpad.dev/~simple-team/latest-bugs.atom')
+    >>> browser.open(
+    ...     'http://feeds.launchpad.dev/~simple-team/latest-bugs.atom')
     >>> BSS(browser.contents)('entry')
     []
 
@@ -66,7 +67,8 @@
     >>> print extract_text(BSS(browser.contents)('tr')[0])
     Bugs for Foo Bar
 
-    >>> browser.open('http://feeds.launchpad.dev/~simple-team/latest-bugs.html')
+    >>> browser.open(
+    ...     'http://feeds.launchpad.dev/~simple-team/latest-bugs.html')
     >>> len(BSS(browser.contents)('tr'))
     1