Merge lp:~adeuring/launchpad/bug-1079116 into lp:launchpad

Proposed by Abel Deuring on 2012-11-29
Status: Merged
Approved by: j.c.sackett on 2012-11-29
Approved revision: no longer in the source branch.
Merged at revision: 16325
Proposed branch: lp:~adeuring/launchpad/bug-1079116
Merge into: lp:launchpad
Diff against target: 106 lines (+63/-2)
2 files modified
lib/lp/code/browser/branchlisting.py (+5/-1)
lib/lp/code/browser/tests/test_branchlisting.py (+58/-1)
To merge this branch: bzr merge lp:~adeuring/launchpad/bug-1079116
Reviewer Review Type Date Requested Status
j.c.sackett (community) 2012-11-29 Approve on 2012-11-29
Review via email: mp+136991@code.launchpad.net

Commit Message

If a branch is the series branch of a proprietary product, do not try to display data about the series in branch listings if users have access to the branch but not to the product.

Description of the Change

This branch fixes bug 1079116: https://code.launchpad.net/~ broken if the user had worked on private projects but has no longer access to these projects

The cause of the error: A user may have an artfiact grant for a proprietary branch that is the official branch of a series of a proprieatry product. If the user does not have a policy grant for the product, accessing the series object in lp.code.browser.branchlisting.BranchListingItemsMixin.product_series_map fails.

product_series_map builds a dictionary branch_id -> [product_series, ...]; I simply added a filter so that only series instances are added which the user can view. The method series.userCanView() is anyway called by the security adapter, so there are no additional queries involved.

test:

./bin/test code -vvt test_proprietary_branch_for_series_artifact_grant

no lint

To post a comment you must log in.
j.c.sackett (jcsackett) wrote :

I had a concern about the userCanView calls, but I think your logic about check_permission is correct, so this looks good. Thanks for adding that note in the proposal.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/browser/branchlisting.py'
2--- lib/lp/code/browser/branchlisting.py 2012-10-09 00:04:10 +0000
3+++ lib/lp/code/browser/branchlisting.py 2012-11-29 16:58:27 +0000
4@@ -340,7 +340,11 @@
5 self._visible_branch_ids)
6 result = {}
7 for series in series_resultset:
8- result.setdefault(series.branch.id, []).append(series)
9+ # Some products may be proprietary or embargoed, and users
10+ # do not need to have access to them, while they may have
11+ # artifact grants for the series branch.
12+ if series.userCanView(self.view_user):
13+ result.setdefault(series.branch.id, []).append(series)
14 return result
15
16 def getProductSeries(self, branch):
17
18=== modified file 'lib/lp/code/browser/tests/test_branchlisting.py'
19--- lib/lp/code/browser/tests/test_branchlisting.py 2012-10-18 12:40:40 +0000
20+++ lib/lp/code/browser/tests/test_branchlisting.py 2012-11-29 16:58:27 +0000
21@@ -20,6 +20,8 @@
22 from testtools.matchers import Not
23 from zope.component import getUtility
24
25+from lp.app.enums import InformationType
26+from lp.app.interfaces.services import IService
27 from lp.code.browser.branchlisting import (
28 BranchListingSort,
29 BranchListingView,
30@@ -31,7 +33,10 @@
31 from lp.code.model.seriessourcepackagebranch import (
32 SeriesSourcePackageBranchSet,
33 )
34-from lp.registry.enums import PersonVisibility
35+from lp.registry.enums import (
36+ PersonVisibility,
37+ SharingPermission,
38+ )
39 from lp.registry.interfaces.person import IPerson
40 from lp.registry.interfaces.personproduct import IPersonProductFactory
41 from lp.registry.interfaces.pocket import PackagePublishingPocket
42@@ -41,6 +46,7 @@
43 from lp.services.webapp import canonical_url
44 from lp.services.webapp.servers import LaunchpadTestRequest
45 from lp.testing import (
46+ admin_logged_in,
47 BrowserTestCase,
48 login_person,
49 normalize_whitespace,
50@@ -258,6 +264,57 @@
51 # The correct template is used for batch requests.
52 self._test_batch_template(self.barney)
53
54+ def test_proprietary_branch_for_series_user_has_artifact_grant(self):
55+ # A user can be the owner of a branch which is the series
56+ # branch of a proprietary product, and the user may only have
57+ # an access grant for the branch but no policy grant for the
58+ # product. In this case, the branch owner does get any information
59+ #about the series.
60+ product_owner = self.factory.makePerson()
61+ product = self.factory.makeProduct(
62+ owner=product_owner, information_type=InformationType.PROPRIETARY)
63+ branch_owner = self.factory.makePerson()
64+ sharing_service = getUtility(IService, 'sharing')
65+ with person_logged_in(product_owner):
66+ # The branch owner needs to have a policy grant at first
67+ # so that they can create the branch.
68+ sharing_service.sharePillarInformation(
69+ product, branch_owner, product_owner,
70+ {InformationType.PROPRIETARY: SharingPermission.ALL})
71+ proprietary_branch = self.factory.makeProductBranch(
72+ product, owner=branch_owner, name='special-branch',
73+ information_type=InformationType.PROPRIETARY)
74+ series = self.factory.makeProductSeries(
75+ product=product, branch=proprietary_branch)
76+ sharing_service.deletePillarGrantee(
77+ product, branch_owner, product_owner)
78+ # Admin help is needed: Product owners do not have the
79+ # permission to create artifact grants for branches they
80+ # do not own, and the branch owner does have the permission
81+ # to issue grants related to the product.
82+ with admin_logged_in():
83+ sharing_service.ensureAccessGrants(
84+ [branch_owner], product_owner, branches=[proprietary_branch])
85+
86+ with person_logged_in(branch_owner):
87+ view = create_initialized_view(
88+ branch_owner, name="+branches", rootsite='code',
89+ principal=branch_owner)
90+ self.assertIn(proprietary_branch, view.branches().batch)
91+ # The product series related to the branch is not returned
92+ # for the branch owner.
93+ self.assertEqual(
94+ [], view.branches().getProductSeries(proprietary_branch))
95+
96+ with person_logged_in(product_owner):
97+ # The product series related to the branch is returned
98+ # for the product owner.
99+ view = create_initialized_view(
100+ branch_owner, name="+branches", rootsite='code',
101+ principal=branch_owner)
102+ self.assertEqual(
103+ [series], view.branches().getProductSeries(proprietary_branch))
104+
105
106 class TestSimplifiedPersonBranchesView(TestCaseWithFactory):
107