blob: cd67c6c60b456312ef0c8c7adc6c8113e812a90a [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2016 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file or at
4# https://developers.google.com/open-source/licenses/bsd
5
6"""Tests for permissions.py."""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
11import time
12import unittest
13
Adrià Vilanova Martínez9f9ade52022-10-10 23:20:11 +020014try:
15 from mox3 import mox
16except ImportError:
17 import mox
Copybara854996b2021-09-07 19:36:02 +000018
19import settings
20from framework import authdata
21from framework import framework_constants
22from framework import framework_views
23from framework import permissions
24from proto import features_pb2
25from proto import project_pb2
26from proto import site_pb2
27from proto import tracker_pb2
28from proto import user_pb2
29from proto import usergroup_pb2
30from testing import fake
31from testing import testing_helpers
32from tracker import tracker_bizobj
33
34
35class PermissionSetTest(unittest.TestCase):
36
37 def setUp(self):
38 self.perms = permissions.PermissionSet(['A', 'b', 'Cc'])
39 self.proj = project_pb2.Project()
40 self.proj.contributor_ids.append(111)
41 self.proj.contributor_ids.append(222)
42 self.proj.extra_perms.append(project_pb2.Project.ExtraPerms(
43 member_id=111, perms=['Cc', 'D', 'e', 'Ff']))
44 self.proj.extra_perms.append(project_pb2.Project.ExtraPerms(
45 member_id=222, perms=['G', 'H']))
46 # user 3 used to be a member and had extra perms, but no longer in project.
47 self.proj.extra_perms.append(project_pb2.Project.ExtraPerms(
48 member_id=333, perms=['G', 'H']))
49
50 def testGetAttr(self):
51 self.assertTrue(self.perms.a)
52 self.assertTrue(self.perms.A)
53 self.assertTrue(self.perms.b)
54 self.assertTrue(self.perms.Cc)
55 self.assertTrue(self.perms.CC)
56
57 self.assertFalse(self.perms.z)
58 self.assertFalse(self.perms.Z)
59
60 def testCanUsePerm_Anonymous(self):
61 effective_ids = set()
62 self.assertTrue(self.perms.CanUsePerm('A', effective_ids, self.proj, []))
63 self.assertFalse(self.perms.CanUsePerm('D', effective_ids, self.proj, []))
64 self.assertFalse(self.perms.CanUsePerm('Z', effective_ids, self.proj, []))
65
66 def testCanUsePerm_SignedInNoGroups(self):
67 effective_ids = {111}
68 self.assertTrue(self.perms.CanUsePerm('A', effective_ids, self.proj, []))
69 self.assertTrue(self.perms.CanUsePerm('D', effective_ids, self.proj, []))
70 self.assertTrue(self.perms.CanUsePerm(
71 'D', effective_ids, self.proj, ['Restrict-D-A']))
72 self.assertFalse(self.perms.CanUsePerm('G', effective_ids, self.proj, []))
73 self.assertFalse(self.perms.CanUsePerm('Z', effective_ids, self.proj, []))
74
75 effective_ids = {222}
76 self.assertTrue(self.perms.CanUsePerm('A', effective_ids, self.proj, []))
77 self.assertFalse(self.perms.CanUsePerm('D', effective_ids, self.proj, []))
78 self.assertTrue(self.perms.CanUsePerm('G', effective_ids, self.proj, []))
79 self.assertFalse(self.perms.CanUsePerm('Z', effective_ids, self.proj, []))
80 self.assertFalse(self.perms.CanUsePerm(
81 'Z', effective_ids, self.proj, ['Restrict-Z-A']))
82
83 def testCanUsePerm_SignedInWithGroups(self):
84 effective_ids = {111, 222, 333}
85 self.assertTrue(self.perms.CanUsePerm('A', effective_ids, self.proj, []))
86 self.assertTrue(self.perms.CanUsePerm('D', effective_ids, self.proj, []))
87 self.assertTrue(self.perms.CanUsePerm('G', effective_ids, self.proj, []))
88 self.assertTrue(self.perms.CanUsePerm(
89 'G', effective_ids, self.proj, ['Restrict-G-D']))
90 self.assertFalse(self.perms.CanUsePerm('Z', effective_ids, self.proj, []))
91 self.assertFalse(self.perms.CanUsePerm(
92 'G', effective_ids, self.proj, ['Restrict-G-Z']))
93
94 def testCanUsePerm_FormerMember(self):
95 effective_ids = {333}
96 self.assertTrue(self.perms.CanUsePerm('A', effective_ids, self.proj, []))
97 self.assertFalse(self.perms.CanUsePerm('D', effective_ids, self.proj, []))
98 self.assertFalse(self.perms.CanUsePerm('G', effective_ids, self.proj, []))
99 self.assertFalse(self.perms.CanUsePerm('Z', effective_ids, self.proj, []))
100
101 def testHasPerm_InPermSet(self):
102 self.assertTrue(self.perms.HasPerm('a', 0, None))
103 self.assertTrue(self.perms.HasPerm('a', 0, self.proj))
104 self.assertTrue(self.perms.HasPerm('A', 0, None))
105 self.assertTrue(self.perms.HasPerm('A', 0, self.proj))
106 self.assertFalse(self.perms.HasPerm('Z', 0, None))
107 self.assertFalse(self.perms.HasPerm('Z', 0, self.proj))
108
109 def testHasPerm_InExtraPerms(self):
110 self.assertTrue(self.perms.HasPerm('d', 111, self.proj))
111 self.assertTrue(self.perms.HasPerm('D', 111, self.proj))
112 self.assertTrue(self.perms.HasPerm('Cc', 111, self.proj))
113 self.assertTrue(self.perms.HasPerm('CC', 111, self.proj))
114 self.assertFalse(self.perms.HasPerm('Z', 111, self.proj))
115
116 self.assertFalse(self.perms.HasPerm('d', 222, self.proj))
117 self.assertFalse(self.perms.HasPerm('D', 222, self.proj))
118
119 # Only current members can have extra permissions
120 self.proj.contributor_ids = []
121 self.assertFalse(self.perms.HasPerm('d', 111, self.proj))
122
123 # TODO(jrobbins): also test consider_restrictions=False and
124 # restriction labels directly in this class.
125
126 def testHasPerm_OverrideExtraPerms(self):
127 # D is an extra perm for 111...
128 self.assertTrue(self.perms.HasPerm('d', 111, self.proj))
129 self.assertTrue(self.perms.HasPerm('D', 111, self.proj))
130 # ...unless we tell HasPerm it isn't.
131 self.assertFalse(self.perms.HasPerm('d', 111, self.proj, []))
132 self.assertFalse(self.perms.HasPerm('D', 111, self.proj, []))
133 # Perms in self.perms are still considered
134 self.assertTrue(self.perms.HasPerm('Cc', 111, self.proj, []))
135 self.assertTrue(self.perms.HasPerm('CC', 111, self.proj, []))
136 # Z is not an extra perm...
137 self.assertFalse(self.perms.HasPerm('Z', 111, self.proj))
138 # ...unless we tell HasPerm it is.
139 self.assertTrue(self.perms.HasPerm('Z', 111, self.proj, ['z']))
140
141 def testHasPerm_GrantedPerms(self):
142 self.assertTrue(self.perms.CanUsePerm(
143 'A', {111}, self.proj, [], granted_perms=['z']))
144 self.assertTrue(self.perms.CanUsePerm(
145 'a', {111}, self.proj, [], granted_perms=['z']))
146 self.assertTrue(self.perms.CanUsePerm(
147 'a', {111}, self.proj, [], granted_perms=['a']))
148 self.assertTrue(self.perms.CanUsePerm(
149 'Z', {111}, self.proj, [], granted_perms=['y', 'z']))
150 self.assertTrue(self.perms.CanUsePerm(
151 'z', {111}, self.proj, [], granted_perms=['y', 'z']))
152 self.assertFalse(self.perms.CanUsePerm(
153 'z', {111}, self.proj, [], granted_perms=['y']))
154
155 def testDebugString(self):
156 self.assertEqual('PermissionSet()',
157 permissions.PermissionSet([]).DebugString())
158 self.assertEqual('PermissionSet(a)',
159 permissions.PermissionSet(['A']).DebugString())
160 self.assertEqual('PermissionSet(a, b, cc)', self.perms.DebugString())
161
162 def testRepr(self):
163 self.assertEqual('PermissionSet(frozenset([]))',
164 permissions.PermissionSet([]).__repr__())
165 self.assertEqual('PermissionSet(frozenset([\'a\']))',
166 permissions.PermissionSet(['A']).__repr__())
167
168
169class PermissionsTest(unittest.TestCase):
170
171 NOW = 1277762224 # Any timestamp will do, we only compare it to itself +/- 1
172 COMMITTER_USER_ID = 111
173 OWNER_USER_ID = 222
174 CONTRIB_USER_ID = 333
175 SITE_ADMIN_USER_ID = 444
176
177 def MakeProject(self, project_name, state, add_members=True, access=None):
178 args = dict(project_name=project_name, state=state)
179 if add_members:
180 args.update(owner_ids=[self.OWNER_USER_ID],
181 committer_ids=[self.COMMITTER_USER_ID],
182 contributor_ids=[self.CONTRIB_USER_ID])
183
184 if access:
185 args.update(access=access)
186
187 return fake.Project(**args)
188
189 def setUp(self):
190 self.live_project = self.MakeProject('live', project_pb2.ProjectState.LIVE)
191 self.archived_project = self.MakeProject(
192 'archived', project_pb2.ProjectState.ARCHIVED)
193 self.other_live_project = self.MakeProject(
194 'other_live', project_pb2.ProjectState.LIVE, add_members=False)
195 self.members_only_project = self.MakeProject(
196 's3kr3t', project_pb2.ProjectState.LIVE,
197 access=project_pb2.ProjectAccess.MEMBERS_ONLY)
198
199 self.nonmember = user_pb2.User()
200 self.member = user_pb2.User()
201 self.owner = user_pb2.User()
202 self.contrib = user_pb2.User()
203 self.site_admin = user_pb2.User()
204 self.site_admin.is_site_admin = True
205 self.borg_user = user_pb2.User(email=settings.borg_service_account)
206
207 self.normal_artifact = tracker_pb2.Issue()
208 self.normal_artifact.labels.extend(['hot', 'Key-Value'])
209 self.normal_artifact.reporter_id = 111
210
211 # Two PermissionSets w/ permissions outside of any project.
212 self.normal_user_perms = permissions.GetPermissions(
213 None, {111}, None)
214 self.admin_perms = permissions.PermissionSet(
215 [permissions.ADMINISTER_SITE,
216 permissions.CREATE_PROJECT])
217
218 self.mox = mox.Mox()
219
220 def tearDown(self):
221 self.mox.UnsetStubs()
222
223 def testGetPermissions_Admin(self):
224 self.assertEqual(
225 permissions.ADMIN_PERMISSIONSET,
226 permissions.GetPermissions(self.site_admin, None, None))
227
228 def testGetPermissions_BorgServiceAccount(self):
229 self.assertEqual(
230 permissions.GROUP_IMPORT_BORG_PERMISSIONSET,
231 permissions.GetPermissions(self.borg_user, None, None))
232
233 def CheckPermissions(self, perms, expected_list):
234 expect_view, expect_commit, expect_edit_project = expected_list
235 self.assertEqual(
236 expect_view, perms.HasPerm(permissions.VIEW, None, None))
237 self.assertEqual(
238 expect_commit, perms.HasPerm(permissions.COMMIT, None, None))
239 self.assertEqual(
240 expect_edit_project,
241 perms.HasPerm(permissions.EDIT_PROJECT, None, None))
242
243 def testAnonPermissions(self):
244 perms = permissions.GetPermissions(None, set(), self.live_project)
245 self.CheckPermissions(perms, [True, False, False])
246
247 perms = permissions.GetPermissions(None, set(), self.members_only_project)
248 self.CheckPermissions(perms, [False, False, False])
249
250 def testNonmemberPermissions(self):
251 perms = permissions.GetPermissions(
252 self.nonmember, {123}, self.live_project)
253 self.CheckPermissions(perms, [True, False, False])
254
255 perms = permissions.GetPermissions(
256 self.nonmember, {123}, self.members_only_project)
257 self.CheckPermissions(perms, [False, False, False])
258
259 def testMemberPermissions(self):
260 perms = permissions.GetPermissions(
261 self.member, {self.COMMITTER_USER_ID}, self.live_project)
262 self.CheckPermissions(perms, [True, True, False])
263
264 perms = permissions.GetPermissions(
265 self.member, {self.COMMITTER_USER_ID}, self.other_live_project)
266 self.CheckPermissions(perms, [True, False, False])
267
268 perms = permissions.GetPermissions(
269 self.member, {self.COMMITTER_USER_ID}, self.members_only_project)
270 self.CheckPermissions(perms, [True, True, False])
271
272 def testOwnerPermissions(self):
273 perms = permissions.GetPermissions(
274 self.owner, {self.OWNER_USER_ID}, self.live_project)
275 self.CheckPermissions(perms, [True, True, True])
276
277 perms = permissions.GetPermissions(
278 self.owner, {self.OWNER_USER_ID}, self.other_live_project)
279 self.CheckPermissions(perms, [True, False, False])
280
281 perms = permissions.GetPermissions(
282 self.owner, {self.OWNER_USER_ID}, self.members_only_project)
283 self.CheckPermissions(perms, [True, True, True])
284
285 def testContributorPermissions(self):
286 perms = permissions.GetPermissions(
287 self.contrib, {self.CONTRIB_USER_ID}, self.live_project)
288 self.CheckPermissions(perms, [True, False, False])
289
290 perms = permissions.GetPermissions(
291 self.contrib, {self.CONTRIB_USER_ID}, self.other_live_project)
292 self.CheckPermissions(perms, [True, False, False])
293
294 perms = permissions.GetPermissions(
295 self.contrib, {self.CONTRIB_USER_ID}, self.members_only_project)
296 self.CheckPermissions(perms, [True, False, False])
297
298 def testLookupPermset_ExactMatch(self):
299 self.assertEqual(
300 permissions.USER_PERMISSIONSET,
301 permissions._LookupPermset(
302 permissions.USER_ROLE, project_pb2.ProjectState.LIVE,
303 project_pb2.ProjectAccess.ANYONE))
304
305 def testLookupPermset_WildcardAccess(self):
306 self.assertEqual(
307 permissions.OWNER_ACTIVE_PERMISSIONSET,
308 permissions._LookupPermset(
309 permissions.OWNER_ROLE, project_pb2.ProjectState.LIVE,
310 project_pb2.ProjectAccess.MEMBERS_ONLY))
311
312 def testGetPermissionKey_AnonUser(self):
313 self.assertEqual(
314 (permissions.ANON_ROLE, permissions.UNDEFINED_STATUS,
315 permissions.UNDEFINED_ACCESS),
316 permissions._GetPermissionKey(None, None))
317 self.assertEqual(
318 (permissions.ANON_ROLE, project_pb2.ProjectState.LIVE,
319 project_pb2.ProjectAccess.ANYONE),
320 permissions._GetPermissionKey(None, self.live_project))
321
322 def testGetPermissionKey_ExpiredProject(self):
323 self.archived_project.delete_time = self.NOW
324 # In an expired project, the user's committe role does not count.
325 self.assertEqual(
326 (permissions.USER_ROLE, project_pb2.ProjectState.ARCHIVED,
327 project_pb2.ProjectAccess.ANYONE),
328 permissions._GetPermissionKey(
329 self.COMMITTER_USER_ID, self.archived_project,
330 expired_before=self.NOW + 1))
331 # If not expired yet, the user's committe role still counts.
332 self.assertEqual(
333 (permissions.COMMITTER_ROLE, project_pb2.ProjectState.ARCHIVED,
334 project_pb2.ProjectAccess.ANYONE),
335 permissions._GetPermissionKey(
336 self.COMMITTER_USER_ID, self.archived_project,
337 expired_before=self.NOW - 1))
338
339 def testGetPermissionKey_DefinedRoles(self):
340 self.assertEqual(
341 (permissions.OWNER_ROLE, project_pb2.ProjectState.LIVE,
342 project_pb2.ProjectAccess.ANYONE),
343 permissions._GetPermissionKey(
344 self.OWNER_USER_ID, self.live_project))
345 self.assertEqual(
346 (permissions.COMMITTER_ROLE, project_pb2.ProjectState.LIVE,
347 project_pb2.ProjectAccess.ANYONE),
348 permissions._GetPermissionKey(
349 self.COMMITTER_USER_ID, self.live_project))
350 self.assertEqual(
351 (permissions.CONTRIBUTOR_ROLE, project_pb2.ProjectState.LIVE,
352 project_pb2.ProjectAccess.ANYONE),
353 permissions._GetPermissionKey(
354 self.CONTRIB_USER_ID, self.live_project))
355
356 def testGetPermissionKey_Nonmember(self):
357 self.assertEqual(
358 (permissions.USER_ROLE, project_pb2.ProjectState.LIVE,
359 project_pb2.ProjectAccess.ANYONE),
360 permissions._GetPermissionKey(
361 999, self.live_project))
362
363 def testPermissionsImmutable(self):
364 self.assertTrue(isinstance(
365 permissions.EMPTY_PERMISSIONSET.perm_names, frozenset))
366 self.assertTrue(isinstance(
367 permissions.READ_ONLY_PERMISSIONSET.perm_names, frozenset))
368 self.assertTrue(isinstance(
369 permissions.COMMITTER_ACTIVE_PERMISSIONSET.perm_names, frozenset))
370 self.assertTrue(isinstance(
371 permissions.OWNER_ACTIVE_PERMISSIONSET.perm_names, frozenset))
372
373 def testGetExtraPerms(self):
374 project = project_pb2.Project()
375 project.committer_ids.append(222)
376 # User 1 is a former member with left-over extra perms that don't count.
377 project.extra_perms.append(project_pb2.Project.ExtraPerms(
378 member_id=111, perms=['a', 'b', 'c']))
379 project.extra_perms.append(project_pb2.Project.ExtraPerms(
380 member_id=222, perms=['a', 'b', 'c']))
381
382 self.assertListEqual(
383 [],
384 permissions.GetExtraPerms(project, 111))
385 self.assertListEqual(
386 ['a', 'b', 'c'],
387 permissions.GetExtraPerms(project, 222))
388 self.assertListEqual(
389 [],
390 permissions.GetExtraPerms(project, 333))
391
392 def testCanDeleteComment_NoPermissionSet(self):
393 """Test that if no PermissionSet is given, we can't delete comments."""
394 comment = tracker_pb2.IssueComment()
395 commenter = user_pb2.User()
396 # If no PermissionSet is given, the user cannot delete the comment.
397 self.assertFalse(permissions.CanDeleteComment(
398 comment, commenter, 111, None))
399 # Same, with no user specified.
400 self.assertFalse(permissions.CanDeleteComment(
401 comment, commenter, framework_constants.NO_USER_SPECIFIED, None))
402
403 def testCanDeleteComment_AnonUsersCannotDelete(self):
404 """Test that anon users can't delete comments."""
405 comment = tracker_pb2.IssueComment()
406 commenter = user_pb2.User()
407 perms = permissions.PermissionSet([permissions.DELETE_ANY])
408
409 # No logged in user, even with perms from somewhere.
410 self.assertFalse(permissions.CanDeleteComment(
411 comment, commenter, framework_constants.NO_USER_SPECIFIED, perms))
412
413 # No logged in user, even if artifact was already deleted.
414 comment.deleted_by = 111
415 self.assertFalse(permissions.CanDeleteComment(
416 comment, commenter, framework_constants.NO_USER_SPECIFIED, perms))
417
418 def testCanDeleteComment_DeleteAny(self):
419 """Test that users with DeleteAny permission can delete any comment.
420
421 Except for spam comments or comments by banned users.
422 """
423 comment = tracker_pb2.IssueComment(user_id=111)
424 commenter = user_pb2.User()
425 perms = permissions.PermissionSet([permissions.DELETE_ANY])
426
427 # Users with DeleteAny permission can delete their own comments.
428 self.assertTrue(permissions.CanDeleteComment(
429 comment, commenter, 111, perms))
430
431 # And also comments by other users
432 comment.user_id = 999
433 self.assertTrue(permissions.CanDeleteComment(
434 comment, commenter, 111, perms))
435
436 # As well as undelete comments they deleted.
437 comment.deleted_by = 111
438 self.assertTrue(permissions.CanDeleteComment(
439 comment, commenter, 111, perms))
440
441 # Or that other users deleted.
442 comment.deleted_by = 222
443 self.assertTrue(permissions.CanDeleteComment(
444 comment, commenter, 111, perms))
445
446 def testCanDeleteComment_DeleteOwn(self):
447 """Test that users with DeleteOwn permission can delete any comment.
448
449 Except for spam comments or comments by banned users.
450 """
451 comment = tracker_pb2.IssueComment(user_id=111)
452 commenter = user_pb2.User()
453 perms = permissions.PermissionSet([permissions.DELETE_OWN])
454
455 # Users with DeleteOwn permission can delete their own comments.
456 self.assertTrue(permissions.CanDeleteComment(
457 comment, commenter, 111, perms))
458
459 # But not comments by other users
460 comment.user_id = 999
461 self.assertFalse(permissions.CanDeleteComment(
462 comment, commenter, 111, perms))
463
464 # They can undelete comments they deleted.
465 comment.user_id = 111
466 comment.deleted_by = 111
467 self.assertTrue(permissions.CanDeleteComment(
468 comment, commenter, 111, perms))
469
470 # But not comments that other users deleted.
471 comment.deleted_by = 222
472 self.assertFalse(permissions.CanDeleteComment(
473 comment, commenter, 111, perms))
474
475 def testCanDeleteComment_CannotDeleteSpamComments(self):
476 """Test that nobody can (un)delete comments marked as spam."""
477 comment = tracker_pb2.IssueComment(user_id=111, is_spam=True)
478 commenter = user_pb2.User()
479
480 # Nobody can delete comments marked as spam.
481 self.assertFalse(permissions.CanDeleteComment(
482 comment, commenter, 111,
483 permissions.PermissionSet([permissions.DELETE_OWN])))
484 self.assertFalse(permissions.CanDeleteComment(
485 comment, commenter, 222,
486 permissions.PermissionSet([permissions.DELETE_ANY])))
487
488 # Nobody can undelete comments marked as spam.
489 comment.deleted_by = 222
490 self.assertFalse(permissions.CanDeleteComment(
491 comment, commenter, 111,
492 permissions.PermissionSet([permissions.DELETE_OWN])))
493 self.assertFalse(permissions.CanDeleteComment(
494 comment, commenter, 222,
495 permissions.PermissionSet([permissions.DELETE_ANY])))
496
497 def testCanDeleteComment_CannotDeleteCommentsByBannedUser(self):
498 """Test that nobody can (un)delete comments by banned users."""
499 comment = tracker_pb2.IssueComment(user_id=111)
500 commenter = user_pb2.User(banned='Some reason')
501
502 # Nobody can delete comments by banned users.
503 self.assertFalse(permissions.CanDeleteComment(
504 comment, commenter, 111,
505 permissions.PermissionSet([permissions.DELETE_OWN])))
506 self.assertFalse(permissions.CanDeleteComment(
507 comment, commenter, 222,
508 permissions.PermissionSet([permissions.DELETE_ANY])))
509
510 # Nobody can undelete comments by banned users.
511 comment.deleted_by = 222
512 self.assertFalse(permissions.CanDeleteComment(
513 comment, commenter, 111,
514 permissions.PermissionSet([permissions.DELETE_OWN])))
515 self.assertFalse(permissions.CanDeleteComment(
516 comment, commenter, 222,
517 permissions.PermissionSet([permissions.DELETE_ANY])))
518
519 def testCanFlagComment_FlagSpamCanReport(self):
520 """Test that users with FlagSpam permissions can report comments."""
521 comment = tracker_pb2.IssueComment()
522 commenter = user_pb2.User()
523
524 can_flag, is_flagged = permissions.CanFlagComment(
525 comment, commenter, [], 111,
526 permissions.PermissionSet([permissions.FLAG_SPAM]))
527
528 self.assertTrue(can_flag)
529 self.assertFalse(is_flagged)
530
531 def testCanFlagComment_FlagSpamCanUnReportOwn(self):
532 """Test that users with FlagSpam permission can un-report comments they
533 previously reported."""
534 comment = tracker_pb2.IssueComment()
535 commenter = user_pb2.User()
536
537 can_flag, is_flagged = permissions.CanFlagComment(
538 comment, commenter, [111], 111,
539 permissions.PermissionSet([permissions.FLAG_SPAM]))
540
541 self.assertTrue(can_flag)
542 self.assertTrue(is_flagged)
543
544 def testCanFlagComment_FlagSpamCannotUnReportOthers(self):
545 """Test that users with FlagSpam permission doesn't know if other users have
546 reported a comment as spam."""
547 comment = tracker_pb2.IssueComment()
548 commenter = user_pb2.User()
549
550 can_flag, is_flagged = permissions.CanFlagComment(
551 comment, commenter, [222], 111,
552 permissions.PermissionSet([permissions.FLAG_SPAM]))
553
554 self.assertTrue(can_flag)
555 self.assertFalse(is_flagged)
556
557 def testCanFlagComment_FlagSpamCannotUnFlag(self):
558 comment = tracker_pb2.IssueComment(is_spam=True)
559 commenter = user_pb2.User()
560
561 can_flag, is_flagged = permissions.CanFlagComment(
562 comment, commenter, [111], 111,
563 permissions.PermissionSet([permissions.FLAG_SPAM]))
564
565 self.assertFalse(can_flag)
566 self.assertTrue(is_flagged)
567
568 def testCanFlagComment_VerdictSpamCanFlag(self):
569 """Test that users with FlagSpam permissions can flag comments."""
570 comment = tracker_pb2.IssueComment()
571 commenter = user_pb2.User()
572
573 can_flag, is_flagged = permissions.CanFlagComment(
574 comment, commenter, [], 111,
575 permissions.PermissionSet([permissions.VERDICT_SPAM]))
576
577 self.assertTrue(can_flag)
578 self.assertFalse(is_flagged)
579
580 def testCanFlagComment_VerdictSpamCanUnFlag(self):
581 """Test that users with FlagSpam permissions can un-flag comments."""
582 comment = tracker_pb2.IssueComment(is_spam=True)
583 commenter = user_pb2.User()
584
585 can_flag, is_flagged = permissions.CanFlagComment(
586 comment, commenter, [], 111,
587 permissions.PermissionSet([permissions.VERDICT_SPAM]))
588
589 self.assertTrue(can_flag)
590 self.assertTrue(is_flagged)
591
592 def testCanFlagComment_CannotFlagNoPermission(self):
593 """Test that users without permission cannot flag comments."""
594 comment = tracker_pb2.IssueComment()
595 commenter = user_pb2.User()
596
597 can_flag, is_flagged = permissions.CanFlagComment(
598 comment, commenter, [], 111,
599 permissions.PermissionSet([permissions.DELETE_ANY]))
600
601 self.assertFalse(can_flag)
602 self.assertFalse(is_flagged)
603
604 def testCanFlagComment_CannotUnFlagNoPermission(self):
605 """Test that users without permission cannot un-flag comments."""
606 comment = tracker_pb2.IssueComment(is_spam=True)
607 commenter = user_pb2.User()
608
609 can_flag, is_flagged = permissions.CanFlagComment(
610 comment, commenter, [], 111,
611 # Users need the VerdictSpam permission to be able to un-flag comments.
612 permissions.PermissionSet([
613 permissions.DELETE_ANY, permissions.FLAG_SPAM]))
614
615 self.assertFalse(can_flag)
616 self.assertTrue(is_flagged)
617
618 def testCanFlagComment_CannotFlagCommentByBannedUser(self):
619 """Test that nobady can flag comments by banned users."""
620 comment = tracker_pb2.IssueComment()
621 commenter = user_pb2.User(banned='Some reason')
622
623 can_flag, is_flagged = permissions.CanFlagComment(
624 comment, commenter, [], 111,
625 permissions.PermissionSet([
626 permissions.FLAG_SPAM, permissions.VERDICT_SPAM]))
627
628 self.assertFalse(can_flag)
629 self.assertFalse(is_flagged)
630
631 def testCanFlagComment_CannotUnFlagCommentByBannedUser(self):
632 """Test that nobady can un-flag comments by banned users."""
633 comment = tracker_pb2.IssueComment(is_spam=True)
634 commenter = user_pb2.User(banned='Some reason')
635
636 can_flag, is_flagged = permissions.CanFlagComment(
637 comment, commenter, [], 111,
638 permissions.PermissionSet([
639 permissions.FLAG_SPAM, permissions.VERDICT_SPAM]))
640
641 self.assertFalse(can_flag)
642 self.assertTrue(is_flagged)
643
644 def testCanFlagComment_CanUnFlagDeletedSpamComment(self):
645 """Test that we can un-flag a deleted comment that is spam."""
646 comment = tracker_pb2.IssueComment(is_spam=True, deleted_by=111)
647 commenter = user_pb2.User()
648
649 can_flag, is_flagged = permissions.CanFlagComment(
650 comment, commenter, [], 222,
651 permissions.PermissionSet([permissions.VERDICT_SPAM]))
652
653 self.assertTrue(can_flag)
654 self.assertTrue(is_flagged)
655
656 def testCanFlagComment_CannotFlagDeletedComment(self):
657 """Test that nobody can flag a deleted comment that is not spam."""
658 comment = tracker_pb2.IssueComment(deleted_by=111)
659 commenter = user_pb2.User()
660
661 can_flag, is_flagged = permissions.CanFlagComment(
662 comment, commenter, [], 111,
663 permissions.PermissionSet([
664 permissions.FLAG_SPAM, permissions.VERDICT_SPAM,
665 permissions.DELETE_ANY, permissions.DELETE_OWN]))
666
667 self.assertFalse(can_flag)
668 self.assertFalse(is_flagged)
669
670 def testCanViewComment_Normal(self):
671 """Test that we can view comments."""
672 comment = tracker_pb2.IssueComment()
673 commenter = user_pb2.User()
674 # We assume that CanViewIssue was already called. There are no further
675 # restrictions to view this comment.
676 self.assertTrue(permissions.CanViewComment(
677 comment, commenter, 111, None))
678
679 def testCanViewComment_CannotViewCommentsByBannedUser(self):
680 """Test that nobody can view comments by banned users."""
681 comment = tracker_pb2.IssueComment(user_id=111)
682 commenter = user_pb2.User(banned='Some reason')
683
684 # Nobody can view comments by banned users.
685 self.assertFalse(permissions.CanViewComment(
686 comment, commenter, 111, permissions.ADMIN_PERMISSIONSET))
687
688 def testCanViewComment_OnlyModeratorsCanViewSpamComments(self):
689 """Test that only users with VerdictSpam can view spam comments."""
690 comment = tracker_pb2.IssueComment(user_id=111, is_spam=True)
691 commenter = user_pb2.User()
692
693 # Users with VerdictSpam permission can view comments marked as spam.
694 self.assertTrue(permissions.CanViewComment(
695 comment, commenter, 222,
696 permissions.PermissionSet([permissions.VERDICT_SPAM])))
697
698 # Other users cannot view comments marked as spam, even if it is their own
699 # comment.
700 self.assertFalse(permissions.CanViewComment(
701 comment, commenter, 111,
702 permissions.PermissionSet([
703 permissions.FLAG_SPAM, permissions.DELETE_ANY,
704 permissions.DELETE_OWN])))
705
706 def testCanViewComment_DeletedComment(self):
707 """Test that for deleted comments, only the users that can undelete it can
708 view it.
709 """
710 comment = tracker_pb2.IssueComment(user_id=111, deleted_by=222)
711 commenter = user_pb2.User()
712
713 # Users with DeleteAny permission can view all deleted comments.
714 self.assertTrue(permissions.CanViewComment(
715 comment, commenter, 333,
716 permissions.PermissionSet([permissions.DELETE_ANY])))
717
718 # Users with DeleteOwn permissions can only see their own comments if they
719 # deleted them.
720 comment.user_id = comment.deleted_by = 333
721 self.assertTrue(permissions.CanViewComment(
722 comment, commenter, 333,
723 permissions.PermissionSet([permissions.DELETE_OWN])))
724
725 # But not comments they didn't delete.
726 comment.deleted_by = 111
727 self.assertFalse(permissions.CanViewComment(
728 comment, commenter, 333,
729 permissions.PermissionSet([permissions.DELETE_OWN])))
730
731 def testCanViewInboundMessage(self):
732 comment = tracker_pb2.IssueComment(user_id=111)
733
734 # Users can view their own inbound messages
735 self.assertTrue(permissions.CanViewInboundMessage(
736 comment, 111, permissions.EMPTY_PERMISSIONSET))
737
738 # Users with the ViewInboundMessages permissions can view inbound messages.
739 self.assertTrue(permissions.CanViewInboundMessage(
740 comment, 333,
741 permissions.PermissionSet([permissions.VIEW_INBOUND_MESSAGES])))
742
743 # Other users cannot view inbound messages.
744 self.assertFalse(permissions.CanViewInboundMessage(
745 comment, 333,
746 permissions.PermissionSet([permissions.VIEW])))
747
748 def testCanViewNormalArifact(self):
749 # Anyone can view a non-restricted artifact.
750 self.assertTrue(permissions.CanView(
751 {111}, permissions.READ_ONLY_PERMISSIONSET,
752 self.live_project, []))
753
754 def testCanCreateProject_NoPerms(self):
755 """Signed out users cannot create projects."""
756 self.assertFalse(permissions.CanCreateProject(
757 permissions.EMPTY_PERMISSIONSET))
758
759 self.assertFalse(permissions.CanCreateProject(
760 permissions.READ_ONLY_PERMISSIONSET))
761
762 def testCanCreateProject_Admin(self):
763 """Site admins can create projects."""
764 self.assertTrue(permissions.CanCreateProject(
765 permissions.ADMIN_PERMISSIONSET))
766
767 def testCanCreateProject_RegularUser(self):
768 """Signed in non-admins can create a project if settings allow ANYONE."""
769 try:
770 orig_restriction = settings.project_creation_restriction
771 ANYONE = site_pb2.UserTypeRestriction.ANYONE
772 ADMIN_ONLY = site_pb2.UserTypeRestriction.ADMIN_ONLY
773 NO_ONE = site_pb2.UserTypeRestriction.NO_ONE
774 perms = permissions.PermissionSet([permissions.CREATE_PROJECT])
775
776 settings.project_creation_restriction = ANYONE
777 self.assertTrue(permissions.CanCreateProject(perms))
778
779 settings.project_creation_restriction = ADMIN_ONLY
780 self.assertFalse(permissions.CanCreateProject(perms))
781
782 settings.project_creation_restriction = NO_ONE
783 self.assertFalse(permissions.CanCreateProject(perms))
784 self.assertFalse(permissions.CanCreateProject(
785 permissions.ADMIN_PERMISSIONSET))
786 finally:
787 settings.project_creation_restriction = orig_restriction
788
789 def testCanCreateGroup_AnyoneWithCreateGroup(self):
790 orig_setting = settings.group_creation_restriction
791 try:
792 settings.group_creation_restriction = site_pb2.UserTypeRestriction.ANYONE
793 self.assertTrue(permissions.CanCreateGroup(
794 permissions.PermissionSet([permissions.CREATE_GROUP])))
795 self.assertFalse(permissions.CanCreateGroup(
796 permissions.PermissionSet([])))
797 finally:
798 settings.group_creation_restriction = orig_setting
799
800 def testCanCreateGroup_AdminOnly(self):
801 orig_setting = settings.group_creation_restriction
802 try:
803 ADMIN_ONLY = site_pb2.UserTypeRestriction.ADMIN_ONLY
804 settings.group_creation_restriction = ADMIN_ONLY
805 self.assertTrue(permissions.CanCreateGroup(
806 permissions.PermissionSet([permissions.ADMINISTER_SITE])))
807 self.assertFalse(permissions.CanCreateGroup(
808 permissions.PermissionSet([permissions.CREATE_GROUP])))
809 self.assertFalse(permissions.CanCreateGroup(
810 permissions.PermissionSet([])))
811 finally:
812 settings.group_creation_restriction = orig_setting
813
814 def testCanCreateGroup_UnspecifiedSetting(self):
815 orig_setting = settings.group_creation_restriction
816 try:
817 settings.group_creation_restriction = None
818 self.assertFalse(permissions.CanCreateGroup(
819 permissions.PermissionSet([permissions.ADMINISTER_SITE])))
820 self.assertFalse(permissions.CanCreateGroup(
821 permissions.PermissionSet([permissions.CREATE_GROUP])))
822 self.assertFalse(permissions.CanCreateGroup(
823 permissions.PermissionSet([])))
824 finally:
825 settings.group_creation_restriction = orig_setting
826
827 def testCanEditGroup_HasPerm(self):
828 self.assertTrue(permissions.CanEditGroup(
829 permissions.PermissionSet([permissions.EDIT_GROUP]), None, None))
830
831 def testCanEditGroup_IsOwner(self):
832 self.assertTrue(permissions.CanEditGroup(
833 permissions.PermissionSet([]), {111}, {111}))
834
835 def testCanEditGroup_Otherwise(self):
836 self.assertFalse(permissions.CanEditGroup(
837 permissions.PermissionSet([]), {111}, {222}))
838
839 def testCanViewGroupMembers_HasPerm(self):
840 self.assertTrue(permissions.CanViewGroupMembers(
841 permissions.PermissionSet([permissions.VIEW_GROUP]),
842 None, None, None, None, None))
843
844 def testCanViewGroupMembers_IsMemberOfFriendProject(self):
845 group_settings = usergroup_pb2.MakeSettings('owners', friend_projects=[890])
846 self.assertFalse(permissions.CanViewGroupMembers(
847 permissions.PermissionSet([]),
848 {111}, group_settings, {222}, {333}, {789}))
849 self.assertTrue(permissions.CanViewGroupMembers(
850 permissions.PermissionSet([]),
851 {111}, group_settings, {222}, {333}, {789, 890}))
852
853 def testCanViewGroupMembers_VisibleToOwner(self):
854 group_settings = usergroup_pb2.MakeSettings('owners')
855 self.assertFalse(permissions.CanViewGroupMembers(
856 permissions.PermissionSet([]),
857 {111}, group_settings, {222}, {333}, {789}))
858 self.assertFalse(permissions.CanViewGroupMembers(
859 permissions.PermissionSet([]),
860 {222}, group_settings, {222}, {333}, {789}))
861 self.assertTrue(permissions.CanViewGroupMembers(
862 permissions.PermissionSet([]),
863 {333}, group_settings, {222}, {333}, {789}))
864
865 def testCanViewGroupMembers_IsVisibleToMember(self):
866 group_settings = usergroup_pb2.MakeSettings('members')
867 self.assertFalse(permissions.CanViewGroupMembers(
868 permissions.PermissionSet([]),
869 {111}, group_settings, {222}, {333}, {789}))
870 self.assertTrue(permissions.CanViewGroupMembers(
871 permissions.PermissionSet([]),
872 {222}, group_settings, {222}, {333}, {789}))
873 self.assertTrue(permissions.CanViewGroupMembers(
874 permissions.PermissionSet([]),
875 {333}, group_settings, {222}, {333}, {789}))
876
877 def testCanViewGroupMembers_AnyoneCanView(self):
878 group_settings = usergroup_pb2.MakeSettings('anyone')
879 self.assertTrue(permissions.CanViewGroupMembers(
880 permissions.PermissionSet([]),
881 {111}, group_settings, {222}, {333}, {789}))
882
883 def testIsBanned_AnonUser(self):
884 user_view = framework_views.StuffUserView(None, None, True)
885 self.assertFalse(permissions.IsBanned(None, user_view))
886
887 def testIsBanned_NormalUser(self):
888 user = user_pb2.User()
889 user_view = framework_views.StuffUserView(None, None, True)
890 self.assertFalse(permissions.IsBanned(user, user_view))
891
892 def testIsBanned_BannedUser(self):
893 user = user_pb2.User()
894 user.banned = 'spammer'
895 user_view = framework_views.StuffUserView(None, None, True)
896 self.assertTrue(permissions.IsBanned(user, user_view))
897
898 def testIsBanned_BadDomainUser(self):
899 user = user_pb2.User()
900 self.assertFalse(permissions.IsBanned(user, None))
901
902 user_view = framework_views.StuffUserView(None, None, True)
903 user_view.domain = 'spammer.com'
904 self.assertFalse(permissions.IsBanned(user, user_view))
905
906 orig_banned_user_domains = settings.banned_user_domains
907 settings.banned_user_domains = ['spammer.com', 'phisher.com']
908 self.assertTrue(permissions.IsBanned(user, user_view))
909 settings.banned_user_domains = orig_banned_user_domains
910
911 def testIsBanned_PlusAddressUser(self):
912 """We don't allow users who have + in their email address."""
913 user = user_pb2.User(email='user@example.com')
914 self.assertFalse(permissions.IsBanned(user, None))
915
916 user.email = 'user+shadystuff@example.com'
917 self.assertTrue(permissions.IsBanned(user, None))
918
919 def testCanExpungeUser_Admin(self):
920 mr = testing_helpers.MakeMonorailRequest()
921 mr.perms = permissions.ADMIN_PERMISSIONSET
922 self.assertTrue(permissions.CanExpungeUsers(mr))
923
924 def testGetCustomPermissions(self):
925 project = project_pb2.Project()
926 self.assertListEqual([], permissions.GetCustomPermissions(project))
927
928 project.extra_perms.append(project_pb2.Project.ExtraPerms(
929 perms=['Core', 'Elite', 'Gold']))
930 self.assertListEqual(['Core', 'Elite', 'Gold'],
931 permissions.GetCustomPermissions(project))
932
933 project.extra_perms.append(project_pb2.Project.ExtraPerms(
934 perms=['Silver', 'Gold', 'Bronze']))
935 self.assertListEqual(['Bronze', 'Core', 'Elite', 'Gold', 'Silver'],
936 permissions.GetCustomPermissions(project))
937
938 # View is not returned because it is a starndard permission.
939 project.extra_perms.append(project_pb2.Project.ExtraPerms(
940 perms=['Bronze', permissions.VIEW]))
941 self.assertListEqual(['Bronze', 'Core', 'Elite', 'Gold', 'Silver'],
942 permissions.GetCustomPermissions(project))
943
944 def testUserCanViewProject(self):
945 self.mox.StubOutWithMock(time, 'time')
946 for _ in range(8):
947 time.time().AndReturn(self.NOW)
948 self.mox.ReplayAll()
949
950 self.assertTrue(permissions.UserCanViewProject(
951 self.member, {self.COMMITTER_USER_ID}, self.live_project))
952 self.assertTrue(permissions.UserCanViewProject(
953 None, None, self.live_project))
954
955 self.archived_project.delete_time = self.NOW + 1
956 self.assertFalse(permissions.UserCanViewProject(
957 None, None, self.archived_project))
958 self.assertTrue(permissions.UserCanViewProject(
959 self.owner, {self.OWNER_USER_ID}, self.archived_project))
960 self.assertTrue(permissions.UserCanViewProject(
961 self.site_admin, {self.SITE_ADMIN_USER_ID},
962 self.archived_project))
963
964 self.archived_project.delete_time = self.NOW - 1
965 self.assertFalse(permissions.UserCanViewProject(
966 None, None, self.archived_project))
967 self.assertFalse(permissions.UserCanViewProject(
968 self.owner, {self.OWNER_USER_ID}, self.archived_project))
969 self.assertTrue(permissions.UserCanViewProject(
970 self.site_admin, {self.SITE_ADMIN_USER_ID},
971 self.archived_project))
972
973 self.mox.VerifyAll()
974
975 def CheckExpired(self, state, expected_to_be_reapable):
976 proj = project_pb2.Project()
977 proj.state = state
978 proj.delete_time = self.NOW + 1
979 self.assertFalse(permissions.IsExpired(proj))
980
981 proj.delete_time = self.NOW - 1
982 self.assertEqual(expected_to_be_reapable, permissions.IsExpired(proj))
983
984 proj.delete_time = self.NOW - 1
985 self.assertFalse(permissions.IsExpired(proj, expired_before=self.NOW - 2))
986
987 def testIsExpired_Live(self):
988 self.CheckExpired(project_pb2.ProjectState.LIVE, False)
989
990 def testIsExpired_Archived(self):
991 self.mox.StubOutWithMock(time, 'time')
992 for _ in range(2):
993 time.time().AndReturn(self.NOW)
994 self.mox.ReplayAll()
995
996 self.CheckExpired(project_pb2.ProjectState.ARCHIVED, True)
997
998 self.mox.VerifyAll()
999
1000
1001class PermissionsCheckTest(unittest.TestCase):
1002
1003 def setUp(self):
1004 self.perms = permissions.PermissionSet(['a', 'b', 'c'])
1005
1006 self.proj = project_pb2.Project()
1007 self.proj.committer_ids.append(111)
1008 self.proj.extra_perms.append(project_pb2.Project.ExtraPerms(
1009 member_id=111, perms=['d']))
1010
1011 # Note: z is an example of a perm that the user does not have.
1012 # Note: q is an example of an irrelevant perm that the user does not have.
1013
1014 def DoCanUsePerm(self, perm, project='default', user_id=None, restrict=''):
1015 """Wrapper function to call CanUsePerm()."""
1016 if project == 'default':
1017 project = self.proj
1018 return self.perms.CanUsePerm(
1019 perm, {user_id or 111}, project, restrict.split())
1020
1021 def testHasPermNoRestrictions(self):
1022 self.assertTrue(self.DoCanUsePerm('a'))
1023 self.assertTrue(self.DoCanUsePerm('A'))
1024 self.assertFalse(self.DoCanUsePerm('z'))
1025 self.assertTrue(self.DoCanUsePerm('d'))
1026 self.assertFalse(self.DoCanUsePerm('d', user_id=222))
1027 self.assertFalse(self.DoCanUsePerm('d', project=project_pb2.Project()))
1028
1029 def testHasPermOperationRestrictions(self):
1030 self.assertTrue(self.DoCanUsePerm('a', restrict='Restrict-a-b'))
1031 self.assertTrue(self.DoCanUsePerm('a', restrict='Restrict-b-z'))
1032 self.assertTrue(self.DoCanUsePerm('a', restrict='Restrict-a-d'))
1033 self.assertTrue(self.DoCanUsePerm('d', restrict='Restrict-d-a'))
1034 self.assertTrue(self.DoCanUsePerm(
1035 'd', restrict='Restrict-q-z Restrict-q-d Restrict-d-a'))
1036
1037 self.assertFalse(self.DoCanUsePerm('a', restrict='Restrict-a-z'))
1038 self.assertFalse(self.DoCanUsePerm('d', restrict='Restrict-d-z'))
1039 self.assertFalse(self.DoCanUsePerm(
1040 'd', restrict='Restrict-d-a Restrict-d-z'))
1041
1042 def testHasPermOutsideProjectScope(self):
1043 self.assertTrue(self.DoCanUsePerm('a', project=None))
1044 self.assertTrue(self.DoCanUsePerm(
1045 'a', project=None, restrict='Restrict-a-c'))
1046 self.assertTrue(self.DoCanUsePerm(
1047 'a', project=None, restrict='Restrict-q-z'))
1048
1049 self.assertFalse(self.DoCanUsePerm('z', project=None))
1050 self.assertFalse(self.DoCanUsePerm(
1051 'a', project=None, restrict='Restrict-a-d'))
1052
1053
1054class CanViewProjectContributorListTest(unittest.TestCase):
1055
1056 def testCanViewProjectContributorList_NoProject(self):
1057 mr = testing_helpers.MakeMonorailRequest(path='/')
1058 self.assertFalse(permissions.CanViewContributorList(mr, mr.project))
1059
1060 def testCanViewProjectContributorList_NormalProject(self):
1061 project = project_pb2.Project()
1062 mr = testing_helpers.MakeMonorailRequest(
1063 path='/p/proj/', project=project)
1064 self.assertTrue(permissions.CanViewContributorList(mr, mr.project))
1065
1066 def testCanViewProjectContributorList_ProjectWithOptionSet(self):
1067 project = project_pb2.Project()
1068 project.only_owners_see_contributors = True
1069
1070 for perms in [permissions.READ_ONLY_PERMISSIONSET,
1071 permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET,
1072 permissions.CONTRIBUTOR_INACTIVE_PERMISSIONSET]:
1073 mr = testing_helpers.MakeMonorailRequest(
1074 path='/p/proj/', project=project, perms=perms)
1075 self.assertFalse(permissions.CanViewContributorList(mr, mr.project))
1076
1077 for perms in [permissions.COMMITTER_ACTIVE_PERMISSIONSET,
1078 permissions.COMMITTER_INACTIVE_PERMISSIONSET,
1079 permissions.OWNER_ACTIVE_PERMISSIONSET,
1080 permissions.OWNER_INACTIVE_PERMISSIONSET,
1081 permissions.ADMIN_PERMISSIONSET]:
1082 mr = testing_helpers.MakeMonorailRequest(
1083 path='/p/proj/', project=project, perms=perms)
1084 self.assertTrue(permissions.CanViewContributorList(mr, mr.project))
1085
1086
1087class ShouldCheckForAbandonmentTest(unittest.TestCase):
1088
1089 def setUp(self):
1090 self.mr = testing_helpers.Blank(
1091 project=project_pb2.Project(),
1092 auth=authdata.AuthData())
1093
1094 def testOwner(self):
1095 self.mr.auth.effective_ids = {111}
1096 self.mr.perms = permissions.OWNER_ACTIVE_PERMISSIONSET
1097 self.assertTrue(permissions.ShouldCheckForAbandonment(self.mr))
1098
1099 def testNonOwner(self):
1100 self.mr.auth.effective_ids = {222}
1101 self.mr.perms = permissions.COMMITTER_ACTIVE_PERMISSIONSET
1102 self.assertFalse(permissions.ShouldCheckForAbandonment(self.mr))
1103 self.mr.perms = permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET
1104 self.assertFalse(permissions.ShouldCheckForAbandonment(self.mr))
1105 self.mr.perms = permissions.USER_PERMISSIONSET
1106 self.assertFalse(permissions.ShouldCheckForAbandonment(self.mr))
1107 self.mr.perms = permissions.EMPTY_PERMISSIONSET
1108 self.assertFalse(permissions.ShouldCheckForAbandonment(self.mr))
1109
1110 def testSiteAdmin(self):
1111 self.mr.auth.effective_ids = {111}
1112 self.mr.perms = permissions.ADMIN_PERMISSIONSET
1113 self.assertFalse(permissions.ShouldCheckForAbandonment(self.mr))
1114
1115
1116class RestrictionLabelsTest(unittest.TestCase):
1117
1118 ORIG_SUMMARY = 'this is the orginal summary'
1119 ORIG_LABELS = ['one', 'two']
1120
1121 def testIsRestrictLabel(self):
1122 self.assertFalse(permissions.IsRestrictLabel('Usability'))
1123 self.assertTrue(permissions.IsRestrictLabel('Restrict-View-CoreTeam'))
1124 # Doing it again will test the cached results.
1125 self.assertFalse(permissions.IsRestrictLabel('Usability'))
1126 self.assertTrue(permissions.IsRestrictLabel('Restrict-View-CoreTeam'))
1127
1128 self.assertFalse(permissions.IsRestrictLabel('Usability', perm='View'))
1129 self.assertTrue(permissions.IsRestrictLabel(
1130 'Restrict-View-CoreTeam', perm='View'))
1131
1132 # This one is a restriction label, but not the kind that we want.
1133 self.assertFalse(permissions.IsRestrictLabel(
1134 'Restrict-View-CoreTeam', perm='Delete'))
1135
1136 def testGetRestrictions_NoIssue(self):
1137 self.assertEqual([], permissions.GetRestrictions(None))
1138
1139 def testGetRestrictions_PermSpecified(self):
1140 """We can return restiction labels related to the given perm."""
1141 art = fake.MakeTestIssue(
1142 789, 1, self.ORIG_SUMMARY, 'New', 0, labels=self.ORIG_LABELS)
1143 self.assertEqual([], permissions.GetRestrictions(art, perm='view'))
1144
1145 art = fake.MakeTestIssue(
1146 789, 1, self.ORIG_SUMMARY, 'New', 0,
1147 labels=['Restrict-View-Core', 'Hot',
1148 'Restrict-EditIssue-Commit', 'Restrict-EditIssue-Core'])
1149 self.assertEqual(
1150 ['restrict-view-core'],
1151 permissions.GetRestrictions(art, perm='view'))
1152 self.assertEqual(
1153 ['restrict-view-core'],
1154 permissions.GetRestrictions(art, perm='View'))
1155 self.assertEqual(
1156 ['restrict-editissue-commit', 'restrict-editissue-core'],
1157 permissions.GetRestrictions(art, perm='EditIssue'))
1158
1159 def testGetRestrictions_NoPerm(self):
1160 art = fake.MakeTestIssue(
1161 789, 1, self.ORIG_SUMMARY, 'New', 0, labels=self.ORIG_LABELS)
1162 self.assertEqual([], permissions.GetRestrictions(art))
1163
1164 art = fake.MakeTestIssue(
1165 789, 1, self.ORIG_SUMMARY, 'New', 0,
1166 labels=['Restrict-MissingThirdPart', 'Hot'])
1167 self.assertEqual([], permissions.GetRestrictions(art))
1168
1169 art = fake.MakeTestIssue(
1170 789, 1, self.ORIG_SUMMARY, 'New', 0,
1171 labels=['Restrict-View-Core', 'Hot'])
1172 self.assertEqual(['restrict-view-core'], permissions.GetRestrictions(art))
1173
1174 art = fake.MakeTestIssue(
1175 789, 1, self.ORIG_SUMMARY, 'New', 0,
1176 labels=['Restrict-View-Core', 'Hot'],
1177 derived_labels=['Color-Red', 'Restrict-EditIssue-GoldMembers'])
1178 self.assertEqual(
1179 ['restrict-view-core', 'restrict-editissue-goldmembers'],
1180 permissions.GetRestrictions(art))
1181
1182 art = fake.MakeTestIssue(
1183 789, 1, self.ORIG_SUMMARY, 'New', 0,
1184 labels=['restrict-view-core', 'hot'],
1185 derived_labels=['Color-Red', 'RESTRICT-EDITISSUE-GOLDMEMBERS'])
1186 self.assertEqual(
1187 ['restrict-view-core', 'restrict-editissue-goldmembers'],
1188 permissions.GetRestrictions(art))
1189
1190
1191REPORTER_ID = 111
1192OWNER_ID = 222
1193CC_ID = 333
1194OTHER_ID = 444
1195APPROVER_ID = 555
1196
1197
1198class IssuePermissionsTest(unittest.TestCase):
1199
1200 REGULAR_ISSUE = tracker_pb2.Issue()
1201 REGULAR_ISSUE.reporter_id = REPORTER_ID
1202
1203 DELETED_ISSUE = tracker_pb2.Issue()
1204 DELETED_ISSUE.deleted = True
1205 DELETED_ISSUE.reporter_id = REPORTER_ID
1206
1207 RESTRICTED_ISSUE = tracker_pb2.Issue()
1208 RESTRICTED_ISSUE.reporter_id = REPORTER_ID
1209 RESTRICTED_ISSUE.owner_id = OWNER_ID
1210 RESTRICTED_ISSUE.cc_ids.append(CC_ID)
1211 RESTRICTED_ISSUE.approval_values.append(
1212 tracker_pb2.ApprovalValue(approver_ids=[APPROVER_ID])
1213 )
1214 RESTRICTED_ISSUE.labels.append('Restrict-View-Commit')
1215
1216 RESTRICTED_ISSUE2 = tracker_pb2.Issue()
1217 RESTRICTED_ISSUE2.reporter_id = REPORTER_ID
1218 # RESTRICTED_ISSUE2 has no owner
1219 RESTRICTED_ISSUE2.cc_ids.append(CC_ID)
1220 RESTRICTED_ISSUE2.labels.append('Restrict-View-Commit')
1221
1222 RESTRICTED_ISSUE3 = tracker_pb2.Issue()
1223 RESTRICTED_ISSUE3.reporter_id = REPORTER_ID
1224 RESTRICTED_ISSUE3.owner_id = OWNER_ID
1225 # Restrict to a permission that no one has.
1226 RESTRICTED_ISSUE3.labels.append('Restrict-EditIssue-Foo')
1227
1228 PROJECT = project_pb2.Project()
1229
1230 ADMIN_PERMS = permissions.ADMIN_PERMISSIONSET
1231 PERMS = permissions.EMPTY_PERMISSIONSET
1232
1233 def testUpdateIssuePermissions_Normal(self):
1234 perms = permissions.UpdateIssuePermissions(
1235 permissions.COMMITTER_ACTIVE_PERMISSIONSET, self.PROJECT,
1236 self.REGULAR_ISSUE, {})
1237
1238 self.assertEqual(
1239 ['addissuecomment',
1240 'commit',
1241 'createissue',
1242 'deleteown',
1243 'editissue',
1244 'flagspam',
1245 'setstar',
1246 'verdictspam',
1247 'view',
1248 'viewcontributorlist',
1249 'viewinboundmessages',
1250 'viewquota'],
1251 sorted(perms.perm_names))
1252
1253 def testUpdateIssuePermissions_FromConfig(self):
1254 config = tracker_pb2.ProjectIssueConfig(
1255 field_defs=[tracker_pb2.FieldDef(field_id=123, grants_perm='Granted')])
1256 issue = tracker_pb2.Issue(
1257 field_values=[tracker_pb2.FieldValue(field_id=123, user_id=111)])
1258 perms = permissions.UpdateIssuePermissions(
1259 permissions.USER_PERMISSIONSET, self.PROJECT, issue, {111},
1260 config=config)
1261 self.assertIn('granted', perms.perm_names)
1262
1263 def testUpdateIssuePermissions_ExtraPerms(self):
1264 project = project_pb2.Project()
1265 project.committer_ids.append(999)
1266 project.extra_perms.append(
1267 project_pb2.Project.ExtraPerms(member_id=999, perms=['EditIssue']))
1268 perms = permissions.UpdateIssuePermissions(
1269 permissions.USER_PERMISSIONSET, project,
1270 self.REGULAR_ISSUE, {999})
1271 self.assertIn('editissue', perms.perm_names)
1272
1273 def testUpdateIssuePermissions_ExtraPermsAreSubjectToRestrictions(self):
1274 project = project_pb2.Project()
1275 project.committer_ids.append(999)
1276 project.extra_perms.append(
1277 project_pb2.Project.ExtraPerms(member_id=999, perms=['EditIssue']))
1278 perms = permissions.UpdateIssuePermissions(
1279 permissions.USER_PERMISSIONSET, project,
1280 self.RESTRICTED_ISSUE3, {999})
1281 self.assertNotIn('editissue', perms.perm_names)
1282
1283 def testUpdateIssuePermissions_GrantedPermsAreNotSubjectToRestrictions(self):
1284 perms = permissions.UpdateIssuePermissions(
1285 permissions.USER_PERMISSIONSET, self.PROJECT, self.RESTRICTED_ISSUE3,
1286 {}, granted_perms=['EditIssue'])
1287 self.assertIn('editissue', perms.perm_names)
1288
1289 def testUpdateIssuePermissions_RespectConsiderRestrictions(self):
1290 perms = permissions.UpdateIssuePermissions(
1291 permissions.ADMIN_PERMISSIONSET, self.PROJECT, self.RESTRICTED_ISSUE3,
1292 {})
1293 self.assertIn('editissue', perms.perm_names)
1294
1295 def testUpdateIssuePermissions_RestrictionsAreConsideredIndividually(self):
1296 issue = tracker_pb2.Issue(
1297 labels=[
1298 'Restrict-Perm1-Perm2',
1299 'Restrict-Perm2-Perm3'])
1300 perms = permissions.UpdateIssuePermissions(
1301 permissions.PermissionSet(['Perm1', 'Perm2', 'View']),
1302 self.PROJECT, issue, {})
1303 self.assertIn('perm1', perms.perm_names)
1304 self.assertNotIn('perm2', perms.perm_names)
1305
1306 def testUpdateIssuePermissions_DeletedNoPermissions(self):
1307 issue = tracker_pb2.Issue(
1308 labels=['Restrict-View-Foo'],
1309 deleted=True)
1310 perms = permissions.UpdateIssuePermissions(
1311 permissions.COMMITTER_ACTIVE_PERMISSIONSET, self.PROJECT, issue, {})
1312 self.assertEqual([], sorted(perms.perm_names))
1313
1314 def testUpdateIssuePermissions_ViewDeleted(self):
1315 perms = permissions.UpdateIssuePermissions(
1316 permissions.COMMITTER_ACTIVE_PERMISSIONSET, self.PROJECT,
1317 self.DELETED_ISSUE, {})
1318 self.assertEqual(['view'], sorted(perms.perm_names))
1319
1320 def testUpdateIssuePermissions_ViewAndDeleteDeleted(self):
1321 perms = permissions.UpdateIssuePermissions(
1322 permissions.OWNER_ACTIVE_PERMISSIONSET, self.PROJECT,
1323 self.DELETED_ISSUE, {})
1324 self.assertEqual(['deleteissue', 'view'], sorted(perms.perm_names))
1325
1326 def testUpdateIssuePermissions_ViewRestrictions(self):
1327 perms = permissions.UpdateIssuePermissions(
1328 permissions.USER_PERMISSIONSET, self.PROJECT, self.RESTRICTED_ISSUE, {})
1329 self.assertNotIn('view', perms.perm_names)
1330
1331 def testUpdateIssuePermissions_RolesBypassViewRestrictions(self):
1332 for role in {OWNER_ID, REPORTER_ID, CC_ID, APPROVER_ID}:
1333 perms = permissions.UpdateIssuePermissions(
1334 permissions.USER_PERMISSIONSET, self.PROJECT, self.RESTRICTED_ISSUE,
1335 {role})
1336 self.assertIn('view', perms.perm_names)
1337
1338 def testUpdateIssuePermissions_RolesAllowViewingDeleted(self):
1339 issue = tracker_pb2.Issue(
1340 reporter_id=REPORTER_ID,
1341 owner_id=OWNER_ID,
1342 cc_ids=[CC_ID],
1343 approval_values=[tracker_pb2.ApprovalValue(approver_ids=[APPROVER_ID])],
1344 labels=['Restrict-View-Foo'],
1345 deleted=True)
1346 for role in {OWNER_ID, REPORTER_ID, CC_ID, APPROVER_ID}:
1347 perms = permissions.UpdateIssuePermissions(
1348 permissions.USER_PERMISSIONSET, self.PROJECT, issue, {role})
1349 self.assertIn('view', perms.perm_names)
1350
1351 def testUpdateIssuePermissions_GrantedViewPermission(self):
1352 perms = permissions.UpdateIssuePermissions(
1353 permissions.USER_PERMISSIONSET, self.PROJECT, self.RESTRICTED_ISSUE,
1354 {}, ['commit'])
1355 self.assertIn('view', perms.perm_names)
1356
1357 def testUpdateIssuePermissions_EditRestrictions(self):
1358 perms = permissions.UpdateIssuePermissions(
1359 permissions.COMMITTER_ACTIVE_PERMISSIONSET, self.PROJECT,
1360 self.RESTRICTED_ISSUE3, {REPORTER_ID, CC_ID, APPROVER_ID})
1361 self.assertNotIn('editissue', perms.perm_names)
1362
1363 def testUpdateIssuePermissions_OwnerBypassEditRestrictions(self):
1364 perms = permissions.UpdateIssuePermissions(
1365 permissions.COMMITTER_ACTIVE_PERMISSIONSET, self.PROJECT,
1366 self.RESTRICTED_ISSUE3, {OWNER_ID})
1367 self.assertIn('editissue', perms.perm_names)
1368
1369 def testUpdateIssuePermissions_CustomPermissionGrantsEditPermission(self):
1370 project = project_pb2.Project()
1371 project.committer_ids.append(999)
1372 project.extra_perms.append(
1373 project_pb2.Project.ExtraPerms(member_id=999, perms=['Foo']))
1374 perms = permissions.UpdateIssuePermissions(
1375 permissions.COMMITTER_ACTIVE_PERMISSIONSET, project,
1376 self.RESTRICTED_ISSUE3, {999})
1377 self.assertIn('editissue', perms.perm_names)
1378
1379 def testCanViewIssue_Deleted(self):
1380 self.assertFalse(permissions.CanViewIssue(
1381 {REPORTER_ID}, permissions.OWNER_ACTIVE_PERMISSIONSET,
1382 self.PROJECT, self.DELETED_ISSUE))
1383 self.assertTrue(permissions.CanViewIssue(
1384 {REPORTER_ID}, permissions.OWNER_ACTIVE_PERMISSIONSET,
1385 self.PROJECT, self.DELETED_ISSUE, allow_viewing_deleted=True))
1386 self.assertTrue(permissions.CanViewIssue(
1387 {REPORTER_ID}, permissions.OWNER_ACTIVE_PERMISSIONSET,
1388 self.PROJECT, self.REGULAR_ISSUE))
1389
1390 def testCanViewIssue_Regular(self):
1391 self.assertTrue(permissions.CanViewIssue(
1392 {REPORTER_ID}, permissions.OWNER_ACTIVE_PERMISSIONSET,
1393 self.PROJECT, self.REGULAR_ISSUE))
1394 self.assertTrue(permissions.CanViewIssue(
1395 {REPORTER_ID}, permissions.COMMITTER_ACTIVE_PERMISSIONSET,
1396 self.PROJECT, self.REGULAR_ISSUE))
1397 self.assertTrue(permissions.CanViewIssue(
1398 {REPORTER_ID},
1399 permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET,
1400 self.PROJECT, self.REGULAR_ISSUE))
1401 self.assertTrue(permissions.CanViewIssue(
1402 {REPORTER_ID}, permissions.USER_PERMISSIONSET,
1403 self.PROJECT, self.REGULAR_ISSUE))
1404 self.assertTrue(permissions.CanViewIssue(
1405 {REPORTER_ID}, permissions.READ_ONLY_PERMISSIONSET,
1406 self.PROJECT, self.REGULAR_ISSUE))
1407 self.assertTrue(permissions.CanViewIssue(
1408 set(), permissions.READ_ONLY_PERMISSIONSET,
1409 self.PROJECT, self.REGULAR_ISSUE))
1410
1411 def testCanViewIssue_Restricted(self):
1412 # Project owner can always view issue.
1413 self.assertTrue(permissions.CanViewIssue(
1414 {OTHER_ID}, permissions.OWNER_ACTIVE_PERMISSIONSET,
1415 self.PROJECT, self.RESTRICTED_ISSUE))
1416 # Member can view because they have Commit perm.
1417 self.assertTrue(permissions.CanViewIssue(
1418 {OTHER_ID}, permissions.COMMITTER_ACTIVE_PERMISSIONSET,
1419 self.PROJECT, self.RESTRICTED_ISSUE))
1420 # Contributors normally do not have Commit perm.
1421 self.assertFalse(permissions.CanViewIssue(
1422 {OTHER_ID}, permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET,
1423 self.PROJECT, self.RESTRICTED_ISSUE))
1424 # Non-members do not have Commit perm.
1425 self.assertFalse(permissions.CanViewIssue(
1426 {OTHER_ID}, permissions.USER_PERMISSIONSET,
1427 self.PROJECT, self.RESTRICTED_ISSUE))
1428 # Anon user's do not have Commit perm.
1429 self.assertFalse(permissions.CanViewIssue(
1430 set(), permissions.READ_ONLY_PERMISSIONSET,
1431 self.PROJECT, self.RESTRICTED_ISSUE))
1432
1433 def testCanViewIssue_RestrictedParticipants(self):
1434 # Reporter can always view issue
1435 self.assertTrue(permissions.CanViewIssue(
1436 {REPORTER_ID}, permissions.READ_ONLY_PERMISSIONSET,
1437 self.PROJECT, self.RESTRICTED_ISSUE))
1438 # Issue owner can always view issue
1439 self.assertTrue(permissions.CanViewIssue(
1440 {OWNER_ID}, permissions.READ_ONLY_PERMISSIONSET,
1441 self.PROJECT, self.RESTRICTED_ISSUE))
1442 # CC'd user can always view issue
1443 self.assertTrue(permissions.CanViewIssue(
1444 {CC_ID}, permissions.READ_ONLY_PERMISSIONSET,
1445 self.PROJECT, self.RESTRICTED_ISSUE))
1446 # Non-participants cannot view issue if they don't have the needed perm.
1447 self.assertFalse(permissions.CanViewIssue(
1448 {OTHER_ID}, permissions.READ_ONLY_PERMISSIONSET,
1449 self.PROJECT, self.RESTRICTED_ISSUE))
1450 # Anon user's do not have Commit perm.
1451 self.assertFalse(permissions.CanViewIssue(
1452 set(), permissions.READ_ONLY_PERMISSIONSET,
1453 self.PROJECT, self.RESTRICTED_ISSUE))
1454 # Anon user's cannot match owner 0.
1455 self.assertFalse(permissions.CanViewIssue(
1456 set(), permissions.READ_ONLY_PERMISSIONSET,
1457 self.PROJECT, self.RESTRICTED_ISSUE2))
1458 # Approvers can always view issue
1459 self.assertTrue(permissions.CanViewIssue(
1460 {APPROVER_ID}, permissions.READ_ONLY_PERMISSIONSET,
1461 self.PROJECT, self.RESTRICTED_ISSUE))
1462
1463 def testCannotViewIssueIfCannotViewProject(self):
1464 """Cross-project search should not be a backdoor to viewing issues."""
1465 # Reporter cannot view issue if they not long have access to the project.
1466 self.assertFalse(permissions.CanViewIssue(
1467 {REPORTER_ID}, permissions.EMPTY_PERMISSIONSET,
1468 self.PROJECT, self.REGULAR_ISSUE))
1469 # Issue owner cannot always view issue
1470 self.assertFalse(permissions.CanViewIssue(
1471 {OWNER_ID}, permissions.EMPTY_PERMISSIONSET,
1472 self.PROJECT, self.REGULAR_ISSUE))
1473 # CC'd user cannot always view issue
1474 self.assertFalse(permissions.CanViewIssue(
1475 {CC_ID}, permissions.EMPTY_PERMISSIONSET,
1476 self.PROJECT, self.REGULAR_ISSUE))
1477 # Non-participants cannot view issue if they don't have the needed perm.
1478 self.assertFalse(permissions.CanViewIssue(
1479 {OTHER_ID}, permissions.EMPTY_PERMISSIONSET,
1480 self.PROJECT, self.REGULAR_ISSUE))
1481 # Anon user's do not have Commit perm.
1482 self.assertFalse(permissions.CanViewIssue(
1483 set(), permissions.EMPTY_PERMISSIONSET, self.PROJECT,
1484 self.REGULAR_ISSUE))
1485 # Anon user's cannot match owner 0.
1486 self.assertFalse(permissions.CanViewIssue(
1487 set(), permissions.EMPTY_PERMISSIONSET, self.PROJECT,
1488 self.REGULAR_ISSUE))
1489
1490 def testCanEditIssue(self):
1491 # Anon users cannot edit issues.
1492 self.assertFalse(permissions.CanEditIssue(
1493 {}, permissions.READ_ONLY_PERMISSIONSET,
1494 self.PROJECT, self.REGULAR_ISSUE))
1495
1496 # Non-members and contributors cannot edit issues,
1497 # even if they reported them.
1498 self.assertFalse(permissions.CanEditIssue(
1499 {REPORTER_ID}, permissions.READ_ONLY_PERMISSIONSET,
1500 self.PROJECT, self.REGULAR_ISSUE))
1501 self.assertFalse(permissions.CanEditIssue(
1502 {REPORTER_ID}, permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET,
1503 self.PROJECT, self.REGULAR_ISSUE))
1504
1505 # Project committers and project owners can edit issues, regardless
1506 # of their role in the issue.
1507 self.assertTrue(permissions.CanEditIssue(
1508 {REPORTER_ID}, permissions.COMMITTER_ACTIVE_PERMISSIONSET,
1509 self.PROJECT, self.REGULAR_ISSUE))
1510 self.assertTrue(permissions.CanEditIssue(
1511 {REPORTER_ID}, permissions.OWNER_ACTIVE_PERMISSIONSET,
1512 self.PROJECT, self.REGULAR_ISSUE))
1513 self.assertTrue(permissions.CanEditIssue(
1514 {OWNER_ID}, permissions.COMMITTER_ACTIVE_PERMISSIONSET,
1515 self.PROJECT, self.REGULAR_ISSUE))
1516 self.assertTrue(permissions.CanEditIssue(
1517 {OWNER_ID}, permissions.OWNER_ACTIVE_PERMISSIONSET,
1518 self.PROJECT, self.REGULAR_ISSUE))
1519 self.assertTrue(permissions.CanEditIssue(
1520 {OTHER_ID}, permissions.COMMITTER_ACTIVE_PERMISSIONSET,
1521 self.PROJECT, self.REGULAR_ISSUE))
1522 self.assertTrue(permissions.CanEditIssue(
1523 {OTHER_ID}, permissions.OWNER_ACTIVE_PERMISSIONSET,
1524 self.PROJECT, self.REGULAR_ISSUE))
1525
1526 def testCanEditIssue_Restricted(self):
1527 # Anon users cannot edit restricted issues.
1528 self.assertFalse(permissions.CanEditIssue(
1529 {}, permissions.COMMITTER_ACTIVE_PERMISSIONSET,
1530 self.PROJECT, self.RESTRICTED_ISSUE3))
1531
1532 # Project committers cannot edit issues with a restriction to a custom
1533 # permission that they don't have.
1534 self.assertFalse(permissions.CanEditIssue(
1535 {OTHER_ID}, permissions.COMMITTER_ACTIVE_PERMISSIONSET,
1536 self.PROJECT, self.RESTRICTED_ISSUE3))
1537
1538 # *Issue* owners can always edit the issues that they own, even if
1539 # those issues are restricted to perms that they don't have.
1540 self.assertTrue(permissions.CanEditIssue(
1541 {OWNER_ID}, permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET,
1542 self.PROJECT, self.RESTRICTED_ISSUE3))
1543
1544 # Project owners can always edit, they cannot lock themselves out.
1545 self.assertTrue(permissions.CanEditIssue(
1546 {OTHER_ID}, permissions.OWNER_ACTIVE_PERMISSIONSET,
1547 self.PROJECT, self.RESTRICTED_ISSUE3))
1548
1549 # A committer with edit permission but not view permission
1550 # should not be able to edit the issue.
1551 self.assertFalse(permissions.CanEditIssue(
1552 {OTHER_ID}, permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET,
1553 self.PROJECT, self.RESTRICTED_ISSUE2))
1554
1555 def testCanCommentIssue_HasPerm(self):
1556 self.assertTrue(permissions.CanCommentIssue(
1557 {111}, permissions.PermissionSet([permissions.ADD_ISSUE_COMMENT]),
1558 None, None))
1559 self.assertFalse(permissions.CanCommentIssue(
1560 {111}, permissions.PermissionSet([]),
1561 None, None))
1562
1563 def testCanCommentIssue_HasExtraPerm(self):
1564 project = project_pb2.Project()
1565 project.committer_ids.append(111)
1566 extra_perm = project_pb2.Project.ExtraPerms(
1567 member_id=111, perms=[permissions.ADD_ISSUE_COMMENT])
1568 project.extra_perms.append(extra_perm)
1569 self.assertTrue(permissions.CanCommentIssue(
1570 {111}, permissions.PermissionSet([]),
1571 project, None))
1572 self.assertFalse(permissions.CanCommentIssue(
1573 {222}, permissions.PermissionSet([]),
1574 project, None))
1575
1576 def testCanCommentIssue_Restricted(self):
1577 issue = tracker_pb2.Issue(labels=['Restrict-AddIssueComment-CoreTeam'])
1578 # User is granted exactly the perm they need specifically in this issue.
1579 self.assertTrue(permissions.CanCommentIssue(
1580 {111}, permissions.PermissionSet([]),
1581 None, issue, granted_perms=['addissuecomment']))
1582 # User is granted CoreTeam, which satifies the restriction, and allows
1583 # them to use the AddIssueComment permission that they have and would
1584 # normally be able to use in an unrestricted issue.
1585 self.assertTrue(permissions.CanCommentIssue(
1586 {111}, permissions.PermissionSet([permissions.ADD_ISSUE_COMMENT]),
1587 None, issue, granted_perms=['coreteam']))
1588 # User was granted CoreTeam, but never had AddIssueComment.
1589 self.assertFalse(permissions.CanCommentIssue(
1590 {111}, permissions.PermissionSet([]),
1591 None, issue, granted_perms=['coreteam']))
1592 # User has AddIssueComment, but cannot satisfy restriction.
1593 self.assertFalse(permissions.CanCommentIssue(
1594 {111}, permissions.PermissionSet([permissions.ADD_ISSUE_COMMENT]),
1595 None, issue))
1596
1597 def testCanCommentIssue_Granted(self):
1598 self.assertTrue(permissions.CanCommentIssue(
1599 {111}, permissions.PermissionSet([]),
1600 None, None, granted_perms=['addissuecomment']))
1601 self.assertFalse(permissions.CanCommentIssue(
1602 {111}, permissions.PermissionSet([]),
1603 None, None))
1604
1605 def testCanUpdateApprovalStatus_Approver(self):
1606 # restricted status
1607 self.assertTrue(permissions.CanUpdateApprovalStatus(
1608 {111, 222}, permissions.PermissionSet([]), self.PROJECT,
1609 [222], tracker_pb2.ApprovalStatus.APPROVED))
1610
1611 # non-restricted status
1612 self.assertTrue(permissions.CanUpdateApprovalStatus(
1613 {111, 222}, permissions.PermissionSet([]), self.PROJECT,
1614 [222], tracker_pb2.ApprovalStatus.NEEDS_REVIEW))
1615
1616 def testCanUpdateApprovalStatus_SiteAdmin(self):
1617 # restricted status
1618 self.assertTrue(permissions.CanUpdateApprovalStatus(
1619 {444}, permissions.PermissionSet([permissions.EDIT_ISSUE_APPROVAL]),
1620 self.PROJECT, [222], tracker_pb2.ApprovalStatus.NOT_APPROVED))
1621
1622 # non-restricted status
1623 self.assertTrue(permissions.CanUpdateApprovalStatus(
1624 {444}, permissions.PermissionSet([permissions.EDIT_ISSUE_APPROVAL]),
1625 self.PROJECT, [222], tracker_pb2.ApprovalStatus.NEEDS_REVIEW))
1626
1627 def testCanUpdateApprovalStatus_NonApprover(self):
1628 # non-restricted status
1629 self.assertTrue(permissions.CanUpdateApprovalStatus(
1630 {111, 222}, permissions.PermissionSet([]), self.PROJECT,
1631 [333], tracker_pb2.ApprovalStatus.NEED_INFO))
1632
1633 # restricted status
1634 self.assertFalse(permissions.CanUpdateApprovalStatus(
1635 {111, 222}, permissions.PermissionSet([]), self.PROJECT,
1636 [333], tracker_pb2.ApprovalStatus.NA))
1637
1638 def testCanUpdateApprovers_Approver(self):
1639 self.assertTrue(permissions.CanUpdateApprovers(
1640 {111, 222}, permissions.PermissionSet([]), self.PROJECT,
1641 [222]))
1642
1643 def testCanUpdateApprovers_SiteAdmins(self):
1644 self.assertTrue(permissions.CanUpdateApprovers(
1645 {444}, permissions.PermissionSet([permissions.EDIT_ISSUE_APPROVAL]),
1646 self.PROJECT, [222]))
1647
1648 def testCanUpdateApprovers_NonApprover(self):
1649 self.assertFalse(permissions.CanUpdateApprovers(
1650 {111, 222}, permissions.PermissionSet([]), self.PROJECT,
1651 [333]))
1652
1653 def testCanViewComponentDef_ComponentAdmin(self):
1654 cd = tracker_pb2.ComponentDef(admin_ids=[111])
1655 perms = permissions.PermissionSet([])
1656 self.assertTrue(permissions.CanViewComponentDef(
1657 {111}, perms, None, cd))
1658 self.assertFalse(permissions.CanViewComponentDef(
1659 {999}, perms, None, cd))
1660
1661 def testCanViewComponentDef_NormalUser(self):
1662 cd = tracker_pb2.ComponentDef()
1663 self.assertTrue(permissions.CanViewComponentDef(
1664 {111}, permissions.PermissionSet([permissions.VIEW]),
1665 None, cd))
1666 self.assertFalse(permissions.CanViewComponentDef(
1667 {111}, permissions.PermissionSet([]),
1668 None, cd))
1669
1670 def testCanEditComponentDef_ComponentAdmin(self):
1671 cd = tracker_pb2.ComponentDef(admin_ids=[111], path='Whole')
1672 sub_cd = tracker_pb2.ComponentDef(admin_ids=[222], path='Whole>Part')
1673 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
1674 config.component_defs.append(cd)
1675 config.component_defs.append(sub_cd)
1676 perms = permissions.PermissionSet([])
1677 self.assertTrue(permissions.CanEditComponentDef(
1678 {111}, perms, None, cd, config))
1679 self.assertFalse(permissions.CanEditComponentDef(
1680 {222}, perms, None, cd, config))
1681 self.assertFalse(permissions.CanEditComponentDef(
1682 {999}, perms, None, cd, config))
1683 self.assertTrue(permissions.CanEditComponentDef(
1684 {111}, perms, None, sub_cd, config))
1685 self.assertTrue(permissions.CanEditComponentDef(
1686 {222}, perms, None, sub_cd, config))
1687 self.assertFalse(permissions.CanEditComponentDef(
1688 {999}, perms, None, sub_cd, config))
1689
1690 def testCanEditComponentDef_ProjectOwners(self):
1691 cd = tracker_pb2.ComponentDef(path='Whole')
1692 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
1693 config.component_defs.append(cd)
1694 self.assertTrue(permissions.CanEditComponentDef(
1695 {111}, permissions.PermissionSet([permissions.EDIT_PROJECT]),
1696 None, cd, config))
1697 self.assertFalse(permissions.CanEditComponentDef(
1698 {111}, permissions.PermissionSet([]),
1699 None, cd, config))
1700
1701 def testCanViewFieldDef_FieldAdmin(self):
1702 fd = tracker_pb2.FieldDef(admin_ids=[111])
1703 perms = permissions.PermissionSet([])
1704 self.assertTrue(permissions.CanViewFieldDef(
1705 {111}, perms, None, fd))
1706 self.assertFalse(permissions.CanViewFieldDef(
1707 {999}, perms, None, fd))
1708
1709 def testCanViewFieldDef_NormalUser(self):
1710 fd = tracker_pb2.FieldDef()
1711 self.assertTrue(permissions.CanViewFieldDef(
1712 {111}, permissions.PermissionSet([permissions.VIEW]),
1713 None, fd))
1714 self.assertFalse(permissions.CanViewFieldDef(
1715 {111}, permissions.PermissionSet([]),
1716 None, fd))
1717
1718 def testCanEditFieldDef_FieldAdmin(self):
1719 fd = tracker_pb2.FieldDef(admin_ids=[111])
1720 perms = permissions.PermissionSet([])
1721 self.assertTrue(permissions.CanEditFieldDef(
1722 {111}, perms, None, fd))
1723 self.assertFalse(permissions.CanEditFieldDef(
1724 {999}, perms, None, fd))
1725
1726 def testCanEditFieldDef_ProjectOwners(self):
1727 fd = tracker_pb2.FieldDef()
1728 self.assertTrue(permissions.CanEditFieldDef(
1729 {111}, permissions.PermissionSet([permissions.EDIT_PROJECT]),
1730 None, fd))
1731 self.assertFalse(permissions.CanEditFieldDef(
1732 {111}, permissions.PermissionSet([]),
1733 None, fd))
1734
1735 def testCanEditValueForFieldDef_NotRestrictedField(self):
1736 fd = tracker_pb2.FieldDef()
1737 perms = permissions.PermissionSet([])
1738 self.assertTrue(permissions.CanEditValueForFieldDef({111}, perms, None, fd))
1739
1740 def testCanEditValueForFieldDef_RestrictedFieldEditor(self):
1741 fd = tracker_pb2.FieldDef(is_restricted_field=True, editor_ids=[111])
1742 perms = permissions.PermissionSet([])
1743 self.assertTrue(permissions.CanEditValueForFieldDef({111}, perms, None, fd))
1744 self.assertFalse(
1745 permissions.CanEditValueForFieldDef({999}, perms, None, fd))
1746
1747 def testCanEditValueForFieldDef_RestrictedFieldAdmin(self):
1748 fd = tracker_pb2.FieldDef(is_restricted_field=True, admin_ids=[111])
1749 perms = permissions.PermissionSet([])
1750 self.assertTrue(permissions.CanEditValueForFieldDef({111}, perms, None, fd))
1751 self.assertFalse(
1752 permissions.CanEditValueForFieldDef({999}, perms, None, fd))
1753
1754 def testCanEditValueForFieldDef_ProjectOwners(self):
1755 fd = tracker_pb2.FieldDef(is_restricted_field=True)
1756 self.assertTrue(
1757 permissions.CanEditValueForFieldDef(
1758 {111}, permissions.PermissionSet([permissions.EDIT_PROJECT]), None,
1759 fd))
1760 self.assertFalse(
1761 permissions.CanEditValueForFieldDef(
1762 {111}, permissions.PermissionSet([]), None, fd))
1763
1764 def testCanViewTemplate_TemplateAdmin(self):
1765 td = tracker_pb2.TemplateDef(admin_ids=[111])
1766 perms = permissions.PermissionSet([])
1767 self.assertTrue(permissions.CanViewTemplate(
1768 {111}, perms, None, td))
1769 self.assertFalse(permissions.CanViewTemplate(
1770 {999}, perms, None, td))
1771
1772 def testCanViewTemplate_MembersOnly(self):
1773 td = tracker_pb2.TemplateDef(members_only=True)
1774 project = project_pb2.Project(committer_ids=[111])
1775 self.assertTrue(permissions.CanViewTemplate(
1776 {111}, permissions.PermissionSet([]),
1777 project, td))
1778 self.assertFalse(permissions.CanViewTemplate(
1779 {999}, permissions.PermissionSet([]),
1780 project, td))
1781
1782 def testCanViewTemplate_AnyoneWhoCanViewProject(self):
1783 td = tracker_pb2.TemplateDef()
1784 self.assertTrue(permissions.CanViewTemplate(
1785 {111}, permissions.PermissionSet([permissions.VIEW]),
1786 None, td))
1787 self.assertFalse(permissions.CanViewTemplate(
1788 {111}, permissions.PermissionSet([]),
1789 None, td))
1790
1791 def testCanEditTemplate_TemplateAdmin(self):
1792 td = tracker_pb2.TemplateDef(admin_ids=[111])
1793 perms = permissions.PermissionSet([])
1794 self.assertTrue(permissions.CanEditTemplate(
1795 {111}, perms, None, td))
1796 self.assertFalse(permissions.CanEditTemplate(
1797 {999}, perms, None, td))
1798
1799 def testCanEditTemplate_ProjectOwners(self):
1800 td = tracker_pb2.TemplateDef()
1801 self.assertTrue(permissions.CanEditTemplate(
1802 {111}, permissions.PermissionSet([permissions.EDIT_PROJECT]),
1803 None, td))
1804 self.assertFalse(permissions.CanEditTemplate(
1805 {111}, permissions.PermissionSet([]),
1806 None, td))
1807
1808 def testCanViewHotlist_Private(self):
1809 hotlist = features_pb2.Hotlist()
1810 hotlist.is_private = True
1811 hotlist.owner_ids.append(111)
1812 hotlist.editor_ids.append(222)
1813
1814 self.assertTrue(permissions.CanViewHotlist({222}, self.PERMS, hotlist))
1815 self.assertTrue(permissions.CanViewHotlist({111, 333}, self.PERMS, hotlist))
1816 self.assertTrue(
1817 permissions.CanViewHotlist({111, 333}, self.ADMIN_PERMS, hotlist))
1818 self.assertFalse(
1819 permissions.CanViewHotlist({333, 444}, self.PERMS, hotlist))
1820 self.assertTrue(
1821 permissions.CanViewHotlist({333, 444}, self.ADMIN_PERMS, hotlist))
1822
1823 def testCanViewHotlist_Public(self):
1824 hotlist = features_pb2.Hotlist()
1825 hotlist.is_private = False
1826 hotlist.owner_ids.append(111)
1827 hotlist.editor_ids.append(222)
1828
1829 self.assertTrue(permissions.CanViewHotlist({222}, self.PERMS, hotlist))
1830 self.assertTrue(permissions.CanViewHotlist({111, 333}, self.PERMS, hotlist))
1831 self.assertTrue(permissions.CanViewHotlist({333, 444}, self.PERMS, hotlist))
1832 self.assertTrue(
1833 permissions.CanViewHotlist({333, 444}, self.ADMIN_PERMS, hotlist))
1834
1835 def testCanEditHotlist(self):
1836 hotlist = features_pb2.Hotlist()
1837 hotlist.owner_ids.append(111)
1838 hotlist.editor_ids.append(222)
1839
1840 self.assertTrue(permissions.CanEditHotlist({222}, self.PERMS, hotlist))
1841 self.assertTrue(permissions.CanEditHotlist({111, 333}, self.PERMS, hotlist))
1842 self.assertTrue(
1843 permissions.CanEditHotlist({111, 333}, self.ADMIN_PERMS, hotlist))
1844 self.assertFalse(
1845 permissions.CanEditHotlist({333, 444}, self.PERMS, hotlist))
1846 self.assertTrue(
1847 permissions.CanEditHotlist({333, 444}, self.ADMIN_PERMS, hotlist))
1848
1849 def testCanAdministerHotlist(self):
1850 hotlist = features_pb2.Hotlist()
1851 hotlist.owner_ids.append(111)
1852 hotlist.editor_ids.append(222)
1853
1854 self.assertFalse(
1855 permissions.CanAdministerHotlist({222}, self.PERMS, hotlist))
1856 self.assertTrue(
1857 permissions.CanAdministerHotlist({111, 333}, self.PERMS, hotlist))
1858 self.assertTrue(
1859 permissions.CanAdministerHotlist({111, 333}, self.ADMIN_PERMS, hotlist))
1860 self.assertFalse(
1861 permissions.CanAdministerHotlist({333, 444}, self.PERMS, hotlist))
1862 self.assertTrue(
1863 permissions.CanAdministerHotlist({333, 444}, self.ADMIN_PERMS, hotlist))