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