Merge lp:~edwin-grubbs/launchpad/bug-506965-merge-team-oops into lp:launchpad
- bug-506965-merge-team-oops
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Curtis Hovey |
Approved revision: | not available |
Merged at revision: | not available |
Proposed branch: | lp:~edwin-grubbs/launchpad/bug-506965-merge-team-oops |
Merge into: | lp:launchpad |
Diff against target: |
246 lines (+82/-43) 4 files modified
lib/lp/registry/browser/menu.py (+1/-1) lib/lp/registry/browser/peoplemerge.py (+4/-4) lib/lp/registry/browser/tests/peoplemerge-views.txt (+34/-4) lib/lp/registry/stories/team/xx-adminteammerge.txt (+43/-34) |
To merge this branch: | bzr merge lp:~edwin-grubbs/launchpad/bug-506965-merge-team-oops |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Curtis Hovey (community) | Approve | ||
Review via email: mp+17445@code.launchpad.net |
Commit message
Description of the change
Edwin Grubbs (edwin-grubbs) wrote : | # |
Curtis Hovey (sinzui) wrote : | # |
Hi Edwin.
There are some dangerous changes in the code and the test does is not what is happening in production.
We need to revert the permissions on the view. It must be admin because we do not want every team owner/admin permission to merge their team with *any* other team. Delete restricts the operation to the context team and ~registry.
> Demo and Q/A
> ------------
>
> * Add ~no-priv to the ~registry team.
> * Login as ~no-priv.
> * Open http://
> * Add a team with a contact email address.
> * You will need to verify the email address with the token it emails you.
> (On launchpad.dev, you can just look in the logintoken table and paste the
> token into https:/
> * Open http://
> * Click on "Merge teams"
> * Enter you new team for the first team.
> * Enter "ubuntu-team" for the second team.
> * Click "Merge"
> * When you get a warning message, click "Deactivate members and merge".
This story is wrong. The delete team scenario is a very restricted merge operation that registry administators may perform. Admins can do unrestricted merges.
* As registry expert.
* Visit https:/
* This team has an email address in NEW status
* team email addresses are not shown in the UI
* only the team owner can access the address.
* Choose Delete team.
* Verify the team is gone.
The code change is the the view, so we want a test that verifies the view handles the real conditions. The test should be in lp/registry/
* Create a team with an email address.
* deletable_
* login_person(
* form = {'field.
* view = create_
* view.errors
[]
* for notification in view.request.
print notification.
Team deleted.
Curtis Hovey (sinzui) wrote : | # |
> * Create a team with an email address.
> * deletable_
I think I meant deletable_team.
Edwin Grubbs (edwin-grubbs) wrote : | # |
> Hi Edwin.
>
> There are some dangerous changes in the code and the test does is not what is
> happening in production.
>
> We need to revert the permissions on the view. It must be admin because we do
> not want every team owner/admin permission to merge their team with *any*
> other team. Delete restricts the operation to the context team and ~registry.
Hi Sinzui,
Thanks for the review. As discussed on IRC, the permissions for the view and for the +adminmergeteam link are fine since it uses launchpad.Moderate on IPersonSet, which does not include admins of any team.
> > Demo and Q/A
> > ------------
> >
> > * Add ~no-priv to the ~registry team.
> > * Login as ~no-priv.
> > * Open http://
> > * Add a team with a contact email address.
> > * You will need to verify the email address with the token it emails you.
> > (On launchpad.dev, you can just look in the logintoken table and paste the
> > token into https:/
> > * Open http://
> > * Click on "Merge teams"
> > * Enter you new team for the first team.
> > * Enter "ubuntu-team" for the second team.
> > * Click "Merge"
> > * When you get a warning message, click "Deactivate members and merge".
>
> This story is wrong. The delete team scenario is a very restricted merge
> operation that registry administators may perform. Admins can do unrestricted
> merges.
> * As registry expert.
> * Visit https:/
> * This team has an email address in NEW status
> * team email addresses are not shown in the UI
> * only the team owner can access the address.
> * Choose Delete team.
> * Verify the team is gone.
>
> The code change is the the view, so we want a test that verifies the view
> handles the real conditions. The test should be in lp/registry/tests
> /peoplemerge-
> this story
> * Create a team with an email address.
> * deletable_
> * login_person(
> * form = {'field.
> * view = create_
> * view.errors
> []
> * for notification in view.request.
> print notification.
> Team deleted.
I have added this test. I also changed other parts of the test that was using the owner of the registry team, which is mark. Since mark is also in the admin team, I don't think it is a very effective test of the registry experts abilities to use him.
-Edwin
Incremental diff:
{{{
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -6,9 +6,17 @@
Team Merges
-----------
+Create a member of the registry team that is not a member of the admins
+team.
+
>>> from lp.registry.
+ >>> from canonical.
+ >>> registry_e...
Curtis Hovey (sinzui) wrote : | # |
Hi Edwin.
Thank you for correcting the registry-experts test. I am sure something
bad would have happened using a super-powerful moderator. This did
happen to me in a test for mirror admins, which user Mark owns.
I have one small suggestion for the test.
review approve
On Wed, 2010-01-20 at 00:02 +0000, Edwin Grubbs wrote:
> Incremental diff:
> {{{
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -6,9 +6,17 @@
> Team Merges
> -----------
...
> @@ -39,6 +47,7 @@
> >>> parent_team = factory.makeTeam()
> >>> child_team = factory.
> >>> random_team = factory.makeTeam()
> + >>> login('<email address hidden>')
Use login('<email address hidden>') so that the role is clear.
...
--
__Curtis C. Hovey_________
http://
Preview Diff
1 | === modified file 'lib/lp/registry/browser/menu.py' |
2 | --- lib/lp/registry/browser/menu.py 2009-08-21 20:04:25 +0000 |
3 | +++ lib/lp/registry/browser/menu.py 2010-01-20 00:01:15 +0000 |
4 | @@ -60,7 +60,7 @@ |
5 | text = 'Merge people' |
6 | return Link('/people/+adminpeoplemerge', text, icon='edit') |
7 | |
8 | - @enabled_with_permission('launchpad.Admin') |
9 | + @enabled_with_permission('launchpad.Moderate') |
10 | def admin_merge_teams(self): |
11 | text = 'Merge teams' |
12 | return Link('/people/+adminteammerge', text, icon='edit') |
13 | |
14 | === modified file 'lib/lp/registry/browser/peoplemerge.py' |
15 | --- lib/lp/registry/browser/peoplemerge.py 2010-01-12 00:19:20 +0000 |
16 | +++ lib/lp/registry/browser/peoplemerge.py 2010-01-20 00:01:15 +0000 |
17 | @@ -140,15 +140,15 @@ |
18 | from zope.security.proxy import removeSecurityProxy |
19 | for email in self.dupe_person_emails: |
20 | email = IMasterObject(email) |
21 | - # XXX: Guilherme Salgado 2007-10-15: Maybe this status change |
22 | - # should be done only when merging people but not when merging |
23 | - # teams. |
24 | - email.status = EmailAddressStatus.NEW |
25 | # EmailAddress.person and EmailAddress.account are readonly |
26 | # fields, so we need to remove the security proxy here. |
27 | naked_email = removeSecurityProxy(email) |
28 | naked_email.personID = self.target_person.id |
29 | naked_email.accountID = self.target_person.accountID |
30 | + # XXX: Guilherme Salgado 2007-10-15: Maybe this status change |
31 | + # should be done only when merging people but not when merging |
32 | + # teams. |
33 | + naked_email.status = EmailAddressStatus.NEW |
34 | flush_database_updates() |
35 | getUtility(IPersonSet).merge(self.dupe_person, self.target_person) |
36 | self.request.response.addInfoNotification(self.merge_message) |
37 | |
38 | === modified file 'lib/lp/registry/browser/tests/peoplemerge-views.txt' |
39 | --- lib/lp/registry/browser/tests/peoplemerge-views.txt 2010-01-06 17:52:45 +0000 |
40 | +++ lib/lp/registry/browser/tests/peoplemerge-views.txt 2010-01-20 00:01:15 +0000 |
41 | @@ -6,9 +6,17 @@ |
42 | Team Merges |
43 | ----------- |
44 | |
45 | +Create a member of the registry team that is not a member of the admins |
46 | +team. |
47 | + |
48 | >>> from lp.registry.interfaces.person import IPersonSet |
49 | + >>> from canonical.launchpad.interfaces import ILaunchpadCelebrities |
50 | + >>> registry_experts = getUtility(ILaunchpadCelebrities).registry_experts |
51 | >>> person_set = getUtility(IPersonSet) |
52 | - >>> registry_expert = person_set.getByName('mark') |
53 | + >>> registry_expert = factory.makePerson() |
54 | + >>> login_person(registry_experts.teamowner) |
55 | + >>> ignored = registry_experts.addMember( |
56 | + ... registry_expert, registry_experts.teamowner) |
57 | >>> login_person(registry_expert) |
58 | |
59 | A team (name21) can be merged into another (ubuntu-team). |
60 | @@ -39,6 +47,7 @@ |
61 | >>> parent_team = factory.makeTeam() |
62 | >>> child_team = factory.makeTeam(name='child-team') |
63 | >>> random_team = factory.makeTeam() |
64 | + >>> login('foo.bar@canonical.com') |
65 | >>> ignored = parent_team.addMember( |
66 | ... child_team, reviewer=parent_team.teamowner, force_team_add=True) |
67 | >>> form = {'field.dupe_person': child_team.name, |
68 | @@ -112,10 +121,8 @@ |
69 | Users with launchpad.Moderate such as team admins and registry experts |
70 | can delete teams. |
71 | |
72 | - >>> from canonical.launchpad.interfaces import ILaunchpadCelebrities |
73 | >>> from canonical.launchpad.webapp.authorization import check_permission |
74 | |
75 | - >>> registry_experts = getUtility(ILaunchpadCelebrities).registry_experts |
76 | >>> team_owner = factory.makePerson() |
77 | >>> team_member = factory.makePerson() |
78 | >>> deletable_team = factory.makeTeam(owner=team_owner, name='deletable') |
79 | @@ -127,7 +134,7 @@ |
80 | >>> check_permission('launchpad.Moderate', view) |
81 | False |
82 | |
83 | - >>> login_person(registry_experts.teamowner) |
84 | + >>> login_person(registry_expert) |
85 | >>> check_permission('launchpad.Moderate', view) |
86 | True |
87 | |
88 | @@ -241,3 +248,26 @@ |
89 | |
90 | >>> print find_tag_by_id(content, 'field.actions.delete') |
91 | None |
92 | + |
93 | +The registry experts should be able to delete a team with an |
94 | +validated email address, which will be invisible, since only |
95 | +preferred email addresses are shown for teams. |
96 | + |
97 | + >>> from canonical.launchpad.interfaces.emailaddress import ( |
98 | + ... IEmailAddressSet) |
99 | + >>> login_person(registry_expert) |
100 | + >>> admin = getUtility(ILaunchpadCelebrities).admin |
101 | + >>> registry_expert.inTeam(admin) |
102 | + False |
103 | + >>> deletable_team = factory.makeTeam(email="del@example.com") |
104 | + >>> deletable_team.setContactAddress(None) |
105 | + >>> for email in getUtility(IEmailAddressSet).getByPerson(deletable_team): |
106 | + ... print email.email, email.status.title |
107 | + del@example.com Validated Email Address |
108 | + >>> form = {'field.actions.delete': 'Delete'} |
109 | + >>> view = create_initialized_view(deletable_team, '+delete', form=form) |
110 | + >>> view.errors |
111 | + [] |
112 | + >>> for notification in view.request.response.notifications: |
113 | + ... print notification.message |
114 | + Team deleted. |
115 | |
116 | === modified file 'lib/lp/registry/stories/team/xx-adminteammerge.txt' |
117 | --- lib/lp/registry/stories/team/xx-adminteammerge.txt 2009-11-22 15:43:16 +0000 |
118 | +++ lib/lp/registry/stories/team/xx-adminteammerge.txt 2010-01-20 00:01:15 +0000 |
119 | @@ -4,30 +4,39 @@ |
120 | active members, so the user will first have to confirm that the |
121 | members should be deactivated before the teams are merged. |
122 | |
123 | - >>> admin_browser.open('http://launchpad.dev/people/+adminteammerge') |
124 | - >>> admin_browser.getControl('Duplicated Team').value = ( |
125 | - ... 'landscape-developers') |
126 | - >>> admin_browser.getControl('Target Team').value = 'guadamen' |
127 | - >>> admin_browser.getControl('Merge').click() |
128 | + >>> from zope.component import getUtility |
129 | + >>> from lp.registry.interfaces.person import IPersonSet |
130 | + >>> login('foo.bar@canonical.com') |
131 | + >>> registry_expert = factory.makePerson( |
132 | + ... email='reg@example.com', password='test') |
133 | + >>> new_team = factory.makeTeam( |
134 | + ... name="new-team", email="new_team@example.com") |
135 | + >>> registry_experts = getUtility(IPersonSet).getByName('registry') |
136 | + >>> ignored = registry_experts.addMember( |
137 | + ... registry_expert, registry_experts.teamowner) |
138 | + >>> logout() |
139 | + >>> registry_browser = setupBrowser(auth='Basic reg@example.com:test') |
140 | + >>> registry_browser.open('http://launchpad.dev/people/+adminteammerge') |
141 | + >>> registry_browser.getControl('Duplicated Team').value = ( |
142 | + ... 'new-team') |
143 | + >>> registry_browser.getControl('Target Team').value = 'guadamen' |
144 | + >>> registry_browser.getControl('Merge').click() |
145 | |
146 | - >>> admin_browser.url |
147 | + >>> registry_browser.url |
148 | 'http://launchpad.dev/people/+adminteammerge' |
149 | - >>> print get_feedback_messages(admin_browser.contents)[0] |
150 | - Landscape Developers has 2 active members which will have to be |
151 | - deactivated before the teams can be merged. |
152 | + >>> print get_feedback_messages(registry_browser.contents)[0] |
153 | + New Team has 1 active members which will have to be deactivated |
154 | + before the teams can be merged. |
155 | |
156 | - >>> admin_browser.getControl('Deactivate Members and Merge').click() |
157 | - >>> admin_browser.url |
158 | + >>> registry_browser.getControl('Deactivate Members and Merge').click() |
159 | + >>> registry_browser.url |
160 | 'http://launchpad.dev/~guadamen' |
161 | |
162 | >>> from canonical.launchpad.ftests import ANONYMOUS, login, logout |
163 | - >>> from canonical.launchpad.interfaces import IMailingListSet, IPersonSet |
164 | + >>> from canonical.launchpad.interfaces import IMailingListSet |
165 | >>> from zope.component import getUtility |
166 | >>> login(ANONYMOUS) |
167 | - >>> person_set = getUtility(IPersonSet) |
168 | - >>> landscape = person_set.getByName( |
169 | - ... 'landscape-developers-merged', ignore_merged=False) |
170 | - >>> landscape.merged.name |
171 | + >>> new_team.merged.name |
172 | u'guadamen' |
173 | >>> logout() |
174 | |
175 | @@ -36,7 +45,7 @@ |
176 | |
177 | Merged teams are not visible anymore. |
178 | |
179 | - >>> browser.open("http://launchpad.dev/~landscape-developers-merged") |
180 | + >>> browser.open("http://launchpad.dev/~new-team-merged") |
181 | Traceback (most recent call last): |
182 | ... |
183 | NotFound:... |
184 | @@ -48,45 +57,45 @@ |
185 | merged, though. |
186 | |
187 | >>> login(ANONYMOUS) |
188 | - >>> guadamen = person_set.getByName('guadamen') |
189 | + >>> guadamen = getUtility(IPersonSet).getByName('guadamen') |
190 | >>> mailing_list = getUtility(IMailingListSet).new(guadamen) |
191 | >>> logout() |
192 | |
193 | - >>> admin_browser.open('http://launchpad.dev/people/+adminteammerge') |
194 | - >>> admin_browser.getControl('Duplicated Team').value = 'guadamen' |
195 | - >>> admin_browser.getControl('Target Team').value = 'ubuntu-team' |
196 | - >>> admin_browser.getControl('Merge').click() |
197 | + >>> registry_browser.open('http://launchpad.dev/people/+adminteammerge') |
198 | + >>> registry_browser.getControl('Duplicated Team').value = 'guadamen' |
199 | + >>> registry_browser.getControl('Target Team').value = 'ubuntu-team' |
200 | + >>> registry_browser.getControl('Merge').click() |
201 | |
202 | - >>> admin_browser.url |
203 | + >>> registry_browser.url |
204 | 'http://launchpad.dev/people/+adminteammerge' |
205 | |
206 | - >>> print get_feedback_messages(admin_browser.contents) |
207 | + >>> print get_feedback_messages(registry_browser.contents) |
208 | [u'There is 1 error.', |
209 | u"guadamen is associated with a Launchpad mailing list; |
210 | we can't merge it."] |
211 | |
212 | We also can't (for obvious reasons) merge any person/team into itself. |
213 | |
214 | - >>> admin_browser.getControl('Duplicated Team').value = 'shipit-admins' |
215 | - >>> admin_browser.getControl('Target Team').value = 'shipit-admins' |
216 | - >>> admin_browser.getControl('Merge').click() |
217 | + >>> registry_browser.getControl('Duplicated Team').value = 'shipit-admins' |
218 | + >>> registry_browser.getControl('Target Team').value = 'shipit-admins' |
219 | + >>> registry_browser.getControl('Merge').click() |
220 | |
221 | - >>> admin_browser.url |
222 | + >>> registry_browser.url |
223 | 'http://launchpad.dev/people/+adminteammerge' |
224 | |
225 | - >>> print get_feedback_messages(admin_browser.contents) |
226 | + >>> print get_feedback_messages(registry_browser.contents) |
227 | [u'There is 1 error.', u"You can't merge shipit-admins into itself."] |
228 | |
229 | Nor can we merge a person into a team or a team into a person. |
230 | |
231 | - >>> admin_browser.getControl('Duplicated Team').value = 'ubuntu-team' |
232 | - >>> admin_browser.getControl('Target Team').value = 'salgado' |
233 | - >>> admin_browser.getControl('Merge').click() |
234 | + >>> registry_browser.getControl('Duplicated Team').value = 'ubuntu-team' |
235 | + >>> registry_browser.getControl('Target Team').value = 'salgado' |
236 | + >>> registry_browser.getControl('Merge').click() |
237 | |
238 | - >>> admin_browser.url |
239 | + >>> registry_browser.url |
240 | 'http://launchpad.dev/people/+adminteammerge' |
241 | |
242 | # Yes, the error message is not of much help, but this UI is only for |
243 | # admins and they're supposed to know what they're doing. |
244 | - >>> print get_feedback_messages(admin_browser.contents) |
245 | + >>> print get_feedback_messages(registry_browser.contents) |
246 | [u'There is 1 error.', u'Constraint not satisfied'] |
Summary
-------
Fixed oops caused when a registry expert (non-admin) merges a team with an email address into another team.
Implementation details ------- ------- -
-------
Set email status after removing security adapter to give the registry expert access in this special case.
Tests
-----
./bin/test -vv -t xx-adminteammer ge.txt
Demo and Q/A
------------
* Add ~no-priv to the ~registry team. launchpad. dev/people/ +newteam /launchpad. dev/token/ $token) launchpad. dev/people/
* Login as ~no-priv.
* Open http://
* Add a team with a contact email address.
* You will need to verify the email address with the token it emails you. (On launchpad.dev, you can just look in the logintoken table and paste the token into https:/
* Open http://
* Click on "Merge teams"
* Enter you new team for the first team.
* Enter "ubuntu-team" for the second team.
* Click "Merge"
* When you get a warning message, click "Deactivate members and merge".