Merge lp:~twom/launchpad/rework-git-permissions-for-shadowing into lp:launchpad
- rework-git-permissions-for-shadowing
- Merge into devel
Proposed by
Tom Wardill
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 18801 | ||||
Proposed branch: | lp:~twom/launchpad/rework-git-permissions-for-shadowing | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
959 lines (+190/-682) 3 files modified
lib/lp/code/interfaces/gitapi.py (+3/-2) lib/lp/code/xmlrpc/git.py (+40/-45) lib/lp/code/xmlrpc/tests/test_git.py (+147/-635) |
||||
To merge this branch: | bzr merge lp:~twom/launchpad/rework-git-permissions-for-shadowing | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Review via email: mp+357091@code.launchpad.net |
Commit message
Rework git branch permissions to improve shadowing for multiple grants
Description of the change
To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) : | # |
review:
Needs Fixing
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/code/interfaces/gitapi.py' | |||
2 | --- lib/lp/code/interfaces/gitapi.py 2018-09-28 13:53:41 +0000 | |||
3 | +++ lib/lp/code/interfaces/gitapi.py 2018-10-19 08:51:38 +0000 | |||
4 | @@ -68,8 +68,9 @@ | |||
5 | 68 | not yet supported. | 68 | not yet supported. |
6 | 69 | """ | 69 | """ |
7 | 70 | 70 | ||
10 | 71 | def listRefRules(self, repository, user): | 71 | def checkRefPermissions(self, repository, ref_paths, user): |
11 | 72 | """Return the list of ref rules for `user` in `repository` | 72 | """Return a list of ref rules for a `user` in a `repository` that |
12 | 73 | match the input refs. | ||
13 | 73 | 74 | ||
14 | 74 | :returns: A list of rules for the user in the specified repository | 75 | :returns: A list of rules for the user in the specified repository |
15 | 75 | """ | 76 | """ |
16 | 76 | 77 | ||
17 | === modified file 'lib/lp/code/xmlrpc/git.py' | |||
18 | --- lib/lp/code/xmlrpc/git.py 2018-10-17 10:09:33 +0000 | |||
19 | +++ lib/lp/code/xmlrpc/git.py 2018-10-19 08:51:38 +0000 | |||
20 | @@ -8,6 +8,8 @@ | |||
21 | 8 | 'GitAPI', | 8 | 'GitAPI', |
22 | 9 | ] | 9 | ] |
23 | 10 | 10 | ||
24 | 11 | from collections import defaultdict | ||
25 | 12 | from fnmatch import fnmatch | ||
26 | 11 | import sys | 13 | import sys |
27 | 12 | 14 | ||
28 | 13 | from pymacaroons import Macaroon | 15 | from pymacaroons import Macaroon |
29 | @@ -24,7 +26,10 @@ | |||
30 | 24 | 26 | ||
31 | 25 | from lp.app.errors import NameLookupFailed | 27 | from lp.app.errors import NameLookupFailed |
32 | 26 | from lp.app.validators import LaunchpadValidationError | 28 | from lp.app.validators import LaunchpadValidationError |
34 | 27 | from lp.code.enums import GitRepositoryType | 29 | from lp.code.enums import ( |
35 | 30 | GitGranteeType, | ||
36 | 31 | GitRepositoryType, | ||
37 | 32 | ) | ||
38 | 28 | from lp.code.errors import ( | 33 | from lp.code.errors import ( |
39 | 29 | GitRepositoryCreationException, | 34 | GitRepositoryCreationException, |
40 | 30 | GitRepositoryCreationFault, | 35 | GitRepositoryCreationFault, |
41 | @@ -350,67 +355,57 @@ | |||
42 | 350 | permissions.add('force_push') | 355 | permissions.add('force_push') |
43 | 351 | return permissions | 356 | return permissions |
44 | 352 | 357 | ||
46 | 353 | def _listRefRules(self, requester, translated_path): | 358 | def _findMatchingRules(self, repository, ref_path): |
47 | 359 | """Find all matching rules for a given ref path""" | ||
48 | 360 | matching_rules = [] | ||
49 | 361 | for rule in repository.rules: | ||
50 | 362 | if fnmatch(ref_path, rule.ref_pattern): | ||
51 | 363 | matching_rules.append(rule) | ||
52 | 364 | return matching_rules | ||
53 | 365 | |||
54 | 366 | def _checkRefPermissions(self, requester, translated_path, ref_paths): | ||
55 | 354 | repository = removeSecurityProxy( | 367 | repository = removeSecurityProxy( |
56 | 355 | getUtility(IGitLookup).getByHostingPath(translated_path)) | 368 | getUtility(IGitLookup).getByHostingPath(translated_path)) |
57 | 356 | is_owner = requester.inTeam(repository.owner) | 369 | is_owner = requester.inTeam(repository.owner) |
58 | 370 | result = {} | ||
59 | 371 | |||
60 | 372 | grants_for_user = defaultdict(list) | ||
61 | 357 | grants = repository.findRuleGrantsByGrantee(requester) | 373 | grants = repository.findRuleGrantsByGrantee(requester) |
62 | 358 | # If the user is the owner, get the grants for REPOSITORY_OWNER | ||
63 | 359 | # and add them to our available grants to match against | ||
64 | 360 | if is_owner: | 374 | if is_owner: |
65 | 361 | owner_grants = repository.findRuleGrantsForRepositoryOwner() | 375 | owner_grants = repository.findRuleGrantsForRepositoryOwner() |
66 | 362 | grants = grants.union(owner_grants) | 376 | grants = grants.union(owner_grants) |
68 | 363 | result = [] | 377 | for grant in grants: |
69 | 378 | grants_for_user[grant.rule].append(grant) | ||
70 | 364 | 379 | ||
81 | 365 | for rule in repository.rules: | 380 | for ref in ref_paths: |
82 | 366 | # Do we have any grants for this rule, for this user? | 381 | matching_rules = self._findMatchingRules(repository, ref) |
83 | 367 | matching_grants = [x for x in grants if x.rule == rule] | 382 | if is_owner and not matching_rules: |
84 | 368 | # If we don't have any grants, but the user is the owner, | 383 | result[ref] = ['create', 'push', 'force_push'] |
75 | 369 | # they get a default grant to the ref specified by the rule. | ||
76 | 370 | if is_owner and not matching_grants: | ||
77 | 371 | result.append( | ||
78 | 372 | {'ref_pattern': rule.ref_pattern, | ||
79 | 373 | 'permissions': ['create', 'push'], | ||
80 | 374 | }) | ||
85 | 375 | continue | 384 | continue |
88 | 376 | 385 | seen_grantees = set() | |
87 | 377 | # Permissions are a union of all the applicable grants | ||
89 | 378 | union_permissions = set() | 386 | union_permissions = set() |
93 | 379 | for grant in matching_grants: | 387 | for rule in matching_rules: |
94 | 380 | permissions = self._buildPermissions(grant) | 388 | for grant in grants_for_user[rule]: |
95 | 381 | union_permissions.update(permissions) | 389 | if (grant.grantee, grant.grantee_type) in seen_grantees: |
96 | 390 | continue | ||
97 | 391 | permissions = self._buildPermissions(grant) | ||
98 | 392 | union_permissions.update(permissions) | ||
99 | 393 | seen_grantees.add((grant.grantee, grant.grantee_type)) | ||
100 | 382 | 394 | ||
105 | 383 | # If the user is the repository owner, they essentially have | 395 | owner_type = (None, GitGranteeType.REPOSITORY_OWNER) |
106 | 384 | # the equivalent of a default team grant, but only | 396 | if is_owner and owner_type not in seen_grantees: |
103 | 385 | # if there is no explicit grant to them otherwise specified | ||
104 | 386 | if is_owner and not any(g for g in owner_grants if g.rule == rule): | ||
107 | 387 | union_permissions.update(['create', 'push']) | 397 | union_permissions.update(['create', 'push']) |
108 | 388 | 398 | ||
109 | 389 | # Sort the permissions from the set for consistency | ||
110 | 390 | sorted_permissions = self._sortPermissions(union_permissions) | 399 | sorted_permissions = self._sortPermissions(union_permissions) |
127 | 391 | result.append( | 400 | result[ref] = sorted_permissions |
112 | 392 | {'ref_pattern': rule.ref_pattern, | ||
113 | 393 | 'permissions': sorted_permissions, | ||
114 | 394 | }) | ||
115 | 395 | |||
116 | 396 | # The last rule is a default wildcard. The repository owner gets | ||
117 | 397 | # permissions to everything, whereas other people get no permissions. | ||
118 | 398 | if is_owner: | ||
119 | 399 | default_permissions = ['create', 'push', 'force_push'] | ||
120 | 400 | else: | ||
121 | 401 | default_permissions = [] | ||
122 | 402 | result.append( | ||
123 | 403 | {'ref_pattern': '*', | ||
124 | 404 | 'permissions': default_permissions, | ||
125 | 405 | }) | ||
126 | 406 | |||
128 | 407 | return result | 401 | return result |
129 | 408 | 402 | ||
132 | 409 | def listRefRules(self, translated_path, auth_params): | 403 | def checkRefPermissions(self, translated_path, ref_paths, auth_params): |
133 | 410 | """See `IGitAPI`""" | 404 | """ See `IGitAPI`""" |
134 | 411 | requester_id = auth_params.get("uid") | 405 | requester_id = auth_params.get("uid") |
135 | 412 | return run_with_login( | 406 | return run_with_login( |
136 | 413 | requester_id, | 407 | requester_id, |
138 | 414 | self._listRefRules, | 408 | self._checkRefPermissions, |
139 | 415 | translated_path, | 409 | translated_path, |
141 | 416 | ) | 410 | ref_paths |
142 | 411 | ) | ||
143 | 417 | 412 | ||
144 | === modified file 'lib/lp/code/xmlrpc/tests/test_git.py' | |||
145 | --- lib/lp/code/xmlrpc/tests/test_git.py 2018-10-17 10:09:33 +0000 | |||
146 | +++ lib/lp/code/xmlrpc/tests/test_git.py 2018-10-19 08:51:38 +0000 | |||
147 | @@ -266,410 +266,7 @@ | |||
148 | 266 | self.assertEqual( | 266 | self.assertEqual( |
149 | 267 | initial_count, getUtility(IAllGitRepositories).count()) | 267 | initial_count, getUtility(IAllGitRepositories).count()) |
150 | 268 | 268 | ||
555 | 269 | def test_listRefRules_simple(self): | 269 | def _make_scenario_one_repository(self): |
152 | 270 | # Test that correct ref rules are retrieved for a Person | ||
153 | 271 | requester = self.factory.makePerson() | ||
154 | 272 | repository = removeSecurityProxy( | ||
155 | 273 | self.factory.makeGitRepository()) | ||
156 | 274 | |||
157 | 275 | rule = self.factory.makeGitRule(repository) | ||
158 | 276 | self.factory.makeGitRuleGrant( | ||
159 | 277 | rule=rule, grantee=requester, can_push=True, can_create=True) | ||
160 | 278 | |||
161 | 279 | results = self.git_api.listRefRules( | ||
162 | 280 | repository.getInternalPath(), | ||
163 | 281 | {'uid': requester.id}) | ||
164 | 282 | self.assertThat(results, MatchesListwise([ | ||
165 | 283 | MatchesDict({ | ||
166 | 284 | 'ref_pattern': Equals('refs/heads/*'), | ||
167 | 285 | 'permissions': Equals(['create', 'push']), | ||
168 | 286 | }), | ||
169 | 287 | MatchesDict({ | ||
170 | 288 | 'ref_pattern': Equals('*'), | ||
171 | 289 | 'permissions': Equals([]), | ||
172 | 290 | }), | ||
173 | 291 | ])) | ||
174 | 292 | |||
175 | 293 | def test_listRefRules_with_other_grants(self): | ||
176 | 294 | # Test that findRuleGrantsByGrantee only returns relevant rules | ||
177 | 295 | requester = self.factory.makePerson() | ||
178 | 296 | other_user = self.factory.makePerson() | ||
179 | 297 | repository = removeSecurityProxy( | ||
180 | 298 | self.factory.makeGitRepository()) | ||
181 | 299 | |||
182 | 300 | rule = self.factory.makeGitRule(repository) | ||
183 | 301 | self.factory.makeGitRuleGrant( | ||
184 | 302 | rule=rule, grantee=requester, can_push=True) | ||
185 | 303 | self.factory.makeGitRuleGrant( | ||
186 | 304 | rule=rule, grantee=other_user, can_create=True) | ||
187 | 305 | |||
188 | 306 | results = self.git_api.listRefRules( | ||
189 | 307 | repository.getInternalPath(), | ||
190 | 308 | {'uid': requester.id}) | ||
191 | 309 | self.assertThat(results, MatchesListwise([ | ||
192 | 310 | MatchesDict({ | ||
193 | 311 | 'ref_pattern': Equals('refs/heads/*'), | ||
194 | 312 | 'permissions': Equals(['push']), | ||
195 | 313 | }), | ||
196 | 314 | MatchesDict({ | ||
197 | 315 | 'ref_pattern': Equals('*'), | ||
198 | 316 | 'permissions': Equals([]), | ||
199 | 317 | }), | ||
200 | 318 | ])) | ||
201 | 319 | |||
202 | 320 | def test_listRefRules_owner_has_default(self): | ||
203 | 321 | owner = self.factory.makePerson() | ||
204 | 322 | repository = removeSecurityProxy( | ||
205 | 323 | self.factory.makeGitRepository(owner=owner)) | ||
206 | 324 | |||
207 | 325 | results = self.git_api.listRefRules( | ||
208 | 326 | repository.getInternalPath(), | ||
209 | 327 | {'uid': owner.id}) | ||
210 | 328 | |||
211 | 329 | self.assertThat(results, MatchesListwise([ | ||
212 | 330 | MatchesDict({ | ||
213 | 331 | 'ref_pattern': Equals('*'), | ||
214 | 332 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
215 | 333 | }), | ||
216 | 334 | ])) | ||
217 | 335 | |||
218 | 336 | def test_listRefRules_owner_modifies_rules(self): | ||
219 | 337 | owner = self.factory.makePerson() | ||
220 | 338 | person = self.factory.makePerson() | ||
221 | 339 | repository = removeSecurityProxy( | ||
222 | 340 | self.factory.makeGitRepository(owner=owner)) | ||
223 | 341 | |||
224 | 342 | rule = self.factory.makeGitRule( | ||
225 | 343 | repository, ref_pattern=u'refs/heads/stable/*') | ||
226 | 344 | self.factory.makeGitRuleGrant( | ||
227 | 345 | rule=rule, grantee=person, can_push=True) | ||
228 | 346 | |||
229 | 347 | results = self.git_api.listRefRules( | ||
230 | 348 | repository.getInternalPath(), | ||
231 | 349 | {'uid': owner.id}) | ||
232 | 350 | |||
233 | 351 | self.assertThat(results, MatchesListwise([ | ||
234 | 352 | MatchesDict({ | ||
235 | 353 | 'ref_pattern': Equals('refs/heads/stable/*'), | ||
236 | 354 | 'permissions': Equals(['create', 'push']), | ||
237 | 355 | }), | ||
238 | 356 | MatchesDict({ | ||
239 | 357 | 'ref_pattern': Equals('*'), | ||
240 | 358 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
241 | 359 | }), | ||
242 | 360 | ])) | ||
243 | 361 | |||
244 | 362 | def test_listRefRules_owner_no_default_with_explicit(self): | ||
245 | 363 | owner = self.factory.makePerson() | ||
246 | 364 | repository = removeSecurityProxy( | ||
247 | 365 | self.factory.makeGitRepository(owner=owner)) | ||
248 | 366 | |||
249 | 367 | rule = self.factory.makeGitRule( | ||
250 | 368 | repository, ref_pattern=u'refs/heads/stable/*') | ||
251 | 369 | self.factory.makeGitRuleGrant( | ||
252 | 370 | rule=rule, grantee=GitGranteeType.REPOSITORY_OWNER, can_push=True) | ||
253 | 371 | |||
254 | 372 | results = self.git_api.listRefRules( | ||
255 | 373 | repository.getInternalPath(), | ||
256 | 374 | {'uid': owner.id}) | ||
257 | 375 | |||
258 | 376 | self.assertThat(results, MatchesListwise([ | ||
259 | 377 | MatchesDict({ | ||
260 | 378 | 'ref_pattern': Equals('refs/heads/stable/*'), | ||
261 | 379 | 'permissions': Equals(['push']), | ||
262 | 380 | }), | ||
263 | 381 | MatchesDict({ | ||
264 | 382 | 'ref_pattern': Equals('*'), | ||
265 | 383 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
266 | 384 | }), | ||
267 | 385 | ])) | ||
268 | 386 | |||
269 | 387 | def test_listRefRules_owner_modifies_rules_multiple_grants(self): | ||
270 | 388 | owner = self.factory.makePerson() | ||
271 | 389 | person = self.factory.makePerson() | ||
272 | 390 | repository = removeSecurityProxy( | ||
273 | 391 | self.factory.makeGitRepository(owner=owner)) | ||
274 | 392 | |||
275 | 393 | rule = self.factory.makeGitRule( | ||
276 | 394 | repository, ref_pattern=u'refs/heads/stable/*') | ||
277 | 395 | self.factory.makeGitRuleGrant( | ||
278 | 396 | rule=rule, grantee=person, can_push=True, can_create=True) | ||
279 | 397 | |||
280 | 398 | self.factory.makeGitRuleGrant( | ||
281 | 399 | rule=rule, grantee=GitGranteeType.REPOSITORY_OWNER, can_push=True) | ||
282 | 400 | |||
283 | 401 | results = self.git_api.listRefRules( | ||
284 | 402 | repository.getInternalPath(), | ||
285 | 403 | {'uid': owner.id}) | ||
286 | 404 | |||
287 | 405 | self.assertThat(results, MatchesListwise([ | ||
288 | 406 | MatchesDict({ | ||
289 | 407 | 'ref_pattern': Equals('refs/heads/stable/*'), | ||
290 | 408 | 'permissions': Equals(['push']), | ||
291 | 409 | }), | ||
292 | 410 | MatchesDict({ | ||
293 | 411 | 'ref_pattern': Equals('*'), | ||
294 | 412 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
295 | 413 | }), | ||
296 | 414 | ])) | ||
297 | 415 | |||
298 | 416 | def test_listRefRules_no_grants(self): | ||
299 | 417 | # User that has no grants and is not the owner | ||
300 | 418 | requester = self.factory.makePerson() | ||
301 | 419 | owner = self.factory.makePerson() | ||
302 | 420 | repository = removeSecurityProxy( | ||
303 | 421 | self.factory.makeGitRepository(owner=owner)) | ||
304 | 422 | |||
305 | 423 | rule = self.factory.makeGitRule(repository) | ||
306 | 424 | self.factory.makeGitRuleGrant( | ||
307 | 425 | rule=rule, grantee=owner, can_push=True, can_create=True) | ||
308 | 426 | |||
309 | 427 | results = self.git_api.listRefRules( | ||
310 | 428 | repository.getInternalPath(), | ||
311 | 429 | {'uid': requester.id}) | ||
312 | 430 | self.assertThat(results, MatchesListwise([ | ||
313 | 431 | MatchesDict({ | ||
314 | 432 | 'ref_pattern': Equals('refs/heads/*'), | ||
315 | 433 | 'permissions': Equals([]), | ||
316 | 434 | }), | ||
317 | 435 | MatchesDict({ | ||
318 | 436 | 'ref_pattern': Equals('*'), | ||
319 | 437 | 'permissions': Equals([]), | ||
320 | 438 | }), | ||
321 | 439 | ])) | ||
322 | 440 | |||
323 | 441 | def test_listRefRules_owner_has_default_with_other_grant(self): | ||
324 | 442 | owner = self.factory.makePerson() | ||
325 | 443 | repository = removeSecurityProxy( | ||
326 | 444 | self.factory.makeGitRepository(owner=owner)) | ||
327 | 445 | |||
328 | 446 | rule = self.factory.makeGitRule( | ||
329 | 447 | repository=repository, ref_pattern=u'refs/heads/master') | ||
330 | 448 | self.factory.makeGitRuleGrant( | ||
331 | 449 | rule=rule, grantee=owner, can_push=True, can_create=True) | ||
332 | 450 | |||
333 | 451 | results = self.git_api.listRefRules( | ||
334 | 452 | repository.getInternalPath(), | ||
335 | 453 | {'uid': owner.id}) | ||
336 | 454 | # Default grant should be last in pattern | ||
337 | 455 | self.assertThat(results, MatchesListwise([ | ||
338 | 456 | MatchesDict({ | ||
339 | 457 | 'ref_pattern': Equals('refs/heads/master'), | ||
340 | 458 | 'permissions': Equals(['create', 'push']), | ||
341 | 459 | }), | ||
342 | 460 | MatchesDict({ | ||
343 | 461 | 'ref_pattern': Equals('*'), | ||
344 | 462 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
345 | 463 | }), | ||
346 | 464 | ])) | ||
347 | 465 | |||
348 | 466 | def test_listRefRules_owner_is_team(self): | ||
349 | 467 | member = self.factory.makePerson() | ||
350 | 468 | owner = self.factory.makeTeam(members=[member]) | ||
351 | 469 | repository = removeSecurityProxy( | ||
352 | 470 | self.factory.makeGitRepository( | ||
353 | 471 | owner=owner, information_type=InformationType.USERDATA)) | ||
354 | 472 | |||
355 | 473 | results = self.git_api.listRefRules( | ||
356 | 474 | repository.getInternalPath(), | ||
357 | 475 | {'uid': member.id}) | ||
358 | 476 | |||
359 | 477 | # Should have default grant as member of owning team | ||
360 | 478 | self.assertThat(results, MatchesListwise([ | ||
361 | 479 | MatchesDict({ | ||
362 | 480 | 'ref_pattern': Equals('*'), | ||
363 | 481 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
364 | 482 | }), | ||
365 | 483 | ])) | ||
366 | 484 | |||
367 | 485 | def test_listRefRules_owner_is_team_with_grants(self): | ||
368 | 486 | member = self.factory.makePerson() | ||
369 | 487 | owner = self.factory.makeTeam(members=[member]) | ||
370 | 488 | repository = removeSecurityProxy( | ||
371 | 489 | self.factory.makeGitRepository( | ||
372 | 490 | owner=owner, information_type=InformationType.USERDATA)) | ||
373 | 491 | |||
374 | 492 | rule = self.factory.makeGitRule( | ||
375 | 493 | repository=repository, ref_pattern=u'refs/heads/master') | ||
376 | 494 | self.factory.makeGitRuleGrant( | ||
377 | 495 | rule=rule, grantee=owner, can_push=True, can_create=True) | ||
378 | 496 | |||
379 | 497 | results = self.git_api.listRefRules( | ||
380 | 498 | repository.getInternalPath(), | ||
381 | 499 | {'uid': member.id}) | ||
382 | 500 | |||
383 | 501 | # Should have default grant as member of owning team | ||
384 | 502 | self.assertThat(results, MatchesListwise([ | ||
385 | 503 | MatchesDict({ | ||
386 | 504 | 'ref_pattern': Equals('refs/heads/master'), | ||
387 | 505 | 'permissions': Equals(['create', 'push']), | ||
388 | 506 | }), | ||
389 | 507 | MatchesDict({ | ||
390 | 508 | 'ref_pattern': Equals('*'), | ||
391 | 509 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
392 | 510 | }), | ||
393 | 511 | ])) | ||
394 | 512 | |||
395 | 513 | def test_listRefRules_owner_is_team_with_grants_to_person(self): | ||
396 | 514 | member = self.factory.makePerson() | ||
397 | 515 | other_member = self.factory.makePerson() | ||
398 | 516 | owner = self.factory.makeTeam(members=[member, other_member]) | ||
399 | 517 | repository = removeSecurityProxy( | ||
400 | 518 | self.factory.makeGitRepository( | ||
401 | 519 | owner=owner, information_type=InformationType.USERDATA)) | ||
402 | 520 | |||
403 | 521 | rule = self.factory.makeGitRule( | ||
404 | 522 | repository=repository, ref_pattern=u'refs/heads/master') | ||
405 | 523 | self.factory.makeGitRuleGrant( | ||
406 | 524 | rule=rule, grantee=GitGranteeType.REPOSITORY_OWNER, | ||
407 | 525 | can_push=True, can_create=True) | ||
408 | 526 | |||
409 | 527 | rule = self.factory.makeGitRule( | ||
410 | 528 | repository=repository, ref_pattern=u'refs/heads/tags') | ||
411 | 529 | self.factory.makeGitRuleGrant( | ||
412 | 530 | rule=rule, grantee=member, can_create=True) | ||
413 | 531 | |||
414 | 532 | # This should not appear | ||
415 | 533 | self.factory.makeGitRuleGrant( | ||
416 | 534 | rule=rule, grantee=other_member, can_push=True) | ||
417 | 535 | |||
418 | 536 | results = self.git_api.listRefRules( | ||
419 | 537 | repository.getInternalPath(), | ||
420 | 538 | {'uid': member.id}) | ||
421 | 539 | |||
422 | 540 | # Should have default grant as member of owning team | ||
423 | 541 | self.assertThat(results, MatchesListwise([ | ||
424 | 542 | MatchesDict({ | ||
425 | 543 | 'ref_pattern': Equals('refs/heads/master'), | ||
426 | 544 | 'permissions': Equals(['create', 'push']), | ||
427 | 545 | }), | ||
428 | 546 | MatchesDict({ | ||
429 | 547 | 'ref_pattern': Equals('refs/heads/tags'), | ||
430 | 548 | 'permissions': Equals(['create', 'push']), | ||
431 | 549 | }), | ||
432 | 550 | MatchesDict({ | ||
433 | 551 | 'ref_pattern': Equals('*'), | ||
434 | 552 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
435 | 553 | }), | ||
436 | 554 | ])) | ||
437 | 555 | |||
438 | 556 | def test_listRefRules_multiple_grants_to_same_ref_with_owner(self): | ||
439 | 557 | member = self.factory.makePerson() | ||
440 | 558 | owner = self.factory.makeTeam(members=[member]) | ||
441 | 559 | repository = removeSecurityProxy( | ||
442 | 560 | self.factory.makeGitRepository(owner=owner)) | ||
443 | 561 | |||
444 | 562 | rule = self.factory.makeGitRule(repository=repository) | ||
445 | 563 | self.factory.makeGitRuleGrant( | ||
446 | 564 | rule=rule, grantee=member, can_create=True) | ||
447 | 565 | self.factory.makeGitRuleGrant( | ||
448 | 566 | rule=rule, grantee=owner, can_push=True) | ||
449 | 567 | |||
450 | 568 | results = self.git_api.listRefRules( | ||
451 | 569 | repository.getInternalPath(), | ||
452 | 570 | {'uid': member.id}) | ||
453 | 571 | |||
454 | 572 | self.assertThat(results, MatchesListwise([ | ||
455 | 573 | MatchesDict({ | ||
456 | 574 | 'ref_pattern': Equals('refs/heads/*'), | ||
457 | 575 | 'permissions': Equals(['create', 'push']), | ||
458 | 576 | }), | ||
459 | 577 | MatchesDict({ | ||
460 | 578 | 'ref_pattern': Equals('*'), | ||
461 | 579 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
462 | 580 | }), | ||
463 | 581 | ])) | ||
464 | 582 | |||
465 | 583 | def test_listRefRules_multiple_grants_collapsing(self): | ||
466 | 584 | member = self.factory.makePerson() | ||
467 | 585 | second_member = self.factory.makePerson() | ||
468 | 586 | third_member = self.factory.makePerson() | ||
469 | 587 | owner = self.factory.makePerson() | ||
470 | 588 | repository = removeSecurityProxy( | ||
471 | 589 | self.factory.makeGitRepository(owner=owner)) | ||
472 | 590 | |||
473 | 591 | rule = self.factory.makeGitRule(repository=repository) | ||
474 | 592 | self.factory.makeGitRuleGrant( | ||
475 | 593 | rule=rule, grantee=member, can_create=True) | ||
476 | 594 | self.factory.makeGitRuleGrant( | ||
477 | 595 | rule=rule, grantee=second_member, can_push=True) | ||
478 | 596 | self.factory.makeGitRuleGrant( | ||
479 | 597 | rule=rule, grantee=third_member, can_force_push=True) | ||
480 | 598 | |||
481 | 599 | results = self.git_api.listRefRules( | ||
482 | 600 | repository.getInternalPath(), | ||
483 | 601 | {'uid': owner.id}) | ||
484 | 602 | |||
485 | 603 | self.assertThat(results, MatchesListwise([ | ||
486 | 604 | MatchesDict({ | ||
487 | 605 | 'ref_pattern': Equals('refs/heads/*'), | ||
488 | 606 | 'permissions': Equals(['create', 'push']), | ||
489 | 607 | }), | ||
490 | 608 | MatchesDict({ | ||
491 | 609 | 'ref_pattern': Equals('*'), | ||
492 | 610 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
493 | 611 | }), | ||
494 | 612 | ])) | ||
495 | 613 | |||
496 | 614 | def test_listRefRules_grantee_owner_type(self): | ||
497 | 615 | owner = self.factory.makePerson() | ||
498 | 616 | repository = removeSecurityProxy( | ||
499 | 617 | self.factory.makeGitRepository(owner=owner)) | ||
500 | 618 | rule = self.factory.makeGitRule(repository=repository) | ||
501 | 619 | self.factory.makeGitRuleGrant( | ||
502 | 620 | rule=rule, grantee=GitGranteeType.REPOSITORY_OWNER, | ||
503 | 621 | can_create=True) | ||
504 | 622 | |||
505 | 623 | results = self.git_api.listRefRules( | ||
506 | 624 | repository.getInternalPath(), | ||
507 | 625 | {'uid': owner.id}) | ||
508 | 626 | |||
509 | 627 | self.assertThat(results, MatchesListwise([ | ||
510 | 628 | MatchesDict({ | ||
511 | 629 | 'ref_pattern': Equals('refs/heads/*'), | ||
512 | 630 | 'permissions': Equals(['create']), | ||
513 | 631 | }), | ||
514 | 632 | MatchesDict({ | ||
515 | 633 | 'ref_pattern': Equals('*'), | ||
516 | 634 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
517 | 635 | }), | ||
518 | 636 | ])) | ||
519 | 637 | |||
520 | 638 | def test_listRefRules_grantee_owner_type_and_other_grants(self): | ||
521 | 639 | owner = self.factory.makePerson() | ||
522 | 640 | other_person = self.factory.makePerson() | ||
523 | 641 | repository = removeSecurityProxy( | ||
524 | 642 | self.factory.makeGitRepository(owner=owner)) | ||
525 | 643 | rule = self.factory.makeGitRule(repository=repository) | ||
526 | 644 | self.factory.makeGitRuleGrant( | ||
527 | 645 | rule=rule, grantee=GitGranteeType.REPOSITORY_OWNER, | ||
528 | 646 | can_create=True) | ||
529 | 647 | |||
530 | 648 | rule = self.factory.makeGitRule( | ||
531 | 649 | repository=repository, ref_pattern=u'refs/heads/other') | ||
532 | 650 | self.factory.makeGitRuleGrant( | ||
533 | 651 | rule=rule, grantee=other_person, can_push=True) | ||
534 | 652 | |||
535 | 653 | results = self.git_api.listRefRules( | ||
536 | 654 | repository.getInternalPath(), | ||
537 | 655 | {'uid': owner.id}) | ||
538 | 656 | |||
539 | 657 | self.assertThat(results, MatchesListwise([ | ||
540 | 658 | MatchesDict({ | ||
541 | 659 | 'ref_pattern': Equals('refs/heads/other'), | ||
542 | 660 | 'permissions': Equals(['create', 'push']), | ||
543 | 661 | }), | ||
544 | 662 | MatchesDict({ | ||
545 | 663 | 'ref_pattern': Equals('refs/heads/*'), | ||
546 | 664 | 'permissions': Equals(['create']), | ||
547 | 665 | }), | ||
548 | 666 | MatchesDict({ | ||
549 | 667 | 'ref_pattern': Equals('*'), | ||
550 | 668 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
551 | 669 | }), | ||
552 | 670 | ])) | ||
553 | 671 | |||
554 | 672 | def test_listRefRules_grantee_example_one(self): | ||
556 | 673 | user_a = self.factory.makePerson() | 270 | user_a = self.factory.makePerson() |
557 | 674 | user_b = self.factory.makePerson() | 271 | user_b = self.factory.makePerson() |
558 | 675 | user_c = self.factory.makePerson() | 272 | user_c = self.factory.makePerson() |
559 | @@ -686,6 +283,10 @@ | |||
560 | 686 | can_force_push=True) | 283 | can_force_push=True) |
561 | 687 | 284 | ||
562 | 688 | rule = self.factory.makeGitRule( | 285 | rule = self.factory.makeGitRule( |
563 | 286 | repository, ref_pattern=u'refs/heads/stable/protected') | ||
564 | 287 | self.factory.makeGitRuleGrant(rule=rule, grantee=stable_team) | ||
565 | 288 | |||
566 | 289 | rule = self.factory.makeGitRule( | ||
567 | 689 | repository, ref_pattern=u'refs/heads/archived/*') | 290 | repository, ref_pattern=u'refs/heads/archived/*') |
568 | 690 | self.factory.makeGitRuleGrant( | 291 | self.factory.makeGitRuleGrant( |
569 | 691 | rule=rule, grantee=GitGranteeType.REPOSITORY_OWNER) | 292 | rule=rule, grantee=GitGranteeType.REPOSITORY_OWNER) |
570 | @@ -710,247 +311,158 @@ | |||
571 | 710 | self.factory.makeGitRuleGrant( | 311 | self.factory.makeGitRuleGrant( |
572 | 711 | rule=rule, grantee=stable_team, can_create=True) | 312 | rule=rule, grantee=stable_team, can_create=True) |
573 | 712 | 313 | ||
576 | 713 | results = self.git_api.listRefRules( | 314 | test_ref_paths = [ |
577 | 714 | repository.getInternalPath(), | 315 | 'refs/heads/stable/next', 'refs/heads/stable/protected', |
578 | 316 | 'refs/heads/stable/foo', 'refs/heads/archived/foo', | ||
579 | 317 | 'refs/heads/foo/next', 'refs/heads/unprotected', | ||
580 | 318 | 'refs/tags/1.0', | ||
581 | 319 | ] | ||
582 | 320 | |||
583 | 321 | return (user_a, user_b, user_c, stable_team, next_team, repository, | ||
584 | 322 | test_ref_paths) | ||
585 | 323 | |||
586 | 324 | def test_checkRefPermissions_scenario_one_user_a(self): | ||
587 | 325 | user_a, _, _, _, _, repo, paths = self._make_scenario_one_repository() | ||
588 | 326 | |||
589 | 327 | results = self.git_api.checkRefPermissions( | ||
590 | 328 | repo.getInternalPath(), | ||
591 | 329 | paths, | ||
592 | 715 | {'uid': user_a.id}) | 330 | {'uid': user_a.id}) |
593 | 716 | 331 | ||
662 | 717 | self.assertThat(results, MatchesListwise([ | 332 | self.assertThat(results, MatchesDict({ |
663 | 718 | MatchesDict( | 333 | 'refs/heads/stable/next': Equals(['push', 'force_push']), |
664 | 719 | {'ref_pattern': Equals('refs/heads/stable/next'), | 334 | 'refs/heads/stable/protected': Equals(['create', 'push']), |
665 | 720 | 'permissions': Equals(['push', 'force_push']), | 335 | 'refs/heads/stable/foo': Equals(['create', 'push']), |
666 | 721 | }), | 336 | 'refs/heads/archived/foo': Equals([]), |
667 | 722 | MatchesDict( | 337 | 'refs/heads/foo/next': Equals(['create', 'push']), |
668 | 723 | {'ref_pattern': Equals('refs/heads/archived/*'), | 338 | 'refs/heads/unprotected': Equals(['create', 'push', 'force_push']), |
669 | 724 | 'permissions': Equals([]), | 339 | 'refs/tags/1.0': Equals(['create']), |
670 | 725 | }), | 340 | })) |
671 | 726 | MatchesDict( | 341 | |
672 | 727 | {'ref_pattern': Equals('refs/heads/stable/*'), | 342 | def test_checkRefPermissions_scenario_one_user_b(self): |
673 | 728 | 'permissions': Equals(['create', 'push']), | 343 | _, user_b, _, _, _, repo, paths = self._make_scenario_one_repository() |
674 | 729 | }), | 344 | |
675 | 730 | MatchesDict( | 345 | results = self.git_api.checkRefPermissions( |
676 | 731 | {'ref_pattern': Equals('refs/heads/*/next'), | 346 | repo.getInternalPath(), |
677 | 732 | 'permissions': Equals(['create', 'push']), | 347 | paths, |
610 | 733 | }), | ||
611 | 734 | MatchesDict( | ||
612 | 735 | {'ref_pattern': Equals('refs/tags/*'), | ||
613 | 736 | 'permissions': Equals(['create']), | ||
614 | 737 | }), | ||
615 | 738 | MatchesDict( | ||
616 | 739 | {'ref_pattern': Equals('*'), | ||
617 | 740 | 'permissions': Equals(['create', 'push', 'force_push']), | ||
618 | 741 | }), | ||
619 | 742 | ])) | ||
620 | 743 | |||
621 | 744 | def test_listRefRules_grantee_example_two(self): | ||
622 | 745 | user_a = self.factory.makePerson() | ||
623 | 746 | user_b = self.factory.makePerson() | ||
624 | 747 | user_c = self.factory.makePerson() | ||
625 | 748 | stable_team = self.factory.makeTeam(members=[user_a, user_b]) | ||
626 | 749 | next_team = self.factory.makeTeam(members=[user_b, user_c]) | ||
627 | 750 | |||
628 | 751 | repository = removeSecurityProxy( | ||
629 | 752 | self.factory.makeGitRepository(owner=user_a)) | ||
630 | 753 | |||
631 | 754 | rule = self.factory.makeGitRule( | ||
632 | 755 | repository, ref_pattern=u'refs/heads/stable/next') | ||
633 | 756 | self.factory.makeGitRuleGrant( | ||
634 | 757 | rule=rule, grantee=user_a, can_force_push=True) | ||
635 | 758 | |||
636 | 759 | rule = self.factory.makeGitRule( | ||
637 | 760 | repository, ref_pattern=u'refs/heads/archived/*') | ||
638 | 761 | self.factory.makeGitRuleGrant( | ||
639 | 762 | rule=rule, grantee=user_a) | ||
640 | 763 | self.factory.makeGitRuleGrant( | ||
641 | 764 | rule=rule, grantee=user_b, can_create=True) | ||
642 | 765 | |||
643 | 766 | rule = self.factory.makeGitRule( | ||
644 | 767 | repository, ref_pattern=u'refs/heads/stable/*') | ||
645 | 768 | self.factory.makeGitRuleGrant( | ||
646 | 769 | rule=rule, grantee=stable_team, can_push=True) | ||
647 | 770 | |||
648 | 771 | rule = self.factory.makeGitRule( | ||
649 | 772 | repository, ref_pattern=u'refs/heads/*/next') | ||
650 | 773 | self.factory.makeGitRuleGrant( | ||
651 | 774 | rule=rule, grantee=next_team, can_force_push=True) | ||
652 | 775 | |||
653 | 776 | rule = self.factory.makeGitRule( | ||
654 | 777 | repository, ref_pattern=u'refs/tags/*') | ||
655 | 778 | self.factory.makeGitRuleGrant( | ||
656 | 779 | rule=rule, grantee=user_a, can_create=True) | ||
657 | 780 | self.factory.makeGitRuleGrant( | ||
658 | 781 | rule=rule, grantee=stable_team, can_create=True) | ||
659 | 782 | |||
660 | 783 | results = self.git_api.listRefRules( | ||
661 | 784 | repository.getInternalPath(), | ||
678 | 785 | {'uid': user_b.id}) | 348 | {'uid': user_b.id}) |
679 | 786 | 349 | ||
748 | 787 | self.assertThat(results, MatchesListwise([ | 350 | self.assertThat(results, MatchesDict({ |
749 | 788 | MatchesDict( | 351 | 'refs/heads/stable/next': Equals(['push', 'force_push']), |
750 | 789 | {'ref_pattern': Equals('refs/heads/stable/next'), | 352 | 'refs/heads/stable/protected': Equals([]), |
751 | 790 | 'permissions': Equals([]), | 353 | 'refs/heads/stable/foo': Equals(['push']), |
752 | 791 | }), | 354 | 'refs/heads/archived/foo': Equals(['create']), |
753 | 792 | MatchesDict( | 355 | 'refs/heads/foo/next': Equals(['push', 'force_push']), |
754 | 793 | {'ref_pattern': Equals('refs/heads/archived/*'), | 356 | 'refs/heads/unprotected': Equals([]), |
755 | 794 | 'permissions': Equals(['create']), | 357 | 'refs/tags/1.0': Equals(['create']), |
756 | 795 | }), | 358 | })) |
757 | 796 | MatchesDict( | 359 | |
758 | 797 | {'ref_pattern': Equals('refs/heads/stable/*'), | 360 | def test_checkRefPermissions_scenario_one_user_c(self): |
759 | 798 | 'permissions': Equals(['push']), | 361 | _, _, user_c, _, _, repo, paths = self._make_scenario_one_repository() |
760 | 799 | }), | 362 | |
761 | 800 | MatchesDict( | 363 | results = self.git_api.checkRefPermissions( |
762 | 801 | {'ref_pattern': Equals('refs/heads/*/next'), | 364 | repo.getInternalPath(), |
763 | 802 | 'permissions': Equals(['push', 'force_push']), | 365 | paths, |
696 | 803 | }), | ||
697 | 804 | MatchesDict( | ||
698 | 805 | {'ref_pattern': Equals('refs/tags/*'), | ||
699 | 806 | 'permissions': Equals(['create']), | ||
700 | 807 | }), | ||
701 | 808 | MatchesDict( | ||
702 | 809 | {'ref_pattern': Equals('*'), | ||
703 | 810 | 'permissions': Equals([]), | ||
704 | 811 | }), | ||
705 | 812 | ])) | ||
706 | 813 | |||
707 | 814 | def test_listRefRules_grantee_example_three(self): | ||
708 | 815 | user_a = self.factory.makePerson() | ||
709 | 816 | user_b = self.factory.makePerson() | ||
710 | 817 | user_c = self.factory.makePerson() | ||
711 | 818 | stable_team = self.factory.makeTeam(members=[user_a, user_b]) | ||
712 | 819 | next_team = self.factory.makeTeam(members=[user_b, user_c]) | ||
713 | 820 | |||
714 | 821 | repository = removeSecurityProxy( | ||
715 | 822 | self.factory.makeGitRepository(owner=user_a)) | ||
716 | 823 | |||
717 | 824 | rule = self.factory.makeGitRule( | ||
718 | 825 | repository, ref_pattern=u'refs/heads/stable/next') | ||
719 | 826 | self.factory.makeGitRuleGrant( | ||
720 | 827 | rule=rule, grantee=user_a, can_force_push=True) | ||
721 | 828 | |||
722 | 829 | rule = self.factory.makeGitRule( | ||
723 | 830 | repository, ref_pattern=u'refs/heads/archived/*') | ||
724 | 831 | self.factory.makeGitRuleGrant( | ||
725 | 832 | rule=rule, grantee=user_a) | ||
726 | 833 | self.factory.makeGitRuleGrant( | ||
727 | 834 | rule=rule, grantee=user_b, can_create=True) | ||
728 | 835 | |||
729 | 836 | rule = self.factory.makeGitRule( | ||
730 | 837 | repository, ref_pattern=u'refs/heads/stable/*') | ||
731 | 838 | self.factory.makeGitRuleGrant( | ||
732 | 839 | rule=rule, grantee=stable_team, can_push=True) | ||
733 | 840 | |||
734 | 841 | rule = self.factory.makeGitRule( | ||
735 | 842 | repository, ref_pattern=u'refs/heads/*/next') | ||
736 | 843 | self.factory.makeGitRuleGrant( | ||
737 | 844 | rule=rule, grantee=next_team, can_force_push=True) | ||
738 | 845 | |||
739 | 846 | rule = self.factory.makeGitRule( | ||
740 | 847 | repository, ref_pattern=u'refs/tags/*') | ||
741 | 848 | self.factory.makeGitRuleGrant( | ||
742 | 849 | rule=rule, grantee=user_a, can_create=True) | ||
743 | 850 | self.factory.makeGitRuleGrant( | ||
744 | 851 | rule=rule, grantee=stable_team, can_create=True) | ||
745 | 852 | |||
746 | 853 | results = self.git_api.listRefRules( | ||
747 | 854 | repository.getInternalPath(), | ||
764 | 855 | {'uid': user_c.id}) | 366 | {'uid': user_c.id}) |
765 | 856 | 367 | ||
792 | 857 | self.assertThat(results, MatchesListwise([ | 368 | self.assertThat(results, MatchesDict({ |
793 | 858 | MatchesDict( | 369 | 'refs/heads/stable/next': Equals(['push', 'force_push']), |
794 | 859 | {'ref_pattern': Equals('refs/heads/stable/next'), | 370 | 'refs/heads/stable/protected': Equals([]), |
795 | 860 | 'permissions': Equals([]), | 371 | 'refs/heads/stable/foo': Equals([]), |
796 | 861 | }), | 372 | 'refs/heads/archived/foo': Equals([]), |
797 | 862 | MatchesDict( | 373 | 'refs/heads/foo/next': Equals(['push', 'force_push']), |
798 | 863 | {'ref_pattern': Equals('refs/heads/archived/*'), | 374 | 'refs/heads/unprotected': Equals([]), |
799 | 864 | 'permissions': Equals([]), | 375 | 'refs/tags/1.0': Equals([]), |
800 | 865 | }), | 376 | })) |
775 | 866 | MatchesDict( | ||
776 | 867 | {'ref_pattern': Equals('refs/heads/stable/*'), | ||
777 | 868 | 'permissions': Equals([]), | ||
778 | 869 | }), | ||
779 | 870 | MatchesDict( | ||
780 | 871 | {'ref_pattern': Equals('refs/heads/*/next'), | ||
781 | 872 | 'permissions': Equals(['push', 'force_push']), | ||
782 | 873 | }), | ||
783 | 874 | MatchesDict( | ||
784 | 875 | {'ref_pattern': Equals('refs/tags/*'), | ||
785 | 876 | 'permissions': Equals([]), | ||
786 | 877 | }), | ||
787 | 878 | MatchesDict( | ||
788 | 879 | {'ref_pattern': Equals('*'), | ||
789 | 880 | 'permissions': Equals([]), | ||
790 | 881 | }), | ||
791 | 882 | ])) | ||
801 | 883 | 377 | ||
806 | 884 | def test_listRefRules_grantee_example_four(self): | 378 | def test_checkRefPermissions_scenario_one_user_d(self): |
803 | 885 | user_a = self.factory.makePerson() | ||
804 | 886 | user_b = self.factory.makePerson() | ||
805 | 887 | user_c = self.factory.makePerson() | ||
807 | 888 | user_d = self.factory.makePerson() | 379 | user_d = self.factory.makePerson() |
845 | 889 | stable_team = self.factory.makeTeam(members=[user_a, user_b]) | 380 | _, _, user_c, _, _, repo, paths = self._make_scenario_one_repository() |
846 | 890 | next_team = self.factory.makeTeam(members=[user_b, user_c]) | 381 | |
847 | 891 | 382 | results = self.git_api.checkRefPermissions( | |
848 | 892 | repository = removeSecurityProxy( | 383 | repo.getInternalPath(), |
849 | 893 | self.factory.makeGitRepository(owner=user_a)) | 384 | paths, |
813 | 894 | |||
814 | 895 | rule = self.factory.makeGitRule( | ||
815 | 896 | repository, ref_pattern=u'refs/heads/stable/next') | ||
816 | 897 | self.factory.makeGitRuleGrant( | ||
817 | 898 | rule=rule, grantee=user_a, can_force_push=True) | ||
818 | 899 | |||
819 | 900 | rule = self.factory.makeGitRule( | ||
820 | 901 | repository, ref_pattern=u'refs/heads/archived/*') | ||
821 | 902 | self.factory.makeGitRuleGrant( | ||
822 | 903 | rule=rule, grantee=user_a) | ||
823 | 904 | self.factory.makeGitRuleGrant( | ||
824 | 905 | rule=rule, grantee=user_b, can_create=True) | ||
825 | 906 | |||
826 | 907 | rule = self.factory.makeGitRule( | ||
827 | 908 | repository, ref_pattern=u'refs/heads/stable/*') | ||
828 | 909 | self.factory.makeGitRuleGrant( | ||
829 | 910 | rule=rule, grantee=stable_team, can_push=True) | ||
830 | 911 | |||
831 | 912 | rule = self.factory.makeGitRule( | ||
832 | 913 | repository, ref_pattern=u'refs/heads/*/next') | ||
833 | 914 | self.factory.makeGitRuleGrant( | ||
834 | 915 | rule=rule, grantee=next_team, can_force_push=True) | ||
835 | 916 | |||
836 | 917 | rule = self.factory.makeGitRule( | ||
837 | 918 | repository, ref_pattern=u'refs/tags/*') | ||
838 | 919 | self.factory.makeGitRuleGrant( | ||
839 | 920 | rule=rule, grantee=user_a, can_create=True) | ||
840 | 921 | self.factory.makeGitRuleGrant( | ||
841 | 922 | rule=rule, grantee=stable_team, can_create=True) | ||
842 | 923 | |||
843 | 924 | results = self.git_api.listRefRules( | ||
844 | 925 | repository.getInternalPath(), | ||
850 | 926 | {'uid': user_d.id}) | 385 | {'uid': user_d.id}) |
851 | 927 | 386 | ||
878 | 928 | self.assertThat(results, MatchesListwise([ | 387 | self.assertThat(results, MatchesDict({ |
879 | 929 | MatchesDict( | 388 | 'refs/heads/stable/next': Equals([]), |
880 | 930 | {'ref_pattern': Equals('refs/heads/stable/next'), | 389 | 'refs/heads/stable/protected': Equals([]), |
881 | 931 | 'permissions': Equals([]), | 390 | 'refs/heads/stable/foo': Equals([]), |
882 | 932 | }), | 391 | 'refs/heads/archived/foo': Equals([]), |
883 | 933 | MatchesDict( | 392 | 'refs/heads/foo/next': Equals([]), |
884 | 934 | {'ref_pattern': Equals('refs/heads/archived/*'), | 393 | 'refs/heads/unprotected': Equals([]), |
885 | 935 | 'permissions': Equals([]), | 394 | 'refs/tags/1.0': Equals([]), |
886 | 936 | }), | 395 | })) |
887 | 937 | MatchesDict( | 396 | |
888 | 938 | {'ref_pattern': Equals('refs/heads/stable/*'), | 397 | def _make_scenario_two_repository(self): |
889 | 939 | 'permissions': Equals([]), | 398 | user_a = self.factory.makePerson() |
890 | 940 | }), | 399 | user_b = self.factory.makePerson() |
891 | 941 | MatchesDict( | 400 | |
892 | 942 | {'ref_pattern': Equals('refs/heads/*/next'), | 401 | repository = removeSecurityProxy( |
893 | 943 | 'permissions': Equals([]), | 402 | self.factory.makeGitRepository(owner=user_a)) |
894 | 944 | }), | 403 | |
895 | 945 | MatchesDict( | 404 | rule = self.factory.makeGitRule( |
896 | 946 | {'ref_pattern': Equals('refs/tags/*'), | 405 | repository, ref_pattern=u'refs/heads/master') |
897 | 947 | 'permissions': Equals([]), | 406 | self.factory.makeGitRuleGrant( |
898 | 948 | }), | 407 | rule=rule, grantee=user_b, can_push=True) |
899 | 949 | MatchesDict( | 408 | |
900 | 950 | {'ref_pattern': Equals('*'), | 409 | rule = self.factory.makeGitRule( |
901 | 951 | 'permissions': Equals([]), | 410 | repository, ref_pattern=u'refs/heads/*') |
902 | 952 | }), | 411 | self.factory.makeGitRuleGrant( |
903 | 953 | ])) | 412 | rule=rule, grantee=GitGranteeType.REPOSITORY_OWNER, |
904 | 413 | can_create=True, can_push=True, can_force_push=True) | ||
905 | 414 | |||
906 | 415 | rule = self.factory.makeGitRule( | ||
907 | 416 | repository, ref_pattern=u'refs/tags/*') | ||
908 | 417 | self.factory.makeGitRuleGrant( | ||
909 | 418 | rule=rule, grantee=user_b, can_push=True) | ||
910 | 419 | |||
911 | 420 | test_ref_paths = ['refs/heads/master', 'refs/heads/foo', | ||
912 | 421 | 'refs/tags/1.0', 'refs/other'] | ||
913 | 422 | return user_a, user_b, repository, test_ref_paths | ||
914 | 423 | |||
915 | 424 | def test_checkRefPermissions_scenario_two_user_a(self): | ||
916 | 425 | user_a, _, repo, paths = self._make_scenario_two_repository() | ||
917 | 426 | results = self.git_api.checkRefPermissions( | ||
918 | 427 | repo.getInternalPath(), | ||
919 | 428 | paths, | ||
920 | 429 | {'uid': user_a.id}) | ||
921 | 430 | |||
922 | 431 | self.assertThat(results, MatchesDict({ | ||
923 | 432 | 'refs/heads/master': Equals(['create', 'push', 'force_push']), | ||
924 | 433 | 'refs/heads/foo': Equals(['create', 'push', 'force_push']), | ||
925 | 434 | 'refs/tags/1.0': Equals(['create', 'push']), | ||
926 | 435 | 'refs/other': Equals(['create', 'push', 'force_push']), | ||
927 | 436 | })) | ||
928 | 437 | |||
929 | 438 | def test_checkRefPermissions_scenario_two_user_b(self): | ||
930 | 439 | _, user_b, repo, paths = self._make_scenario_two_repository() | ||
931 | 440 | results = self.git_api.checkRefPermissions( | ||
932 | 441 | repo.getInternalPath(), | ||
933 | 442 | paths, | ||
934 | 443 | {'uid': user_b.id}) | ||
935 | 444 | |||
936 | 445 | self.assertThat(results, MatchesDict({ | ||
937 | 446 | 'refs/heads/master': Equals(['push']), | ||
938 | 447 | 'refs/heads/foo': Equals([]), | ||
939 | 448 | 'refs/tags/1.0': Equals(['push']), | ||
940 | 449 | 'refs/other': Equals([]), | ||
941 | 450 | })) | ||
942 | 451 | |||
943 | 452 | def test_checkRefPermissions_scenario_two_user_c(self): | ||
944 | 453 | _, _, repo, paths = self._make_scenario_two_repository() | ||
945 | 454 | user_c = self.factory.makePerson() | ||
946 | 455 | results = self.git_api.checkRefPermissions( | ||
947 | 456 | repo.getInternalPath(), | ||
948 | 457 | paths, | ||
949 | 458 | {'uid': user_c.id}) | ||
950 | 459 | |||
951 | 460 | self.assertThat(results, MatchesDict({ | ||
952 | 461 | 'refs/heads/master': Equals([]), | ||
953 | 462 | 'refs/heads/foo': Equals([]), | ||
954 | 463 | 'refs/tags/1.0': Equals([]), | ||
955 | 464 | 'refs/other': Equals([]), | ||
956 | 465 | })) | ||
957 | 954 | 466 | ||
958 | 955 | 467 | ||
959 | 956 | class TestGitAPI(TestGitAPIMixin, TestCaseWithFactory): | 468 | class TestGitAPI(TestGitAPIMixin, TestCaseWithFactory): |
Just a few minor tweaks, but otherwise this looks good and we can land it.