Merge lp:~stevenk/launchpad/bugs-remove-old-privacy into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 15038
Proposed branch: lp:~stevenk/launchpad/bugs-remove-old-privacy
Merge into: lp:launchpad
Diff against target: 1202 lines (+232/-232)
21 files modified
lib/lp/bugs/browser/bug.py (+8/-5)
lib/lp/bugs/browser/bugtarget.py (+8/-5)
lib/lp/bugs/doc/bug-private-by-default.txt (+2/-1)
lib/lp/bugs/doc/bug.txt (+5/-2)
lib/lp/bugs/doc/bugnotification-sending.txt (+2/-1)
lib/lp/bugs/doc/bugsubscription.txt (+4/-3)
lib/lp/bugs/doc/security-teams.txt (+8/-7)
lib/lp/bugs/interfaces/bug.py (+10/-15)
lib/lp/bugs/mail/commands.py (+10/-8)
lib/lp/bugs/mail/tests/test_commands.py (+10/-6)
lib/lp/bugs/model/bug.py (+91/-128)
lib/lp/bugs/model/bugtask.py (+3/-3)
lib/lp/bugs/model/tests/test_bug.py (+23/-26)
lib/lp/bugs/scripts/bugimport.py (+8/-8)
lib/lp/bugs/stories/bugs/xx-bug-activity.txt (+6/-0)
lib/lp/bugs/xmlrpc/bug.py (+11/-7)
lib/lp/registry/enums.py (+5/-0)
lib/lp/registry/model/person.py (+5/-2)
lib/lp/security.py (+3/-1)
lib/lp/systemhomes.py (+5/-2)
lib/lp/testing/factory.py (+5/-2)
To merge this branch: bzr merge lp:~stevenk/launchpad/bugs-remove-old-privacy
Reviewer Review Type Date Requested Status
Ian Booth (community) Approve
Review via email: mp+98974@code.launchpad.net

Commit message

Replace private and security_related in CreateBugParams() with information_type, and replace IBug.setPrivacyAndSecurityRelated() with IBug.transistionToInformationType().

Description of the change

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 moves the code from IBug.setPrivacyAndSecurityRelated() to a new function, IBug.transistionToInformationType(), which is exported over the devel API. This slightly changes the behavior of the function, since it will now always complain about multi-pillar private bugs whereas it used to only care if you were flipping the privacy flag.

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.

I think this branch is safe to land in its current state, with or without the DB patches -11-4 and -12-3 applied.

To post a comment you must log in.
Revision history for this message
Ian Booth (wallyworld) wrote :

This looks good. As discussed, setPrivacyAndSecurityRelated could be changed to no longer return a tuple.
I am scared there's stuff we haven't anticipated that could break, but that's what our marvellous tests are for, right?

review: Approve
Revision history for this message
Ian Booth (wallyworld) wrote :

I would actually remove setPrivacyAndSecurityRelated entirely.
It is a recent addition can can be removed from the API since AFAIUI was only exported to 'devel' and never formally released.

Revision history for this message
William Grant (wgrant) wrote :

lib/lp/bugs/mail/commands.py seems to have inverted logic. The second branch is executed if it's *not* embargoedsecurity. Apart from that I can't see any more glaring issues.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/browser/bug.py'
2--- lib/lp/bugs/browser/bug.py 2012-03-13 00:45:33 +0000
3+++ lib/lp/bugs/browser/bug.py 2012-03-29 05:56:22 +0000
4@@ -69,6 +69,7 @@
5 from lp.app.errors import NotFoundError
6 from lp.app.widgets.itemswidgets import LaunchpadRadioWidgetWithDescription
7 from lp.app.widgets.project import ProjectScopeWidget
8+from lp.bugs.adapters.bug import convert_to_information_type
9 from lp.bugs.browser.bugsubscription import BugPortletSubscribersWithDetails
10 from lp.bugs.browser.widgets.bug import BugTagsWidget
11 from lp.bugs.enums import BugNotificationLevel
12@@ -874,7 +875,7 @@
13
14 # We handle privacy changes by hand instead of leaving it to
15 # the usual machinery because we must use
16- # bug.setPrivacyAndSecurityRelated() to ensure auditing information is
17+ # bug.transitionToInformationType() to ensure auditing information is
18 # recorded.
19 bug = self.context.bug
20 private = data.pop('private', bug.private)
21@@ -882,12 +883,14 @@
22 private and bug.getSubscribersForPerson(self.user).is_empty())
23 security_related = data.pop('security_related')
24 user = getUtility(ILaunchBag).user
25- (private_changed, security_related_changed) = (
26- bug.setPrivacyAndSecurityRelated(private, security_related, user))
27- if private_changed:
28+ # This will change when the UI does.
29+ information_type = convert_to_information_type(
30+ private, security_related)
31+ changed = bug.transitionToInformationType(information_type, user)
32+ if changed:
33 self._handlePrivacyChanged(user_will_be_subscribed)
34 if self.request.is_ajax:
35- if private_changed or security_related_changed:
36+ if changed:
37 return self._getSubscriptionDetails()
38 else:
39 return ''
40
41=== modified file 'lib/lp/bugs/browser/bugtarget.py'
42--- lib/lp/bugs/browser/bugtarget.py 2012-02-21 22:46:28 +0000
43+++ lib/lp/bugs/browser/bugtarget.py 2012-03-29 05:56:22 +0000
44@@ -117,6 +117,7 @@
45 ProductConfigureBase,
46 ProductPrivateBugsMixin,
47 )
48+from lp.registry.enums import InformationType
49 from lp.registry.interfaces.distribution import IDistribution
50 from lp.registry.interfaces.distributionsourcepackage import (
51 IDistributionSourcePackage,
52@@ -580,12 +581,13 @@
53 if self.request.form.get("packagename_option") == "none":
54 packagename = None
55
56- # Security bugs are always private when filed, but can be disclosed
57+ # Security bugs are always embargoed when filed, but can be disclosed
58 # after they've been reported.
59+ # This will change when the UI does.
60 if security_related:
61- private = True
62+ information_type = InformationType.EMBARGOEDSECURITY
63 else:
64- private = False
65+ information_type = InformationType.PUBLIC
66
67 linkified_ack = structured(FormattersAPI(
68 self.getAcknowledgementMessage(self.context)).text_to_html(
69@@ -593,7 +595,7 @@
70 notifications = [linkified_ack]
71 params = CreateBugParams(
72 title=title, comment=comment, owner=self.user,
73- security_related=security_related, private=private,
74+ information_type=information_type,
75 tags=data.get('tags'))
76 if IDistribution.providedBy(context) and packagename:
77 # We don't know if the package name we got was a source or binary
78@@ -623,7 +625,8 @@
79 'Additional information was added to the bug description.')
80
81 if extra_data.private:
82- params.private = extra_data.private
83+ if params.information_type == InformationType.PUBLIC:
84+ params.information_type = InformationType.USERDATA
85
86 # Apply any extra options given by privileged users.
87 if BugTask.userHasBugSupervisorPrivilegesContext(context, self.user):
88
89=== modified file 'lib/lp/bugs/doc/bug-private-by-default.txt'
90--- lib/lp/bugs/doc/bug-private-by-default.txt 2012-01-24 12:36:15 +0000
91+++ lib/lp/bugs/doc/bug-private-by-default.txt 2012-03-29 05:56:22 +0000
92@@ -5,6 +5,7 @@
93 (this is enforced by a DB constraint).
94
95 >>> from lp.bugs.interfaces.bug import CreateBugParams
96+ >>> from lp.registry.enums import InformationType
97 >>> from lp.registry.interfaces.person import IPersonSet
98 >>> from lp.registry.interfaces.product import IProductSet
99 >>> from lp.testing.dbuser import switch_dbuser
100@@ -46,7 +47,7 @@
101 >>> security_bug_params = CreateBugParams(
102 ... owner=no_priv, title='Security bug',
103 ... comment='A monkey took my GPG keys.',
104- ... security_related=True)
105+ ... information_type=InformationType.EMBARGOEDSECURITY)
106 >>> security_bug = landscape.createBug(security_bug_params)
107 >>> [security_bug_task] = security_bug.bugtasks
108 >>> security_bug_task.bug.private
109
110=== modified file 'lib/lp/bugs/doc/bug.txt'
111--- lib/lp/bugs/doc/bug.txt 2011-12-30 06:14:56 +0000
112+++ lib/lp/bugs/doc/bug.txt 2012-03-29 05:56:22 +0000
113@@ -90,6 +90,7 @@
114 The event can be seen when we file a bug.
115
116 >>> from lp.bugs.interfaces.bug import CreateBugParams
117+ >>> from lp.registry.enums import InformationType
118
119 >>> steve_harris = factory.makePerson(name='steve-harris')
120 >>> params = CreateBugParams(
121@@ -477,7 +478,7 @@
122
123 >>> params = CreateBugParams(
124 ... title="test firefox bug", comment="blah blah blah", owner=foobar,
125- ... private=True)
126+ ... information_type=InformationType.USERDATA)
127 >>> params.setBugTarget(product=firefox)
128 >>> added_bug = getUtility(IBugSet).createBug(params)
129 >>> private_bug = bugset.get(added_bug.id)
130@@ -507,7 +508,7 @@
131 >>> evolution = spnset.get(9)
132 >>> params = CreateBugParams(
133 ... title="test firefox bug", comment="blah blah blah",
134- ... owner=foobar, private=True)
135+ ... owner=foobar, information_type=InformationType.USERDATA)
136 >>> params.setBugTarget(distribution=ubuntu, sourcepackagename=evolution)
137 >>> added_bug = getUtility(IBugSet).createBug(params)
138 >>> private_bug = bugset.get(added_bug.id)
139@@ -824,6 +825,7 @@
140
141 We need a feature flag for this test since multi-pillar bugs shouldn't be
142 private by default.
143+
144 >>> from lp.services.features.testing import FeatureFixture
145 >>> feature_flag = {
146 ... 'disclosure.allow_multipillar_private_bugs.enabled': 'on'}
147@@ -850,6 +852,7 @@
148
149 Changing bug security.
150
151+ >>> ign = firefox_bug.setPrivate(False, getUtility(ILaunchBag).user)
152 >>> bug_before_modification = Snapshot(firefox_bug, providing=IBug)
153
154 >>> firefox_bug.security_related
155
156=== modified file 'lib/lp/bugs/doc/bugnotification-sending.txt'
157--- lib/lp/bugs/doc/bugnotification-sending.txt 2012-03-13 00:45:33 +0000
158+++ lib/lp/bugs/doc/bugnotification-sending.txt 2012-03-29 05:56:22 +0000
159@@ -352,6 +352,7 @@
160 We will need a fresh new bug.
161
162 >>> from lp.bugs.interfaces.bug import CreateBugParams
163+ >>> from lp.registry.enums import InformationType
164 >>> from lp.registry.interfaces.distribution import IDistributionSet
165 >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
166 >>> description = getUtility(IMessageSet).fromText(
167@@ -418,7 +419,7 @@
168 ... sec_vuln_bug = ubuntu.createBug(CreateBugParams(
169 ... msg=sec_vuln_description, owner=sample_person,
170 ... title='Zero-day on Frobulator',
171- ... security_related=True, private=True))
172+ ... information_type=InformationType.EMBARGOEDSECURITY))
173
174 >>> sec_vuln_bug.security_related
175 True
176
177=== modified file 'lib/lp/bugs/doc/bugsubscription.txt'
178--- lib/lp/bugs/doc/bugsubscription.txt 2012-03-13 00:45:33 +0000
179+++ lib/lp/bugs/doc/bugsubscription.txt 2012-03-29 05:56:22 +0000
180@@ -48,6 +48,7 @@
181
182 >>> from lp.services.webapp.interfaces import ILaunchBag
183 >>> from lp.bugs.interfaces.bug import CreateBugParams
184+ >>> from lp.registry.enums import InformationType
185 >>> from lp.registry.interfaces.distribution import IDistributionSet
186 >>> from lp.registry.interfaces.person import IPersonSet
187 >>> ubuntu = getUtility(IDistributionSet).getByName("ubuntu")
188@@ -717,7 +718,7 @@
189
190 >>> params = CreateBugParams(
191 ... title="a test bug", comment="a test description",
192- ... owner=foobar, security_related=True, private=True)
193+ ... owner=foobar, information_type=InformationType.EMBARGOEDSECURITY)
194 >>> new_bug = ubuntu.createBug(params)
195
196 >>> getSubscribers(new_bug)
197@@ -805,7 +806,7 @@
198
199 >>> params = CreateBugParams(
200 ... title="a test bug", comment="a test description",
201- ... owner=foobar, security_related=True, private=True)
202+ ... owner=foobar, information_type=InformationType.EMBARGOEDSECURITY)
203 >>> new_bug = firefox.createBug(params)
204
205 >>> getSubscribers(new_bug)
206@@ -871,7 +872,7 @@
207 >>> params = CreateBugParams(
208 ... title="yet another test bug",
209 ... comment="yet another test description",
210- ... owner=foobar, security_related=True, private=True)
211+ ... owner=foobar, information_type=InformationType.EMBARGOEDSECURITY)
212 >>> new_bug = evolution.createBug(params)
213
214 >>> getSubscribers(new_bug)
215
216=== modified file 'lib/lp/bugs/doc/security-teams.txt'
217--- lib/lp/bugs/doc/security-teams.txt 2011-12-24 17:49:30 +0000
218+++ lib/lp/bugs/doc/security-teams.txt 2012-03-29 05:56:22 +0000
219@@ -37,19 +37,20 @@
220 >>> print firefox.security_contact.name
221 ubuntu-team
222
223-When creating a bug, use the security_related flag to indicate that the
224+When creating a bug, use the information_type enum to indicate that the
225 bug is a security vulnerability, and the security contact should be
226 subscribed to the bug, even when it's marked private.
227
228 >>> from lp.services.webapp.interfaces import ILaunchBag
229 >>> from lp.bugs.interfaces.bug import CreateBugParams
230+ >>> from lp.registry.enums import InformationType
231
232 >>> ubuntu_firefox = ubuntu.getSourcePackage("mozilla-firefox")
233 >>> params = CreateBugParams(
234 ... owner=getUtility(ILaunchBag).user,
235 ... title="a security bug",
236 ... comment="this is an example security bug",
237- ... security_related=True, private=True)
238+ ... information_type=InformationType.EMBARGOEDSECURITY)
239 >>> bug = ubuntu.createBug(params)
240
241 >>> bug.security_related
242@@ -79,7 +80,7 @@
243 ... owner=getUtility(ILaunchBag).user,
244 ... title="a security bug",
245 ... comment="this is an example security bug",
246- ... security_related=False)
247+ ... information_type=InformationType.PUBLIC)
248 >>> bug = ubuntu.createBug(params)
249
250 >>> bug.security_related
251@@ -95,7 +96,7 @@
252 ... owner=getUtility(ILaunchBag).user,
253 ... title="another security bug",
254 ... comment="this is another security bug",
255- ... security_related=True, private=True)
256+ ... information_type=InformationType.EMBARGOEDSECURITY)
257 >>> bug = firefox.createBug(params)
258
259 >>> bug.security_related
260@@ -113,7 +114,7 @@
261 ... owner=getUtility(ILaunchBag).user,
262 ... title="another security bug",
263 ... comment="this is another security bug",
264- ... security_related=False)
265+ ... information_type=InformationType.PUBLIC)
266 >>> bug = firefox.createBug(params)
267
268 >>> bug.security_related
269@@ -134,7 +135,7 @@
270 ... owner=getUtility(ILaunchBag).user,
271 ... title="another security bug",
272 ... comment="this is another security bug",
273- ... security_related=True, private=True)
274+ ... information_type=InformationType.EMBARGOEDSECURITY)
275
276 >>> bug = firefox.createBug(params)
277
278@@ -190,7 +191,7 @@
279 ... owner=getUtility(ILaunchBag).user,
280 ... title="another security bug",
281 ... comment="this is private security bug",
282- ... private=True, security_related=True)
283+ ... information_type=InformationType.EMBARGOEDSECURITY)
284 >>> bug = firefox.createBug(params)
285
286 >>> bug.security_related
287
288=== modified file 'lib/lp/bugs/interfaces/bug.py'
289--- lib/lp/bugs/interfaces/bug.py 2012-03-21 01:17:50 +0000
290+++ lib/lp/bugs/interfaces/bug.py 2012-03-29 05:56:22 +0000
291@@ -100,9 +100,9 @@
292 class CreateBugParams:
293 """The parameters used to create a bug."""
294
295- def __init__(self, owner, title, comment=None, description=None, msg=None,
296- status=None, datecreated=None, security_related=False,
297- private=False, subscribers=(),
298+ def __init__(self, owner, title, comment=None, description=None,
299+ msg=None, status=None, datecreated=None,
300+ information_type=InformationType.PUBLIC, subscribers=(),
301 tags=None, subscribe_owner=True, filed_by=None,
302 importance=None, milestone=None, assignee=None, cve=None):
303 self.owner = owner
304@@ -112,8 +112,7 @@
305 self.msg = msg
306 self.status = status
307 self.datecreated = datecreated
308- self.security_related = security_related
309- self.private = private
310+ self.information_type = information_type
311 self.subscribers = subscribers
312 self.product = None
313 self.distribution = None
314@@ -891,20 +890,16 @@
315 """
316
317 @operation_parameters(
318- private=copy_field(IBugPublic['private']),
319- security_related=copy_field(IBugView['security_related']),
320+ information_type=copy_field(IBugPublic['information_type']),
321 )
322 @call_with(who=REQUEST_USER)
323 @export_write_operation()
324 @operation_for_version("devel")
325- def setPrivacyAndSecurityRelated(private, security_related, who):
326- """Set bug privacy and security .
327-
328- :private: True/False.
329- :security_related: True/False.
330- :who: The IPerson who is making the change.
331-
332- Return (private_changed, security_related_changed) tuple.
333+ def transitionToInformationType(information_type, who):
334+ """Set the information type for this bug.
335+
336+ :information_type: The `InformationType` to transition to.
337+ :who: The `IPerson` who is making the change.
338 """
339
340 @operation_parameters(
341
342=== modified file 'lib/lp/bugs/mail/commands.py'
343--- lib/lp/bugs/mail/commands.py 2012-01-01 02:58:52 +0000
344+++ lib/lp/bugs/mail/commands.py 2012-03-29 05:56:22 +0000
345@@ -1,4 +1,4 @@
346-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
347+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
348 # GNU Affero General Public License version 3 (see the file LICENSE).
349
350 __metaclass__ = type
351@@ -46,6 +46,7 @@
352 IllegalTarget,
353 )
354 from lp.bugs.interfaces.cve import ICveSet
355+from lp.registry.enums import InformationType
356 from lp.registry.interfaces.distribution import IDistribution
357 from lp.registry.interfaces.distributionsourcepackage import (
358 IDistributionSourcePackage,
359@@ -184,10 +185,13 @@
360 stop_processing=True)
361
362 if isinstance(context, CreateBugParams):
363- if context.security_related:
364- # BugSet.createBug() requires new security bugs to be private.
365- private = True
366- context.private = private
367+ if private and (
368+ context.information_type == InformationType.PUBLIC):
369+ context.information_type = InformationType.USERDATA
370+ elif (
371+ context.information_type !=
372+ InformationType.EMBARGOEDSECURITY):
373+ context.information_type = InformationType.PUBLIC
374 return context, current_event
375
376 # Snapshot.
377@@ -240,10 +244,8 @@
378 stop_processing=True)
379
380 if isinstance(context, CreateBugParams):
381- context.security_related = security_related
382 if security_related:
383- # BugSet.createBug() requires new security bugs to be private.
384- context.private = True
385+ context.information_type = InformationType.EMBARGOEDSECURITY
386 return context, current_event
387
388 # Take a snapshot.
389
390=== modified file 'lib/lp/bugs/mail/tests/test_commands.py'
391--- lib/lp/bugs/mail/tests/test_commands.py 2012-01-01 02:58:52 +0000
392+++ lib/lp/bugs/mail/tests/test_commands.py 2012-03-29 05:56:22 +0000
393@@ -1,4 +1,4 @@
394-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
395+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
396 # GNU Affero General Public License version 3 (see the file LICENSE).
397
398 from lazr.lifecycle.interfaces import (
399@@ -19,6 +19,7 @@
400 TagEmailCommand,
401 UnsubscribeEmailCommand,
402 )
403+from lp.registry.enums import InformationType
404 from lp.services.mail.interfaces import (
405 BugTargetNotFound,
406 EmailProcessingError,
407@@ -364,7 +365,8 @@
408 dummy_event = object()
409 params, event = command.execute(bug_params, dummy_event)
410 self.assertEqual(bug_params, params)
411- self.assertEqual(True, bug_params.private)
412+ self.assertEqual(
413+ InformationType.USERDATA, bug_params.information_type)
414 self.assertEqual(dummy_event, event)
415
416 def test_execute_bug_params_with_security(self):
417@@ -372,12 +374,14 @@
418 user = self.factory.makePerson()
419 login_person(user)
420 bug_params = CreateBugParams(
421- title='bug title', owner=user, security_related='yes')
422+ title='bug title', owner=user,
423+ information_type=InformationType.EMBARGOEDSECURITY)
424 command = PrivateEmailCommand('private', ['no'])
425 dummy_event = object()
426 params, event = command.execute(bug_params, dummy_event)
427 self.assertEqual(bug_params, params)
428- self.assertEqual(True, bug_params.private)
429+ self.assertEqual(
430+ InformationType.EMBARGOEDSECURITY, bug_params.information_type)
431 self.assertEqual(dummy_event, event)
432
433
434@@ -402,8 +406,8 @@
435 dummy_event = object()
436 params, event = command.execute(bug_params, dummy_event)
437 self.assertEqual(bug_params, params)
438- self.assertEqual(True, bug_params.security_related)
439- self.assertEqual(True, bug_params.private)
440+ self.assertEqual(
441+ InformationType.EMBARGOEDSECURITY, bug_params.information_type)
442 self.assertEqual(dummy_event, event)
443
444
445
446=== modified file 'lib/lp/bugs/model/bug.py'
447--- lib/lp/bugs/model/bug.py 2012-03-26 14:23:39 +0000
448+++ lib/lp/bugs/model/bug.py 2012-03-29 05:56:22 +0000
449@@ -235,11 +235,10 @@
450 return Snapshot(
451 bug_params, names=[
452 "owner", "title", "comment", "description", "msg",
453- "datecreated", "security_related", "private",
454- "distribution", "sourcepackagename",
455- "product", "status", "subscribers", "tags",
456- "subscribe_owner", "filed_by", "importance",
457- "milestone", "assignee", "cve"])
458+ "datecreated", "information_type", "distribution",
459+ "sourcepackagename", "product", "status", "subscribers", "tags",
460+ "subscribe_owner", "filed_by", "importance", "milestone",
461+ "assignee", "cve"])
462
463
464 class BugTag(SQLBase):
465@@ -360,7 +359,7 @@
466 _security_related = BoolCol(
467 dbName='security_related', notNull=True, default=False)
468 information_type = EnumCol(
469- enum=InformationType, default=InformationType.PUBLIC)
470+ enum=InformationType, notNull=True, default=InformationType.PUBLIC)
471
472 # useful Joins
473 activity = SQLMultipleJoin('BugActivity', joinColumn='bug', orderBy='id')
474@@ -397,17 +396,11 @@
475
476 @property
477 def private(self):
478- if self.information_type:
479- return self.information_type in PRIVATE_INFORMATION_TYPES
480- else:
481- return self._private
482+ return self.information_type in PRIVATE_INFORMATION_TYPES
483
484 @property
485 def security_related(self):
486- if self.information_type:
487- return self.information_type in SECURITY_INFORMATION_TYPES
488- else:
489- return self._security_related
490+ return self.information_type in SECURITY_INFORMATION_TYPES
491
492 @cachedproperty
493 def _subscriber_cache(self):
494@@ -1717,109 +1710,76 @@
495
496 return bugtask
497
498- def setPrivacyAndSecurityRelated(self, private, security_related, who):
499- """ See `IBug`."""
500- private_changed = False
501- security_related_changed = False
502- bug_before_modification = Snapshot(self, providing=providedBy(self))
503-
504- f_flag_str = 'disclosure.enhanced_private_bug_subscriptions.enabled'
505- f_flag = bool(getFeatureFlag(f_flag_str))
506- if f_flag:
507- # Before we update the privacy or security_related status, we
508- # need to reconcile the subscribers to avoid leaking private
509- # information.
510- if (self.private != private
511- or self.security_related != security_related):
512- self.reconcileSubscribers(private, security_related, who)
513-
514- if self.private != private:
515- # We do not allow multi-pillar private bugs except for those teams
516- # who want to shoot themselves in the foot.
517- if private:
518- allow_multi_pillar_private = bool(getFeatureFlag(
519- 'disclosure.allow_multipillar_private_bugs.enabled'))
520- if (not allow_multi_pillar_private
521- and len(self.affected_pillars) > 1):
522- raise BugCannotBePrivate(
523- "Multi-pillar bugs cannot be private.")
524- private_changed = True
525- self._private = private
526-
527- if private:
528- self.who_made_private = who
529- self.date_made_private = UTC_NOW
530- else:
531- self.who_made_private = None
532- self.date_made_private = None
533-
534- # XXX: This should be a bulk update. RBC 20100827
535- # bug=https://bugs.launchpad.net/storm/+bug/625071
536- for attachment in self.attachments_unpopulated:
537- attachment.libraryfile.restricted = private
538-
539- if self.security_related != security_related:
540- security_related_changed = True
541- self._security_related = security_related
542-
543- if private_changed or security_related_changed:
544- # Correct the heat for the bug immediately, so that we don't have
545- # to wait for the next calculation job for the adjusted heat.
546- self.updateHeat()
547-
548- self.information_type = convert_to_information_type(
549- self._private, self._security_related)
550-
551- if private_changed or security_related_changed:
552- changed_fields = []
553-
554- if private_changed:
555- changed_fields.append('private')
556- if not f_flag and private:
557- # If we didn't call reconcileSubscribers, we may have
558- # bug supervisors who should be on this bug, but aren't.
559- supervisors = set()
560- for bugtask in self.bugtasks:
561- supervisors.add(bugtask.pillar.bug_supervisor)
562- if None in supervisors:
563- supervisors.remove(None)
564- for s in supervisors:
565- subscriptions = get_structural_subscriptions_for_bug(
566- self, s)
567- if subscriptions != []:
568- self.subscribe(s, who)
569-
570- if security_related_changed:
571- changed_fields.append('security_related')
572- if not f_flag and security_related:
573- # The bug turned out to be security-related, subscribe the
574- # security contact. We do it here only if the feature flag
575- # is not set, otherwise it's done in
576- # reconcileSubscribers().
577- for pillar in self.affected_pillars:
578- if pillar.security_contact is not None:
579- self.subscribe(pillar.security_contact, who)
580-
581- notify(ObjectModifiedEvent(
582- self, bug_before_modification, changed_fields, user=who))
583-
584- return private_changed, security_related_changed
585-
586 def setPrivate(self, private, who):
587 """See `IBug`.
588
589 We also record who made the change and when the change took
590 place.
591 """
592- return self.setPrivacyAndSecurityRelated(
593- private, self.security_related, who)[0]
594+ return self.transitionToInformationType(
595+ convert_to_information_type(private, self.security_related), who)
596
597 def setSecurityRelated(self, security_related, who):
598 """Setter for the `security_related` property."""
599- return self.setPrivacyAndSecurityRelated(
600- self.private, security_related, who)[1]
601-
602- def getRequiredSubscribers(self, for_private, for_security_related, who):
603+ return self.transitionToInformationType(
604+ convert_to_information_type(self.private, security_related), who)
605+
606+ def transitionToInformationType(self, information_type, who):
607+ """See `IBug`."""
608+ bug_before_modification = Snapshot(self, providing=providedBy(self))
609+ if self.information_type == information_type:
610+ return False
611+ f_flag_str = 'disclosure.enhanced_private_bug_subscriptions.enabled'
612+ f_flag = bool(getFeatureFlag(f_flag_str))
613+ if f_flag:
614+ self.reconcileSubscribers(information_type, who)
615+ if information_type in PRIVATE_INFORMATION_TYPES:
616+ allow_multi_pillar_private = bool(getFeatureFlag(
617+ 'disclosure.allow_multipillar_private_bugs.enabled'))
618+ if (not allow_multi_pillar_private
619+ and len(self.affected_pillars) > 1):
620+ raise BugCannotBePrivate(
621+ "Multi-pillar bugs cannot be private.")
622+ self.who_made_private = who
623+ self.date_made_private = UTC_NOW
624+ else:
625+ self.who_made_private = None
626+ self.date_made_private = None
627+ # XXX: This should be a bulk update. RBC 20100827
628+ # bug=https://bugs.launchpad.net/storm/+bug/625071
629+ for attachment in self.attachments_unpopulated:
630+ attachment.libraryfile.restricted = (
631+ information_type in PRIVATE_INFORMATION_TYPES)
632+ self.updateHeat()
633+ if not f_flag and information_type == InformationType.USERDATA:
634+ # If we didn't call reconcileSubscribers(), we may have
635+ # bug supervisors who should be on this bug, but aren't.
636+ supervisors = set()
637+ for bugtask in self.bugtasks:
638+ supervisors.add(bugtask.pillar.bug_supervisor)
639+ if None in supervisors:
640+ supervisors.remove(None)
641+ for s in supervisors:
642+ if not get_structural_subscriptions_for_bug(self, s):
643+ self.subscribe(s, who)
644+ if not f_flag and information_type in SECURITY_INFORMATION_TYPES:
645+ # The bug turned out to be security-related, subscribe the
646+ # security contact. We do it here only if the feature flag
647+ # is not set, otherwise it's done in
648+ # reconcileSubscribers().
649+ for pillar in self.affected_pillars:
650+ if pillar.security_contact is not None:
651+ self.subscribe(pillar.security_contact, who)
652+ self.information_type = information_type
653+ # Set the legacy attributes for now.
654+ self._private = information_type in PRIVATE_INFORMATION_TYPES
655+ self._security_related = (
656+ information_type in SECURITY_INFORMATION_TYPES)
657+ notify(ObjectModifiedEvent(
658+ self, bug_before_modification, [information_type], user=who))
659+ return True
660+
661+ def getRequiredSubscribers(self, information_type, who):
662 """Return the mandatory subscribers for a bug with given attributes.
663
664 When a bug is marked as private or security related, it is required
665@@ -1835,23 +1795,23 @@
666 If bug supervisor or security contact is unset, fallback to bugtask
667 reporter/owner.
668 """
669- if not for_private and not for_security_related:
670+ if information_type == InformationType.PUBLIC:
671 return set()
672 result = set()
673 result.add(self.owner)
674 for bugtask in self.bugtasks:
675 maintainer = bugtask.pillar.owner
676- if for_security_related:
677+ if information_type in SECURITY_INFORMATION_TYPES:
678 result.add(bugtask.pillar.security_contact or maintainer)
679- if for_private:
680+ if information_type in PRIVATE_INFORMATION_TYPES:
681 result.add(bugtask.pillar.bug_supervisor or maintainer)
682- if for_private:
683+ if information_type in PRIVATE_INFORMATION_TYPES:
684 subscribers_for_who = self.getSubscribersForPerson(who)
685 if subscribers_for_who.is_empty():
686 result.add(who)
687 return result
688
689- def getAutoRemovedSubscribers(self, for_private, for_security_related):
690+ def getAutoRemovedSubscribers(self, information_type):
691 """Return the to be removed subscribers for bug with given attributes.
692
693 When a bug's privacy or security related attributes change, some
694@@ -1865,6 +1825,8 @@
695 """
696 bug_supervisors = []
697 security_contacts = []
698+ for_security_related = information_type in SECURITY_INFORMATION_TYPES
699+ for_private = information_type in PRIVATE_INFORMATION_TYPES
700 for pillar in self.affected_pillars:
701 if (self.security_related and not for_security_related
702 and pillar.security_contact):
703@@ -1874,7 +1836,7 @@
704 bug_supervisors.append(pillar.bug_supervisor)
705 return bug_supervisors, security_contacts
706
707- def reconcileSubscribers(self, for_private, for_security_related, who):
708+ def reconcileSubscribers(self, information_type, who):
709 """ Ensure only appropriate people are subscribed to private bugs.
710
711 When a bug is marked as either private = True or security_related =
712@@ -1894,9 +1856,9 @@
713 current_direct_subscribers = (
714 self.getSubscriptionInfo().direct_subscribers)
715 required_subscribers = self.getRequiredSubscribers(
716- for_private, for_security_related, who)
717+ information_type, who)
718 removed_bug_supervisors, removed_security_contacts = (
719- self.getAutoRemovedSubscribers(for_private, for_security_related))
720+ self.getAutoRemovedSubscribers(information_type))
721 for subscriber in removed_bug_supervisors:
722 recipients = BugNotificationRecipients()
723 recipients.addBugSupervisor(subscriber)
724@@ -1929,7 +1891,8 @@
725 # unsubscribe any unauthorised direct subscribers.
726 pillar = self.default_bugtask.pillar
727 private_project = IProduct.providedBy(pillar) and pillar.private_bugs
728- if private_project and (for_private or for_security_related):
729+ privileged_info = information_type != InformationType.PUBLIC
730+ if private_project and privileged_info:
731 allowed_subscribers = set()
732 allowed_subscribers.add(self.owner)
733 for bugtask in self.bugtasks:
734@@ -2813,13 +2776,12 @@
735 if params.product and params.product.private_bugs:
736 # If the private_bugs flag is set on a product, then
737 # force the new bug report to be private.
738- params.private = True
739+ if params.information_type == InformationType.PUBLIC:
740+ params.information_type = InformationType.USERDATA
741
742 bug, event = self.createBugWithoutTarget(params)
743
744- if params.security_related:
745- assert params.private, (
746- "A security related bug should always be private by default.")
747+ if params.information_type in SECURITY_INFORMATION_TYPES:
748 if params.product:
749 context = params.product
750 else:
751@@ -2905,21 +2867,22 @@
752 params.description = params.msg.text_contents
753
754 extra_params = {}
755- if params.private:
756+ if params.information_type in PRIVATE_INFORMATION_TYPES:
757 # We add some auditing information. After bug creation
758 # time these attributes are updated by Bug.setPrivate().
759 extra_params.update(
760 date_made_private=params.datecreated,
761 who_made_private=params.owner)
762
763- information_type = convert_to_information_type(
764- params.private, params.security_related)
765+ # Set the legacy attributes for now.
766+ private = params.information_type in PRIVATE_INFORMATION_TYPES
767+ security_related = (
768+ params.information_type in SECURITY_INFORMATION_TYPES)
769 bug = Bug(
770 title=params.title, description=params.description,
771- _private=params.private, owner=params.owner,
772- datecreated=params.datecreated,
773- _security_related=params.security_related,
774- information_type=information_type,
775+ owner=params.owner, datecreated=params.datecreated,
776+ information_type=params.information_type,
777+ _private=private, _security_related=security_related,
778 **extra_params)
779
780 if params.subscribe_owner:
781
782=== modified file 'lib/lp/bugs/model/bugtask.py'
783--- lib/lp/bugs/model/bugtask.py 2012-03-21 17:31:45 +0000
784+++ lib/lp/bugs/model/bugtask.py 2012-03-29 05:56:22 +0000
785@@ -43,10 +43,8 @@
786 And,
787 Join,
788 Or,
789- Select,
790 SQL,
791 Sum,
792- Union,
793 )
794 from storm.store import (
795 EmptyResultSet,
796@@ -86,6 +84,7 @@
797 UserCannotEditBugTaskMilestone,
798 UserCannotEditBugTaskStatus,
799 )
800+from lp.registry.enums import PUBLIC_INFORMATION_TYPES
801 from lp.registry.interfaces.distribution import (
802 IDistribution,
803 IDistributionSet,
804@@ -1698,7 +1697,8 @@
805 def getStatusCountsForProductSeries(self, user, product_series):
806 """See `IBugTaskSet`."""
807 if user is None:
808- bug_privacy_filter = 'AND Bug.private IS FALSE'
809+ bug_privacy_filter = 'AND Bug.information_type IN %s' % (
810+ sqlvalues(PUBLIC_INFORMATION_TYPES))
811 else:
812 # Since the count won't reveal sensitive information, and
813 # since the get_bug_privacy_filter() check for non-admins is
814
815=== modified file 'lib/lp/bugs/model/tests/test_bug.py'
816--- lib/lp/bugs/model/tests/test_bug.py 2012-03-26 00:12:50 +0000
817+++ lib/lp/bugs/model/tests/test_bug.py 2012-03-29 05:56:22 +0000
818@@ -603,8 +603,11 @@
819 removeSecurityProxy(bug_product).private_bugs = True
820 bug = self.factory.makeBug(owner=bug_owner, product=bug_product)
821 with person_logged_in(bug_owner):
822- bug.setPrivacyAndSecurityRelated(
823- private_security_related, private_security_related, bug_owner)
824+ if private_security_related:
825+ information_type = InformationType.EMBARGOEDSECURITY
826+ else:
827+ information_type = InformationType.PUBLIC
828+ bug.transitionToInformationType(information_type, bug_owner)
829 owner_a = self.factory.makePerson(name='ownera')
830 product_series_a = self.factory.makeProductSeries(
831 product=bug_product, owner=owner_a)
832@@ -639,8 +642,8 @@
833 for subscriber in initial_subscribers:
834 bug.subscribe(subscriber, bug_owner)
835 who = self.factory.makePerson()
836- bug.setPrivacyAndSecurityRelated(
837- private=True, security_related=True, who=who)
838+ bug.transitionToInformationType(
839+ InformationType.EMBARGOEDSECURITY, who=who)
840 subscribers = bug.getDirectSubscribers()
841 expected_subscribers = set((
842 bugtask_a.owner,
843@@ -672,8 +675,7 @@
844 for subscriber in initial_subscribers:
845 bug.subscribe(subscriber, bug_owner)
846 who = self.factory.makePerson()
847- bug.setPrivacyAndSecurityRelated(
848- private=True, security_related=False, who=who)
849+ bug.transitionToInformationType(InformationType.USERDATA, who)
850 subscribers = bug.getDirectSubscribers()
851 expected_subscribers = set((
852 default_bugtask.pillar.bug_supervisor,
853@@ -704,8 +706,8 @@
854 for subscriber in initial_subscribers:
855 bug.subscribe(subscriber, bug_owner)
856 who = self.factory.makePerson()
857- bug.setPrivacyAndSecurityRelated(
858- private=False, security_related=True, who=who)
859+ bug.transitionToInformationType(
860+ InformationType.UNEMBARGOEDSECURITY, who)
861 subscribers = bug.getDirectSubscribers()
862 expected_subscribers = set((
863 default_bugtask.pillar.driver,
864@@ -731,8 +733,7 @@
865 bug.subscribe(subscriber, bug_owner)
866 who = self.factory.makePerson()
867 expected_direct_subscribers = set(bug.getDirectSubscribers())
868- bug.setPrivacyAndSecurityRelated(
869- private=False, security_related=False, who=who)
870+ bug.transitionToInformationType(InformationType.PUBLIC, who)
871 subscribers = set(bug.getDirectSubscribers())
872 expected_direct_subscribers.difference_update(
873 (default_bugtask.pillar.security_contact,
874@@ -747,8 +748,7 @@
875 bug = self.factory.makeBug(owner=bug_owner)
876 with person_logged_in(bug_owner):
877 who = self.factory.makePerson()
878- bug.setPrivacyAndSecurityRelated(
879- private=True, security_related=False, who=who)
880+ bug.transitionToInformationType(InformationType.USERDATA, who)
881 subscribers = bug.getDirectSubscribers()
882 naked_bugtask = removeSecurityProxy(bug).default_bugtask
883 self.assertContentEqual(
884@@ -762,8 +762,8 @@
885 bug = self.factory.makeBug(owner=bug_owner)
886 with person_logged_in(bug_owner):
887 who = self.factory.makePerson()
888- bug.setPrivacyAndSecurityRelated(
889- private=False, security_related=True, who=who)
890+ bug.transitionToInformationType(
891+ InformationType.UNEMBARGOEDSECURITY, who)
892 subscribers = bug.getDirectSubscribers()
893 naked_bugtask = removeSecurityProxy(bug).default_bugtask
894 self.assertContentEqual(
895@@ -833,8 +833,8 @@
896 with person_logged_in(bug_owner):
897 bug.subscribe(default_bugtask.pillar.bug_supervisor, bug_owner)
898 who = self.factory.makePerson(name="who")
899- bug.setPrivacyAndSecurityRelated(
900- private=False, security_related=True, who=who)
901+ bug.transitionToInformationType(
902+ InformationType.UNEMBARGOEDSECURITY, who)
903 subscribers = bug.getDirectSubscribers()
904 self.assertNotIn(
905 default_bugtask.pillar.bug_supervisor, subscribers)
906@@ -863,8 +863,7 @@
907 self.assertFalse(bug_supervisor in bug.getDirectSubscribers())
908 with person_logged_in(bug_owner):
909 who = self.factory.makePerson(name="who")
910- bug.setPrivacyAndSecurityRelated(
911- private=True, security_related=False, who=who)
912+ bug.transitionToInformationType(InformationType.USERDATA, who)
913 self.assertTrue(bug_supervisor in bug.getDirectSubscribers())
914
915 def test_securityContactUnsubscribedIfBugNotSecurityRelated(self):
916@@ -878,8 +877,7 @@
917 with person_logged_in(bug_owner):
918 bug.subscribe(bugtask_a.pillar.security_contact, bug_owner)
919 who = self.factory.makePerson(name="who")
920- bug.setPrivacyAndSecurityRelated(
921- private=True, security_related=False, who=who)
922+ bug.transitionToInformationType(InformationType.USERDATA, who)
923 subscribers = bug.getDirectSubscribers()
924 self.assertFalse(bugtask_a.pillar.security_contact in subscribers)
925
926@@ -905,17 +903,16 @@
927 self.factory.makeBugTask(bug=bug, target=product)
928 login_person(bug.owner)
929 self.assertRaises(
930- BugCannotBePrivate, bug.setPrivacyAndSecurityRelated, True, False,
931- bug.owner)
932- self.assertRaises(
933- BugCannotBePrivate, bug.setPrivate, True, bug.owner)
934+ BugCannotBePrivate, bug.transitionToInformationType,
935+ InformationType.USERDATA, bug.owner)
936
937 # Some teams though need multi-pillar private bugs.
938 feature_flag = {
939 'disclosure.allow_multipillar_private_bugs.enabled': 'on'
940 }
941 with FeatureFixture(feature_flag):
942- bug.setPrivacyAndSecurityRelated(True, False, bug.owner)
943+ bug.transitionToInformationType(
944+ InformationType.USERDATA, bug.owner)
945 self.assertTrue(bug.private)
946
947 def test_bug_information_type(self):
948@@ -960,7 +957,7 @@
949 bug = self.factory.makeBug(
950 private=True, security_related=True, owner=owner)
951 with person_logged_in(owner):
952- bug.setPrivacyAndSecurityRelated(False, False, owner)
953+ bug.transitionToInformationType(InformationType.PUBLIC, owner)
954 self.assertEqual(InformationType.PUBLIC, bug.information_type)
955
956 def test_public_to_private_information_type(self):
957
958=== modified file 'lib/lp/bugs/scripts/bugimport.py'
959--- lib/lp/bugs/scripts/bugimport.py 2012-03-22 23:21:24 +0000
960+++ lib/lp/bugs/scripts/bugimport.py 2012-03-29 05:56:22 +0000
961@@ -40,6 +40,7 @@
962 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
963 from lp.services.librarian.interfaces import ILibraryFileAliasSet
964 from lp.services.messages.interfaces.message import IMessageSet
965+from lp.bugs.adapters.bug import convert_to_information_type
966 from lp.bugs.interfaces.bug import (
967 CreateBugParams,
968 IBugSet,
969@@ -295,6 +296,8 @@
970 # If the product has private_bugs, we force private to True.
971 if self.product.private_bugs:
972 private = True
973+ information_type = convert_to_information_type(
974+ private, security_related)
975
976 if owner is None:
977 owner = self.bug_importer
978@@ -302,12 +305,8 @@
979 msg = self.createMessage(commentnode, defaulttitle=title)
980
981 bug = self.product.createBug(CreateBugParams(
982- msg=msg,
983- datecreated=datecreated,
984- title=title,
985- private=private or security_related,
986- security_related=security_related,
987- owner=owner))
988+ msg=msg, datecreated=datecreated, title=title,
989+ information_type=information_type, owner=owner))
990 bugtask = bug.bugtasks[0]
991 self.logger.info('Creating Launchpad bug #%d', bug.id)
992
993@@ -324,8 +323,9 @@
994
995 # Security bugs must be created private, so set it correctly.
996 if not self.product.private_bugs:
997- bug.setPrivacyAndSecurityRelated(
998- private, security_related, owner)
999+ information_type = convert_to_information_type(
1000+ private, security_related)
1001+ bug.transitionToInformationType(information_type, owner)
1002 bug.name = get_value(bugnode, 'nickname')
1003 description = get_value(bugnode, 'description')
1004 if description:
1005
1006=== modified file 'lib/lp/bugs/stories/bugs/xx-bug-activity.txt'
1007--- lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2011-12-02 17:44:47 +0000
1008+++ lib/lp/bugs/stories/bugs/xx-bug-activity.txt 2012-03-29 05:56:22 +0000
1009@@ -123,6 +123,12 @@
1010 public => private
1011 --------
1012
1013+ >>> admin_browser.open(
1014+ ... 'http://bugs.launchpad.dev/redfish/+bug/15/+secrecy')
1015+ >>> admin_browser.getControl(
1016+ ... "This bug report should be private").selected = False
1017+ >>> admin_browser.getControl("Change").click()
1018+
1019 Clean up the feature flag.
1020 >>> flags.cleanUp()
1021
1022
1023=== modified file 'lib/lp/bugs/xmlrpc/bug.py'
1024--- lib/lp/bugs/xmlrpc/bug.py 2012-01-01 02:58:52 +0000
1025+++ lib/lp/bugs/xmlrpc/bug.py 2012-03-29 05:56:22 +0000
1026@@ -1,10 +1,13 @@
1027-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
1028+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
1029 # GNU Affero General Public License version 3 (see the file LICENSE).
1030
1031 """XML-RPC APIs for Malone."""
1032
1033 __metaclass__ = type
1034-__all__ = ["FileBugAPI", "ExternalBugTrackerTokenAPI"]
1035+__all__ = [
1036+ "ExternalBugTrackerTokenAPI",
1037+ "FileBugAPI",
1038+ ]
1039
1040 from zope.component import getUtility
1041 from zope.interface import implements
1042@@ -12,6 +15,7 @@
1043 from lp.app.errors import NotFoundError
1044 from lp.bugs.interfaces.bug import CreateBugParams
1045 from lp.bugs.interfaces.externalbugtracker import IExternalBugTrackerTokenAPI
1046+from lp.registry.enums import InformationType
1047 from lp.registry.interfaces.distribution import IDistributionSet
1048 from lp.registry.interfaces.person import IPersonSet
1049 from lp.registry.interfaces.product import IProductSet
1050@@ -100,14 +104,14 @@
1051 else:
1052 subscriber_list.append(subscriber)
1053
1054- security_related = bool(security_related)
1055-
1056- # Privacy is always set the same as security, by default.
1057- private = security_related
1058+ if security_related:
1059+ information_type = InformationType.EMBARGOEDSECURITY
1060+ else:
1061+ information_type = InformationType.PUBLIC
1062
1063 params = CreateBugParams(
1064 owner=self.user, title=summary, comment=comment,
1065- security_related=security_related, private=private,
1066+ information_type=information_type,
1067 subscribers=subscriber_list)
1068
1069 bug = target.createBug(params)
1070
1071=== modified file 'lib/lp/registry/enums.py'
1072--- lib/lp/registry/enums.py 2012-03-25 23:33:53 +0000
1073+++ lib/lp/registry/enums.py 2012-03-29 05:56:22 +0000
1074@@ -10,6 +10,7 @@
1075 'InformationType',
1076 'PersonTransferJobType',
1077 'PRIVATE_INFORMATION_TYPES',
1078+ 'PUBLIC_INFORMATION_TYPES',
1079 'ProductJobType',
1080 'SECURITY_INFORMATION_TYPES',
1081 'SharingPermission',
1082@@ -63,6 +64,10 @@
1083 """)
1084
1085
1086+PUBLIC_INFORMATION_TYPES = (
1087+ InformationType.PUBLIC, InformationType.UNEMBARGOEDSECURITY)
1088+
1089+
1090 PRIVATE_INFORMATION_TYPES = (
1091 InformationType.EMBARGOEDSECURITY, InformationType.USERDATA,
1092 InformationType.PROPRIETARY)
1093
1094=== modified file 'lib/lp/registry/model/person.py'
1095--- lib/lp/registry/model/person.py 2012-03-27 19:46:03 +0000
1096+++ lib/lp/registry/model/person.py 2012-03-29 05:56:22 +0000
1097@@ -147,6 +147,7 @@
1098 HasMergeProposalsMixin,
1099 HasRequestedReviewsMixin,
1100 )
1101+from lp.registry.enums import PRIVATE_INFORMATION_TYPES
1102 from lp.registry.errors import (
1103 InvalidName,
1104 JoinNotAllowed,
1105@@ -1849,14 +1850,16 @@
1106 Bug,
1107 Join(BugSubscription, BugSubscription.bug_id == Bug.id)),
1108 where=And(
1109- Bug._private == True,
1110+ Bug.information_type.is_in(PRIVATE_INFORMATION_TYPES),
1111 BugSubscription.person_id == self.id)),
1112 Select(
1113 Bug.id,
1114 tables=(
1115 Bug,
1116 Join(BugTask, BugTask.bugID == Bug.id)),
1117- where=And(Bug._private == True, BugTask.assignee == self.id)),
1118+ where=And(Bug.information_type.is_in(
1119+ PRIVATE_INFORMATION_TYPES),
1120+ BugTask.assignee == self.id)),
1121 limit=1))
1122 if private_bugs_involved.rowcount:
1123 raise TeamSubscriptionPolicyError(
1124
1125=== modified file 'lib/lp/security.py'
1126--- lib/lp/security.py 2012-03-19 16:02:52 +0000
1127+++ lib/lp/security.py 2012-03-29 05:56:22 +0000
1128@@ -986,6 +986,7 @@
1129 user_private_bugs_visible_filter = get_bug_privacy_filter(
1130 user.person, private_only=True)
1131
1132+ # 1 = PUBLIC, 2 = UNEMBARGOEDSECURITY
1133 query = """
1134 SELECT TRUE WHERE
1135 EXISTS (
1136@@ -1005,7 +1006,8 @@
1137 -- do those first.
1138 %(team_bug_select)s
1139 WHERE bug_id in (
1140- SELECT Bug.id FROM Bug WHERE Bug.private is FALSE
1141+ SELECT Bug.id FROM Bug WHERE Bug.information_type IN
1142+ (1, 2)
1143 )
1144 UNION ALL
1145 -- Now do the private bugs the user can see.
1146
1147=== modified file 'lib/lp/systemhomes.py'
1148--- lib/lp/systemhomes.py 2011-12-30 07:32:58 +0000
1149+++ lib/lp/systemhomes.py 2012-03-29 05:56:22 +0000
1150@@ -1,4 +1,4 @@
1151-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
1152+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
1153 # GNU Affero General Public License version 3 (see the file LICENSE).
1154
1155 """Content classes for the 'home pages' of the subsystems of Launchpad."""
1156@@ -24,6 +24,7 @@
1157 from zope.component import getUtility
1158 from zope.interface import implements
1159
1160+from lp.bugs.adapters.bug import convert_to_information_type
1161 from lp.bugs.errors import InvalidBugTargetType
1162 from lp.bugs.interfaces.bug import (
1163 CreateBugParams,
1164@@ -126,9 +127,11 @@
1165 def createBug(self, owner, title, description, target,
1166 security_related=False, private=False, tags=None):
1167 """See `IMaloneApplication`."""
1168+ information_type = convert_to_information_type(
1169+ private, security_related)
1170 params = CreateBugParams(
1171 title=title, comment=description, owner=owner,
1172- security_related=security_related, private=private, tags=tags)
1173+ information_type=information_type, tags=tags)
1174 if IProduct.providedBy(target):
1175 params.setBugTarget(product=target)
1176 elif IDistribution.providedBy(target):
1177
1178=== modified file 'lib/lp/testing/factory.py'
1179--- lib/lp/testing/factory.py 2012-03-28 18:13:37 +0000
1180+++ lib/lp/testing/factory.py 2012-03-29 05:56:22 +0000
1181@@ -77,6 +77,7 @@
1182 )
1183 from lp.blueprints.interfaces.specification import ISpecificationSet
1184 from lp.blueprints.interfaces.sprint import ISprintSet
1185+from lp.bugs.adapters.bug import convert_to_information_type
1186 from lp.bugs.interfaces.bug import (
1187 CreateBugParams,
1188 IBugSet,
1189@@ -1688,9 +1689,11 @@
1190 self.makeSourcePackagePublishingHistory(
1191 distroseries=distribution.currentseries,
1192 sourcepackagename=sourcepackagename)
1193+ # Factory changes delayed for a seperate branch.
1194+ information_type = convert_to_information_type(
1195+ private, security_related)
1196 create_bug_params = CreateBugParams(
1197- owner, title, comment=comment, private=private,
1198- security_related=security_related,
1199+ owner, title, comment=comment, information_type=information_type,
1200 datecreated=date_created, description=description,
1201 status=status, tags=tags)
1202 create_bug_params.setBugTarget(