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