launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #06864
[Merge] lp:~stevenk/launchpad/bugs-remove-old-privacy into lp:launchpad
Steve Kowalik has proposed merging lp:~stevenk/launchpad/bugs-remove-old-privacy into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #933766 in Launchpad itself: "Update bug to use information_visibility_policy"
https://bugs.launchpad.net/launchpad/+bug/933766
For more details, see:
https://code.launchpad.net/~stevenk/launchpad/bugs-remove-old-privacy/+merge/98974
As part of the slow march towards un-conflating privacy and security of bugs, we are moving everything from using Bug.private and Bug.security_related to Bug.information_type.
This branch drops Bug._{private,security_related} as well as moving the code from IBug.setPrivacyAndSecurityRelated() to a new function, IBug.transistionToInformationType() -- I've not exported it on the API, but that is easy enough to change.
I have dropped private and security from CreateBugParams and replaced it with information_type. I have hacked around that in the factory and a few other places to make this branch a little more manageable.
This branch requires DB patches -11-4 and -12-3 to be on production (and therefore in devel) before it can land.
--
https://code.launchpad.net/~stevenk/launchpad/bugs-remove-old-privacy/+merge/98974
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/bugs-remove-old-privacy 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-23 06:19:21 +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/bugtarget.py'
--- lib/lp/bugs/browser/bugtarget.py 2012-02-21 22:46:28 +0000
+++ lib/lp/bugs/browser/bugtarget.py 2012-03-23 06:19:21 +0000
@@ -77,6 +77,7 @@
GhostWidget,
ProductBugTrackerWidget,
)
+from lp.bugs.adapters.bug import convert_to_information_type
from lp.bugs.browser.bugrole import BugRoleMixin
from lp.bugs.browser.structuralsubscription import (
expose_structural_subscription_data_to_js,
@@ -117,6 +118,7 @@
ProductConfigureBase,
ProductPrivateBugsMixin,
)
+from lp.registry.enums import InformationType
from lp.registry.interfaces.distribution import IDistribution
from lp.registry.interfaces.distributionsourcepackage import (
IDistributionSourcePackage,
@@ -582,10 +584,11 @@
# Security bugs are always private when filed, but can be disclosed
# after they've been reported.
+ # This will change when the UI does.
if security_related:
- private = True
+ information_type = InformationType.EMBARGOEDSECURITY
else:
- private = False
+ information_type = InformationType.PUBLIC
linkified_ack = structured(FormattersAPI(
self.getAcknowledgementMessage(self.context)).text_to_html(
@@ -593,7 +596,7 @@
notifications = [linkified_ack]
params = CreateBugParams(
title=title, comment=comment, owner=self.user,
- security_related=security_related, private=private,
+ information_type=information_type,
tags=data.get('tags'))
if IDistribution.providedBy(context) and packagename:
# We don't know if the package name we got was a source or binary
@@ -623,7 +626,8 @@
'Additional information was added to the bug description.')
if extra_data.private:
- params.private = extra_data.private
+ if params.information_type is InformationType.PUBLIC:
+ params.information_type = InformationType.USERDATA
# Apply any extra options given by privileged users.
if BugTask.userHasBugSupervisorPrivilegesContext(context, self.user):
=== modified file 'lib/lp/bugs/doc/bug-private-by-default.txt'
--- lib/lp/bugs/doc/bug-private-by-default.txt 2012-01-24 12:36:15 +0000
+++ lib/lp/bugs/doc/bug-private-by-default.txt 2012-03-23 06:19:21 +0000
@@ -5,6 +5,7 @@
(this is enforced by a DB constraint).
>>> from lp.bugs.interfaces.bug import CreateBugParams
+ >>> from lp.registry.enums import InformationType
>>> from lp.registry.interfaces.person import IPersonSet
>>> from lp.registry.interfaces.product import IProductSet
>>> from lp.testing.dbuser import switch_dbuser
@@ -46,7 +47,7 @@
>>> security_bug_params = CreateBugParams(
... owner=no_priv, title='Security bug',
... comment='A monkey took my GPG keys.',
- ... security_related=True)
+ ... information_type=InformationType.EMBARGOEDSECURITY)
>>> security_bug = landscape.createBug(security_bug_params)
>>> [security_bug_task] = security_bug.bugtasks
>>> security_bug_task.bug.private
=== modified file 'lib/lp/bugs/doc/bug.txt'
--- lib/lp/bugs/doc/bug.txt 2011-12-30 06:14:56 +0000
+++ lib/lp/bugs/doc/bug.txt 2012-03-23 06:19:21 +0000
@@ -90,6 +90,7 @@
The event can be seen when we file a bug.
>>> from lp.bugs.interfaces.bug import CreateBugParams
+ >>> from lp.registry.enums import InformationType
>>> steve_harris = factory.makePerson(name='steve-harris')
>>> params = CreateBugParams(
@@ -477,7 +478,7 @@
>>> params = CreateBugParams(
... title="test firefox bug", comment="blah blah blah", owner=foobar,
- ... private=True)
+ ... information_type=InformationType.USERDATA)
>>> params.setBugTarget(product=firefox)
>>> added_bug = getUtility(IBugSet).createBug(params)
>>> private_bug = bugset.get(added_bug.id)
@@ -507,7 +508,7 @@
>>> evolution = spnset.get(9)
>>> params = CreateBugParams(
... title="test firefox bug", comment="blah blah blah",
- ... owner=foobar, private=True)
+ ... owner=foobar, information_type=InformationType.USERDATA)
>>> params.setBugTarget(distribution=ubuntu, sourcepackagename=evolution)
>>> added_bug = getUtility(IBugSet).createBug(params)
>>> private_bug = bugset.get(added_bug.id)
@@ -824,6 +825,7 @@
We need a feature flag for this test since multi-pillar bugs shouldn't be
private by default.
+
>>> from lp.services.features.testing import FeatureFixture
>>> feature_flag = {
... 'disclosure.allow_multipillar_private_bugs.enabled': 'on'}
@@ -850,6 +852,7 @@
Changing bug security.
+ >>> ign = firefox_bug.setPrivate(False, getUtility(ILaunchBag).user)
>>> bug_before_modification = Snapshot(firefox_bug, providing=IBug)
>>> firefox_bug.security_related
=== modified file 'lib/lp/bugs/doc/bugnotification-sending.txt'
--- lib/lp/bugs/doc/bugnotification-sending.txt 2012-03-13 00:45:33 +0000
+++ lib/lp/bugs/doc/bugnotification-sending.txt 2012-03-23 06:19:21 +0000
@@ -352,6 +352,7 @@
We will need a fresh new bug.
>>> from lp.bugs.interfaces.bug import CreateBugParams
+ >>> from lp.registry.enums import InformationType
>>> from lp.registry.interfaces.distribution import IDistributionSet
>>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
>>> description = getUtility(IMessageSet).fromText(
@@ -418,7 +419,7 @@
... sec_vuln_bug = ubuntu.createBug(CreateBugParams(
... msg=sec_vuln_description, owner=sample_person,
... title='Zero-day on Frobulator',
- ... security_related=True, private=True))
+ ... information_type=InformationType.EMBARGOEDSECURITY))
>>> sec_vuln_bug.security_related
True
=== modified file 'lib/lp/bugs/doc/bugsubscription.txt'
--- lib/lp/bugs/doc/bugsubscription.txt 2012-03-13 00:45:33 +0000
+++ lib/lp/bugs/doc/bugsubscription.txt 2012-03-23 06:19:21 +0000
@@ -48,6 +48,7 @@
>>> from lp.services.webapp.interfaces import ILaunchBag
>>> from lp.bugs.interfaces.bug import CreateBugParams
+ >>> from lp.registry.enums import InformationType
>>> from lp.registry.interfaces.distribution import IDistributionSet
>>> from lp.registry.interfaces.person import IPersonSet
>>> ubuntu = getUtility(IDistributionSet).getByName("ubuntu")
@@ -717,7 +718,7 @@
>>> params = CreateBugParams(
... title="a test bug", comment="a test description",
- ... owner=foobar, security_related=True, private=True)
+ ... owner=foobar, information_type=InformationType.EMBARGOEDSECURITY)
>>> new_bug = ubuntu.createBug(params)
>>> getSubscribers(new_bug)
@@ -805,7 +806,7 @@
>>> params = CreateBugParams(
... title="a test bug", comment="a test description",
- ... owner=foobar, security_related=True, private=True)
+ ... owner=foobar, information_type=InformationType.EMBARGOEDSECURITY)
>>> new_bug = firefox.createBug(params)
>>> getSubscribers(new_bug)
@@ -871,7 +872,7 @@
>>> params = CreateBugParams(
... title="yet another test bug",
... comment="yet another test description",
- ... owner=foobar, security_related=True, private=True)
+ ... owner=foobar, information_type=InformationType.EMBARGOEDSECURITY)
>>> new_bug = evolution.createBug(params)
>>> getSubscribers(new_bug)
=== modified file 'lib/lp/bugs/doc/security-teams.txt'
--- lib/lp/bugs/doc/security-teams.txt 2011-12-24 17:49:30 +0000
+++ lib/lp/bugs/doc/security-teams.txt 2012-03-23 06:19:21 +0000
@@ -37,19 +37,20 @@
>>> print firefox.security_contact.name
ubuntu-team
-When creating a bug, use the security_related flag to indicate that the
+When creating a bug, use the information_type enum to indicate that the
bug is a security vulnerability, and the security contact should be
subscribed to the bug, even when it's marked private.
>>> from lp.services.webapp.interfaces import ILaunchBag
>>> from lp.bugs.interfaces.bug import CreateBugParams
+ >>> from lp.registry.enums import InformationType
>>> ubuntu_firefox = ubuntu.getSourcePackage("mozilla-firefox")
>>> params = CreateBugParams(
... owner=getUtility(ILaunchBag).user,
... title="a security bug",
... comment="this is an example security bug",
- ... security_related=True, private=True)
+ ... information_type=InformationType.EMBARGOEDSECURITY)
>>> bug = ubuntu.createBug(params)
>>> bug.security_related
@@ -79,7 +80,7 @@
... owner=getUtility(ILaunchBag).user,
... title="a security bug",
... comment="this is an example security bug",
- ... security_related=False)
+ ... information_type=InformationType.PUBLIC)
>>> bug = ubuntu.createBug(params)
>>> bug.security_related
@@ -95,7 +96,7 @@
... owner=getUtility(ILaunchBag).user,
... title="another security bug",
... comment="this is another security bug",
- ... security_related=True, private=True)
+ ... information_type=InformationType.EMBARGOEDSECURITY)
>>> bug = firefox.createBug(params)
>>> bug.security_related
@@ -113,7 +114,7 @@
... owner=getUtility(ILaunchBag).user,
... title="another security bug",
... comment="this is another security bug",
- ... security_related=False)
+ ... information_type=InformationType.PUBLIC)
>>> bug = firefox.createBug(params)
>>> bug.security_related
@@ -134,7 +135,7 @@
... owner=getUtility(ILaunchBag).user,
... title="another security bug",
... comment="this is another security bug",
- ... security_related=True, private=True)
+ ... information_type=InformationType.EMBARGOEDSECURITY)
>>> bug = firefox.createBug(params)
@@ -190,7 +191,7 @@
... owner=getUtility(ILaunchBag).user,
... title="another security bug",
... comment="this is private security bug",
- ... private=True, security_related=True)
+ ... information_type=InformationType.EMBARGOEDSECURITY)
>>> bug = firefox.createBug(params)
>>> bug.security_related
=== modified file 'lib/lp/bugs/interfaces/bug.py'
--- lib/lp/bugs/interfaces/bug.py 2012-03-21 01:17:50 +0000
+++ lib/lp/bugs/interfaces/bug.py 2012-03-23 06:19:21 +0000
@@ -100,9 +100,9 @@
class CreateBugParams:
"""The parameters used to create a bug."""
- def __init__(self, owner, title, comment=None, description=None, msg=None,
- status=None, datecreated=None, security_related=False,
- private=False, subscribers=(),
+ def __init__(self, owner, title, comment=None, description=None,
+ msg=None, status=None, datecreated=None,
+ information_type=InformationType.PUBLIC, subscribers=(),
tags=None, subscribe_owner=True, filed_by=None,
importance=None, milestone=None, assignee=None, cve=None):
self.owner = owner
@@ -112,8 +112,7 @@
self.msg = msg
self.status = status
self.datecreated = datecreated
- self.security_related = security_related
- self.private = private
+ self.information_type = information_type
self.subscribers = subscribers
self.product = None
self.distribution = None
@@ -907,6 +906,13 @@
Return (private_changed, security_related_changed) tuple.
"""
+ def transitionToInformationType(information_type, who):
+ """Set the information type for this bug.
+
+ :information_type: The `InformationType` to transition to.
+ :who: The `IPerson` who is making the change.
+ """
+
@operation_parameters(
submission=Reference(
Interface, title=_('A HWDB submission'), required=True))
=== modified file 'lib/lp/bugs/mail/commands.py'
--- lib/lp/bugs/mail/commands.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/mail/commands.py 2012-03-23 06:19:21 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 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).
__metaclass__ = type
@@ -46,6 +46,7 @@
IllegalTarget,
)
from lp.bugs.interfaces.cve import ICveSet
+from lp.registry.enums import InformationType
from lp.registry.interfaces.distribution import IDistribution
from lp.registry.interfaces.distributionsourcepackage import (
IDistributionSourcePackage,
@@ -184,10 +185,15 @@
stop_processing=True)
if isinstance(context, CreateBugParams):
- if context.security_related:
- # BugSet.createBug() requires new security bugs to be private.
- private = True
- context.private = private
+ if private and (
+ context.information_type is InformationType.PUBLIC):
+ context.information_type = InformationType.USERDATA
+ elif (
+ context.information_type is
+ InformationType.EMBARGOEDSECURITY):
+ pass
+ else:
+ context.information_type = InformationType.PUBLIC
return context, current_event
# Snapshot.
@@ -240,10 +246,10 @@
stop_processing=True)
if isinstance(context, CreateBugParams):
- context.security_related = security_related
if security_related:
- # BugSet.createBug() requires new security bugs to be private.
- context.private = True
+ context.information_type = InformationType.EMBARGOEDSECURITY
+ else:
+ context.information_type = InformationType.PUBLIC
return context, current_event
# Take a snapshot.
=== modified file 'lib/lp/bugs/mail/tests/test_commands.py'
--- lib/lp/bugs/mail/tests/test_commands.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/mail/tests/test_commands.py 2012-03-23 06:19:21 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 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).
from lazr.lifecycle.interfaces import (
@@ -19,6 +19,7 @@
TagEmailCommand,
UnsubscribeEmailCommand,
)
+from lp.registry.enums import InformationType
from lp.services.mail.interfaces import (
BugTargetNotFound,
EmailProcessingError,
@@ -364,7 +365,8 @@
dummy_event = object()
params, event = command.execute(bug_params, dummy_event)
self.assertEqual(bug_params, params)
- self.assertEqual(True, bug_params.private)
+ self.assertEqual(
+ InformationType.USERDATA, bug_params.information_type)
self.assertEqual(dummy_event, event)
def test_execute_bug_params_with_security(self):
@@ -372,12 +374,14 @@
user = self.factory.makePerson()
login_person(user)
bug_params = CreateBugParams(
- title='bug title', owner=user, security_related='yes')
+ title='bug title', owner=user,
+ information_type=InformationType.EMBARGOEDSECURITY)
command = PrivateEmailCommand('private', ['no'])
dummy_event = object()
params, event = command.execute(bug_params, dummy_event)
self.assertEqual(bug_params, params)
- self.assertEqual(True, bug_params.private)
+ self.assertEqual(
+ InformationType.EMBARGOEDSECURITY, bug_params.information_type)
self.assertEqual(dummy_event, event)
=== modified file 'lib/lp/bugs/model/bug.py'
--- lib/lp/bugs/model/bug.py 2012-03-21 01:17:50 +0000
+++ lib/lp/bugs/model/bug.py 2012-03-23 06:19:21 +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,
@@ -234,11 +235,10 @@
return Snapshot(
bug_params, names=[
"owner", "title", "comment", "description", "msg",
- "datecreated", "security_related", "private",
- "distribution", "sourcepackagename",
- "product", "status", "subscribers", "tags",
- "subscribe_owner", "filed_by", "importance",
- "milestone", "assignee", "cve"])
+ "datecreated", "information_type", "distribution",
+ "sourcepackagename", "product", "status", "subscribers", "tags",
+ "subscribe_owner", "filed_by", "importance", "milestone",
+ "assignee", "cve"])
class BugTag(SQLBase):
@@ -351,15 +351,12 @@
dbName='duplicateof', foreignKey='Bug', default=None)
datecreated = UtcDateTimeCol(notNull=True, default=UTC_NOW)
date_last_updated = UtcDateTimeCol(notNull=True, default=UTC_NOW)
- _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(
- dbName='security_related', notNull=True, default=False)
information_type = EnumCol(
- enum=InformationType, default=InformationType.PUBLIC)
+ enum=InformationType, notNull=True, default=InformationType.PUBLIC)
# useful Joins
activity = SQLMultipleJoin('BugActivity', joinColumn='bug', orderBy='id')
@@ -396,17 +393,11 @@
@property
def private(self):
- if self.information_type:
- return self.information_type in PRIVATE_INFORMATION_TYPES
- else:
- return self._private
+ return self.information_type in PRIVATE_INFORMATION_TYPES
@property
def security_related(self):
- if self.information_type:
- return self.information_type in SECURITY_INFORMATION_TYPES
- else:
- return self._security_related
+ return self.information_type in SECURITY_INFORMATION_TYPES
@cachedproperty
def _subscriber_cache(self):
@@ -1716,102 +1707,11 @@
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
- security_related_changed = False
- bug_before_modification = Snapshot(self, providing=providedBy(self))
-
- f_flag_str = 'disclosure.enhanced_private_bug_subscriptions.enabled'
- f_flag = bool(getFeatureFlag(f_flag_str))
- if f_flag:
- # Before we update the privacy or security_related status, we
- # need to reconcile the subscribers to avoid leaking private
- # information.
- if (self.private != private
- or self.security_related != security_related):
- self.reconcileSubscribers(private, security_related, who)
-
- if self.private != private:
- # We do not allow multi-pillar private bugs except for those teams
- # who want to shoot themselves in the foot.
- if private:
- allow_multi_pillar_private = bool(getFeatureFlag(
- 'disclosure.allow_multipillar_private_bugs.enabled'))
- if (not allow_multi_pillar_private
- and len(self.affected_pillars) > 1):
- raise BugCannotBePrivate(
- "Multi-pillar bugs cannot be private.")
- private_changed = True
- self._private = private
-
- if private:
- self.who_made_private = who
- self.date_made_private = UTC_NOW
- else:
- self.who_made_private = None
- self.date_made_private = None
-
- # XXX: This should be a bulk update. RBC 20100827
- # bug=https://bugs.launchpad.net/storm/+bug/625071
- for attachment in self.attachments_unpopulated:
- attachment.libraryfile.restricted = private
-
- if self.security_related != security_related:
- security_related_changed = True
- 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()
-
- if private_changed or security_related_changed:
- changed_fields = []
-
- if private_changed:
- changed_fields.append('private')
- if not f_flag and private:
- # If we didn't call reconcileSubscribers, we may have
- # bug supervisors who should be on this bug, but aren't.
- supervisors = set()
- for bugtask in self.bugtasks:
- supervisors.add(bugtask.pillar.bug_supervisor)
- if None in supervisors:
- supervisors.remove(None)
- for s in supervisors:
- subscriptions = get_structural_subscriptions_for_bug(
- self, s)
- if subscriptions != []:
- self.subscribe(s, who)
-
- if security_related_changed:
- changed_fields.append('security_related')
- if not f_flag and security_related:
- # The bug turned out to be security-related, subscribe the
- # security contact. We do it here only if the feature flag
- # is not set, otherwise it's done in
- # reconcileSubscribers().
- for pillar in self.affected_pillars:
- if pillar.security_contact is not None:
- self.subscribe(pillar.security_contact, who)
-
- notify(ObjectModifiedEvent(
- self, bug_before_modification, changed_fields, user=who))
-
- return private_changed, security_related_changed
+ ret = self.transitionToInformationType(
+ convert_to_information_type(private, security_related), who)
+ return (ret, ret)
def setPrivate(self, private, who):
"""See `IBug`.
@@ -1827,7 +1727,58 @@
return self.setPrivacyAndSecurityRelated(
self.private, security_related, who)[1]
- def getRequiredSubscribers(self, for_private, for_security_related, who):
+ def transitionToInformationType(self, information_type, who):
+ """See `IBug`."""
+ bug_before_modification = Snapshot(self, providing=providedBy(self))
+ if self.information_type is information_type:
+ return False
+ f_flag_str = 'disclosure.enhanced_private_bug_subscriptions.enabled'
+ f_flag = bool(getFeatureFlag(f_flag_str))
+ if f_flag:
+ self.reconcileSubscribers(information_type, who)
+ if information_type in PRIVATE_INFORMATION_TYPES:
+ allow_multi_pillar_private = bool(getFeatureFlag(
+ 'disclosure.allow_multipillar_private_bugs.enabled'))
+ if (not allow_multi_pillar_private
+ and len(self.affected_pillars) > 1):
+ raise BugCannotBePrivate(
+ "Multi-pillar bugs cannot be private.")
+ self.who_made_private = who
+ self.date_made_private = UTC_NOW
+ else:
+ self.who_made_private = None
+ self.date_made_private = None
+ # XXX: This should be a bulk update. RBC 20100827
+ # bug=https://bugs.launchpad.net/storm/+bug/625071
+ for attachment in self.attachments_unpopulated:
+ attachment.libraryfile.restricted = (
+ information_type in PRIVATE_INFORMATION_TYPES)
+ self.updateHeat()
+ if not f_flag and information_type is InformationType.USERDATA:
+ # If we didn't call reconcileSubscribers(), we may have
+ # bug supervisors who should be on this bug, but aren't.
+ supervisors = set()
+ for bugtask in self.bugtasks:
+ supervisors.add(bugtask.pillar.bug_supervisor)
+ if None in supervisors:
+ supervisors.remove(None)
+ for s in supervisors:
+ if not get_structural_subscriptions_for_bug(self, s):
+ self.subscribe(s, who)
+ if not f_flag and information_type in SECURITY_INFORMATION_TYPES:
+ # The bug turned out to be security-related, subscribe the
+ # security contact. We do it here only if the feature flag
+ # is not set, otherwise it's done in
+ # reconcileSubscribers().
+ for pillar in self.affected_pillars:
+ if pillar.security_contact is not None:
+ self.subscribe(pillar.security_contact, who)
+ self.information_type = information_type
+ notify(ObjectModifiedEvent(
+ self, bug_before_modification, [information_type], user=who))
+ return True
+
+ def getRequiredSubscribers(self, information_type, who):
"""Return the mandatory subscribers for a bug with given attributes.
When a bug is marked as private or security related, it is required
@@ -1843,23 +1794,23 @@
If bug supervisor or security contact is unset, fallback to bugtask
reporter/owner.
"""
- if not for_private and not for_security_related:
+ if information_type is InformationType.PUBLIC:
return set()
result = set()
result.add(self.owner)
for bugtask in self.bugtasks:
maintainer = bugtask.pillar.owner
- if for_security_related:
+ if information_type in SECURITY_INFORMATION_TYPES:
result.add(bugtask.pillar.security_contact or maintainer)
- if for_private:
+ if information_type in PRIVATE_INFORMATION_TYPES:
result.add(bugtask.pillar.bug_supervisor or maintainer)
- if for_private:
+ if information_type in PRIVATE_INFORMATION_TYPES:
subscribers_for_who = self.getSubscribersForPerson(who)
if subscribers_for_who.is_empty():
result.add(who)
return result
- def getAutoRemovedSubscribers(self, for_private, for_security_related):
+ def getAutoRemovedSubscribers(self, information_type):
"""Return the to be removed subscribers for bug with given attributes.
When a bug's privacy or security related attributes change, some
@@ -1873,6 +1824,8 @@
"""
bug_supervisors = []
security_contacts = []
+ for_security_related = information_type in SECURITY_INFORMATION_TYPES
+ for_private = information_type in PRIVATE_INFORMATION_TYPES
for pillar in self.affected_pillars:
if (self.security_related and not for_security_related
and pillar.security_contact):
@@ -1882,7 +1835,7 @@
bug_supervisors.append(pillar.bug_supervisor)
return bug_supervisors, security_contacts
- def reconcileSubscribers(self, for_private, for_security_related, who):
+ def reconcileSubscribers(self, information_type, who):
""" Ensure only appropriate people are subscribed to private bugs.
When a bug is marked as either private = True or security_related =
@@ -1902,9 +1855,9 @@
current_direct_subscribers = (
self.getSubscriptionInfo().direct_subscribers)
required_subscribers = self.getRequiredSubscribers(
- for_private, for_security_related, who)
+ information_type, who)
removed_bug_supervisors, removed_security_contacts = (
- self.getAutoRemovedSubscribers(for_private, for_security_related))
+ self.getAutoRemovedSubscribers(information_type))
for subscriber in removed_bug_supervisors:
recipients = BugNotificationRecipients()
recipients.addBugSupervisor(subscriber)
@@ -1937,7 +1890,8 @@
# unsubscribe any unauthorised direct subscribers.
pillar = self.default_bugtask.pillar
private_project = IProduct.providedBy(pillar) and pillar.private_bugs
- if private_project and (for_private or for_security_related):
+ privleged_info = information_type is not InformationType.PUBLIC
+ if private_project and privleged_info:
allowed_subscribers = set()
allowed_subscribers.add(self.owner)
for bugtask in self.bugtasks:
@@ -2821,13 +2775,12 @@
if params.product and params.product.private_bugs:
# If the private_bugs flag is set on a product, then
# force the new bug report to be private.
- params.private = True
+ if params.information_type is InformationType.PUBLIC:
+ params.information_type = InformationType.USERDATA
bug, event = self.createBugWithoutTarget(params)
- if params.security_related:
- assert params.private, (
- "A security related bug should always be private by default.")
+ if params.information_type in SECURITY_INFORMATION_TYPES:
if params.product:
context = params.product
else:
@@ -2874,8 +2827,6 @@
if notify_event:
notify(event)
- bug._setInformationType()
-
# Calculate the bug's initial heat.
bug.updateHeat()
@@ -2915,7 +2866,7 @@
params.description = params.msg.text_contents
extra_params = {}
- if params.private:
+ if params.information_type in PRIVATE_INFORMATION_TYPES:
# We add some auditing information. After bug creation
# time these attributes are updated by Bug.setPrivate().
extra_params.update(
@@ -2924,9 +2875,8 @@
bug = Bug(
title=params.title, description=params.description,
- _private=params.private, owner=params.owner,
- datecreated=params.datecreated,
- _security_related=params.security_related,
+ owner=params.owner, datecreated=params.datecreated,
+ information_type=params.information_type,
**extra_params)
if params.subscribe_owner:
=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py 2012-03-21 17:31:45 +0000
+++ lib/lp/bugs/model/bugtask.py 2012-03-23 06:19:21 +0000
@@ -1698,7 +1698,8 @@
def getStatusCountsForProductSeries(self, user, product_series):
"""See `IBugTaskSet`."""
if user is None:
- bug_privacy_filter = 'AND Bug.private IS FALSE'
+ # 1 = PUBLIC, 2 = UNEMBARGOEDSECURITY.
+ bug_privacy_filter = 'AND Bug.information_type IN (1, 2)'
else:
# Since the count won't reveal sensitive information, and
# since the get_bug_privacy_filter() check for non-admins is
=== modified file 'lib/lp/bugs/model/bugtasksearch.py'
--- lib/lp/bugs/model/bugtasksearch.py 2012-03-20 09:43:46 +0000
+++ lib/lp/bugs/model/bugtasksearch.py 2012-03-23 06:19:21 +0000
@@ -1413,14 +1413,15 @@
returns BugTask objects.
"""
if user is None:
- return "Bug.private IS FALSE", _nocache_bug_decorator
+ return "Bug.information_type IN (1, 2)", _nocache_bug_decorator
admin_team = getUtility(ILaunchpadCelebrities).admin
if user.inTeam(admin_team):
return "", _nocache_bug_decorator
public_bug_filter = ''
if not private_only:
- public_bug_filter = 'Bug.private IS FALSE OR'
+ # 1 == PUBLIC, 2 == UNEMBARGOEDSECURITY
+ public_bug_filter = 'Bug.information_type IN (1, 2) OR'
# A subselect is used here because joining through
# TeamParticipation is only relevant to the "user-aware"
=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
--- lib/lp/bugs/model/tests/test_bugtask.py 2012-03-08 12:03:22 +0000
+++ lib/lp/bugs/model/tests/test_bugtask.py 2012-03-23 06:19:21 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 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).
__metaclass__ = type
@@ -922,9 +922,9 @@
# clause if the specified user is None, regardless of the value of the
# private_only parameter.
filter = get_bug_privacy_filter(None)
- self.assertIn('Bug.private IS FALSE', filter)
+ self.assertIn('Bug.information_type IN (1, 2)', filter)
filter = get_bug_privacy_filter(None, private_only=True)
- self.assertIn('Bug.private IS FALSE', filter)
+ self.assertIn('Bug.information_type IN (1, 2)', filter)
def test_bug_privacy_filter_private_only_param_with_user(self):
# The bug privacy filter expression omits has the "private is false"
@@ -932,9 +932,9 @@
# specified.
any_user = self.factory.makePerson()
filter = get_bug_privacy_filter(any_user)
- self.assertIn('Bug.private IS FALSE', filter)
+ self.assertIn('Bug.information_type IN (1, 2)', filter)
filter = get_bug_privacy_filter(any_user, private_only=True)
- self.assertNotIn('Bug.private IS FALSE', filter)
+ self.assertNotIn('Bug.information_type IN (1, 2)', filter)
def test_no_tasks(self):
# A brand new bug target has no tasks.
=== modified file 'lib/lp/bugs/scripts/bugimport.py'
--- lib/lp/bugs/scripts/bugimport.py 2012-03-22 23:21:24 +0000
+++ lib/lp/bugs/scripts/bugimport.py 2012-03-23 06:19:21 +0000
@@ -40,10 +40,15 @@
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.services.librarian.interfaces import ILibraryFileAliasSet
from lp.services.messages.interfaces.message import IMessageSet
+<<<<<<< TREE
from lp.bugs.interfaces.bug import (
CreateBugParams,
IBugSet,
)
+=======
+from lp.bugs.adapters.bug import convert_to_information_type
+from lp.bugs.interfaces.bug import CreateBugParams, IBugSet
+>>>>>>> MERGE-SOURCE
from lp.bugs.interfaces.bugactivity import IBugActivitySet
from lp.bugs.interfaces.bugattachment import (
BugAttachmentType,
@@ -295,6 +300,8 @@
# If the product has private_bugs, we force private to True.
if self.product.private_bugs:
private = True
+ information_type = convert_to_information_type(
+ private, security_related)
if owner is None:
owner = self.bug_importer
@@ -302,12 +309,8 @@
msg = self.createMessage(commentnode, defaulttitle=title)
bug = self.product.createBug(CreateBugParams(
- msg=msg,
- datecreated=datecreated,
- title=title,
- private=private or security_related,
- security_related=security_related,
- owner=owner))
+ msg=msg, datecreated=datecreated, title=title,
+ information_type=information_type, owner=owner))
bugtask = bug.bugtasks[0]
self.logger.info('Creating Launchpad bug #%d', bug.id)
=== modified file 'lib/lp/bugs/stories/bugs/xx-bug-activity.txt'
--- lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2011-12-02 17:44:47 +0000
+++ lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2012-03-23 06:19:21 +0000
@@ -123,6 +123,12 @@
public => private
--------
+ >>> admin_browser.open(
+ ... 'http://bugs.launchpad.dev/redfish/+bug/15/+secrecy')
+ >>> admin_browser.getControl(
+ ... "This bug report should be private").selected = False
+ >>> admin_browser.getControl("Change").click()
+
Clean up the feature flag.
>>> flags.cleanUp()
=== modified file 'lib/lp/bugs/xmlrpc/bug.py'
--- lib/lp/bugs/xmlrpc/bug.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/xmlrpc/bug.py 2012-03-23 06:19:21 +0000
@@ -1,10 +1,13 @@
-# Copyright 2009-2011 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).
"""XML-RPC APIs for Malone."""
__metaclass__ = type
-__all__ = ["FileBugAPI", "ExternalBugTrackerTokenAPI"]
+__all__ = [
+ "ExternalBugTrackerTokenAPI",
+ "FileBugAPI",
+ ]
from zope.component import getUtility
from zope.interface import implements
@@ -12,6 +15,7 @@
from lp.app.errors import NotFoundError
from lp.bugs.interfaces.bug import CreateBugParams
from lp.bugs.interfaces.externalbugtracker import IExternalBugTrackerTokenAPI
+from lp.registry.enums import InformationType
from lp.registry.interfaces.distribution import IDistributionSet
from lp.registry.interfaces.person import IPersonSet
from lp.registry.interfaces.product import IProductSet
@@ -100,14 +104,14 @@
else:
subscriber_list.append(subscriber)
- security_related = bool(security_related)
-
- # Privacy is always set the same as security, by default.
- private = security_related
+ if security_related:
+ information_type = InformationType.EMBARGOEDSECURITY
+ else:
+ information_type = InformationType.PUBLIC
params = CreateBugParams(
owner=self.user, title=summary, comment=comment,
- security_related=security_related, private=private,
+ information_type=information_type,
subscribers=subscriber_list)
bug = target.createBug(params)
=== modified file 'lib/lp/systemhomes.py'
--- lib/lp/systemhomes.py 2011-12-30 07:32:58 +0000
+++ lib/lp/systemhomes.py 2012-03-23 06:19:21 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 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).
"""Content classes for the 'home pages' of the subsystems of Launchpad."""
@@ -24,6 +24,7 @@
from zope.component import getUtility
from zope.interface import implements
+from lp.bugs.adapters.bug import convert_to_information_type
from lp.bugs.errors import InvalidBugTargetType
from lp.bugs.interfaces.bug import (
CreateBugParams,
@@ -126,9 +127,11 @@
def createBug(self, owner, title, description, target,
security_related=False, private=False, tags=None):
"""See `IMaloneApplication`."""
+ information_type = convert_to_information_type(
+ private, security_related)
params = CreateBugParams(
title=title, comment=description, owner=owner,
- security_related=security_related, private=private, tags=tags)
+ information_type=information_type, tags=tags)
if IProduct.providedBy(target):
params.setBugTarget(product=target)
elif IDistribution.providedBy(target):
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2012-03-15 14:35:58 +0000
+++ lib/lp/testing/factory.py 2012-03-23 06:19:21 +0000
@@ -78,6 +78,7 @@
)
from lp.blueprints.interfaces.specification import ISpecificationSet
from lp.blueprints.interfaces.sprint import ISprintSet
+from lp.bugs.adapters.bug import convert_to_information_type
from lp.bugs.interfaces.bug import (
CreateBugParams,
IBugSet,
@@ -1689,9 +1690,11 @@
self.makeSourcePackagePublishingHistory(
distroseries=distribution.currentseries,
sourcepackagename=sourcepackagename)
+ # Factory changes delayed for a seperate branch.
+ information_type = convert_to_information_type(
+ private, security_related)
create_bug_params = CreateBugParams(
- owner, title, comment=comment, private=private,
- security_related=security_related,
+ owner, title, comment=comment, information_type=information_type,
datecreated=date_created, description=description,
status=status, tags=tags)
create_bug_params.setBugTarget(