@@ -36,8 +36,8 @@ func TestOwnerExec(t *testing.T) {
36
36
37
37
auth := rbac .NewCachingAuthorizer (prometheus .NewRegistry ())
38
38
// Exec a random workspace
39
- err := auth .Authorize (context .Background (),owner ,policy .ActionCreate ,
40
- rbac .ResourceWorkspaceExecution .WithID (uuid .New ()).InOrg (uuid .New ()).WithOwner (uuid .NewString ()))
39
+ err := auth .Authorize (context .Background (),owner ,policy .ActionSSH ,
40
+ rbac .ResourceWorkspace .WithID (uuid .New ()).InOrg (uuid .New ()).WithOwner (uuid .NewString ()))
41
41
require .ErrorAsf (t ,err ,& rbac.UnauthorizedError {},"expected unauthorized error" )
42
42
})
43
43
@@ -50,8 +50,8 @@ func TestOwnerExec(t *testing.T) {
50
50
auth := rbac .NewCachingAuthorizer (prometheus .NewRegistry ())
51
51
52
52
// Exec a random workspace
53
- err := auth .Authorize (context .Background (),owner ,policy .ActionCreate ,
54
- rbac .ResourceWorkspaceExecution .WithID (uuid .New ()).InOrg (uuid .New ()).WithOwner (uuid .NewString ()))
53
+ err := auth .Authorize (context .Background (),owner ,policy .ActionSSH ,
54
+ rbac .ResourceWorkspace .WithID (uuid .New ()).InOrg (uuid .New ()).WithOwner (uuid .NewString ()))
55
55
require .NoError (t ,err ,"expected owner can" )
56
56
})
57
57
}
@@ -60,6 +60,8 @@ func TestOwnerExec(t *testing.T) {
60
60
func TestRolePermissions (t * testing.T ) {
61
61
t .Parallel ()
62
62
63
+ crud := []policy.Action {policy .ActionCreate ,policy .ActionRead ,policy .ActionUpdate ,policy .ActionDelete }
64
+
63
65
auth := rbac .NewCachingAuthorizer (prometheus .NewRegistry ())
64
66
65
67
// currentUser is anything that references "me", "mine", or "my".
@@ -145,8 +147,8 @@ func TestRolePermissions(t *testing.T) {
145
147
{
146
148
Name :"MyWorkspaceInOrgExecution" ,
147
149
// When creating the WithID won't be set, but it does not change the result.
148
- Actions : []policy.Action {policy .ActionCreate , policy . ActionRead , policy . ActionUpdate , policy . ActionDelete },
149
- Resource :rbac .ResourceWorkspaceExecution .WithID (workspaceID ).InOrg (orgID ).WithOwner (currentUser .String ()),
150
+ Actions : []policy.Action {policy .ActionSSH },
151
+ Resource :rbac .ResourceWorkspace .WithID (workspaceID ).InOrg (orgID ).WithOwner (currentUser .String ()),
150
152
AuthorizeMap :map [bool ][]authSubject {
151
153
true : {owner ,orgMemberMe },
152
154
false : {orgAdmin ,memberMe ,otherOrgAdmin ,otherOrgMember ,templateAdmin ,userAdmin },
@@ -155,16 +157,16 @@ func TestRolePermissions(t *testing.T) {
155
157
{
156
158
Name :"MyWorkspaceInOrgAppConnect" ,
157
159
// When creating the WithID won't be set, but it does not change the result.
158
- Actions : []policy.Action {policy .ActionCreate , policy . ActionRead , policy . ActionUpdate , policy . ActionDelete },
159
- Resource :rbac .ResourceWorkspaceApplicationConnect .WithID (workspaceID ).InOrg (orgID ).WithOwner (currentUser .String ()),
160
+ Actions : []policy.Action {policy .ActionApplicationConnect },
161
+ Resource :rbac .ResourceWorkspace .WithID (workspaceID ).InOrg (orgID ).WithOwner (currentUser .String ()),
160
162
AuthorizeMap :map [bool ][]authSubject {
161
- true : {owner ,orgAdmin , orgMemberMe },
162
- false : {memberMe ,otherOrgAdmin ,otherOrgMember ,templateAdmin ,userAdmin },
163
+ true : {owner ,orgMemberMe },
164
+ false : {memberMe ,otherOrgAdmin ,otherOrgMember ,templateAdmin ,userAdmin , orgAdmin },
163
165
},
164
166
},
165
167
{
166
168
Name :"Templates" ,
167
- Actions : []policy.Action {policy .ActionCreate ,policy .ActionUpdate ,policy .ActionDelete },
169
+ Actions : []policy.Action {policy .ActionCreate ,policy .ActionUpdate ,policy .ActionDelete , policy . ActionViewInsights },
168
170
Resource :rbac .ResourceTemplate .WithID (templateID ).InOrg (orgID ),
169
171
AuthorizeMap :map [bool ][]authSubject {
170
172
true : {owner ,orgAdmin ,templateAdmin },
@@ -191,7 +193,7 @@ func TestRolePermissions(t *testing.T) {
191
193
},
192
194
{
193
195
Name :"MyFile" ,
194
- Actions : []policy.Action {policy .ActionCreate ,policy .ActionRead , policy . ActionUpdate , policy . ActionDelete },
196
+ Actions : []policy.Action {policy .ActionCreate ,policy .ActionRead },
195
197
Resource :rbac .ResourceFile .WithID (fileID ).WithOwner (currentUser .String ()),
196
198
AuthorizeMap :map [bool ][]authSubject {
197
199
true : {owner ,memberMe ,orgMemberMe ,templateAdmin },
@@ -227,8 +229,8 @@ func TestRolePermissions(t *testing.T) {
227
229
},
228
230
{
229
231
Name :"RoleAssignment" ,
230
- Actions : []policy.Action {policy .ActionCreate , policy . ActionUpdate ,policy .ActionDelete },
231
- Resource :rbac .ResourceRoleAssignment ,
232
+ Actions : []policy.Action {policy .ActionAssign ,policy .ActionDelete },
233
+ Resource :rbac .ResourceAssignRole ,
232
234
AuthorizeMap :map [bool ][]authSubject {
233
235
true : {owner ,userAdmin },
234
236
false : {orgAdmin ,orgMemberMe ,otherOrgAdmin ,otherOrgMember ,memberMe ,templateAdmin },
@@ -237,16 +239,16 @@ func TestRolePermissions(t *testing.T) {
237
239
{
238
240
Name :"ReadRoleAssignment" ,
239
241
Actions : []policy.Action {policy .ActionRead },
240
- Resource :rbac .ResourceRoleAssignment ,
242
+ Resource :rbac .ResourceAssignRole ,
241
243
AuthorizeMap :map [bool ][]authSubject {
242
244
true : {owner ,orgAdmin ,orgMemberMe ,otherOrgAdmin ,otherOrgMember ,memberMe ,templateAdmin ,userAdmin },
243
245
false : {},
244
246
},
245
247
},
246
248
{
247
249
Name :"OrgRoleAssignment" ,
248
- Actions : []policy.Action {policy .ActionCreate , policy . ActionUpdate ,policy .ActionDelete },
249
- Resource :rbac .ResourceOrgRoleAssignment .InOrg (orgID ),
250
+ Actions : []policy.Action {policy .ActionAssign ,policy .ActionDelete },
251
+ Resource :rbac .ResourceAssignOrgRole .InOrg (orgID ),
250
252
AuthorizeMap :map [bool ][]authSubject {
251
253
true : {owner ,orgAdmin },
252
254
false : {orgMemberMe ,otherOrgAdmin ,otherOrgMember ,memberMe ,templateAdmin ,userAdmin },
@@ -255,7 +257,7 @@ func TestRolePermissions(t *testing.T) {
255
257
{
256
258
Name :"ReadOrgRoleAssignment" ,
257
259
Actions : []policy.Action {policy .ActionRead },
258
- Resource :rbac .ResourceOrgRoleAssignment .InOrg (orgID ),
260
+ Resource :rbac .ResourceAssignOrgRole .InOrg (orgID ),
259
261
AuthorizeMap :map [bool ][]authSubject {
260
262
true : {owner ,orgAdmin ,orgMemberMe },
261
263
false : {otherOrgAdmin ,otherOrgMember ,memberMe ,templateAdmin ,userAdmin },
@@ -264,16 +266,16 @@ func TestRolePermissions(t *testing.T) {
264
266
{
265
267
Name :"APIKey" ,
266
268
Actions : []policy.Action {policy .ActionCreate ,policy .ActionRead ,policy .ActionUpdate ,policy .ActionDelete },
267
- Resource :rbac .ResourceAPIKey .WithID (apiKeyID ).WithOwner (currentUser .String ()),
269
+ Resource :rbac .ResourceApiKey .WithID (apiKeyID ).WithOwner (currentUser .String ()),
268
270
AuthorizeMap :map [bool ][]authSubject {
269
271
true : {owner ,orgMemberMe ,memberMe },
270
272
false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,templateAdmin ,userAdmin },
271
273
},
272
274
},
273
275
{
274
276
Name :"UserData" ,
275
- Actions : []policy.Action {policy .ActionCreate ,policy .ActionRead , policy . ActionUpdate , policy . ActionDelete },
276
- Resource :rbac .ResourceUserData . WithID (currentUser ). WithOwner ( currentUser . String () ),
277
+ Actions : []policy.Action {policy .ActionReadPersonal ,policy .ActionUpdatePersonal },
278
+ Resource :rbac .ResourceUserObject (currentUser ),
277
279
AuthorizeMap :map [bool ][]authSubject {
278
280
true : {owner ,orgMemberMe ,memberMe ,userAdmin },
279
281
false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,templateAdmin },
@@ -312,6 +314,15 @@ func TestRolePermissions(t *testing.T) {
312
314
},
313
315
{
314
316
Name :"Groups" ,
317
+ Actions : []policy.Action {policy .ActionCreate ,policy .ActionDelete ,policy .ActionUpdate },
318
+ Resource :rbac .ResourceGroup .WithID (groupID ).InOrg (orgID ),
319
+ AuthorizeMap :map [bool ][]authSubject {
320
+ true : {owner ,orgAdmin ,userAdmin },
321
+ false : {memberMe ,otherOrgAdmin ,orgMemberMe ,otherOrgMember ,templateAdmin },
322
+ },
323
+ },
324
+ {
325
+ Name :"GroupsRead" ,
315
326
Actions : []policy.Action {policy .ActionRead },
316
327
Resource :rbac .ResourceGroup .WithID (groupID ).InOrg (orgID ),
317
328
AuthorizeMap :map [bool ][]authSubject {
@@ -330,19 +341,183 @@ func TestRolePermissions(t *testing.T) {
330
341
},
331
342
{
332
343
Name :"WorkspaceBuild" ,
333
- Actions :rbac . AllActions () ,
334
- Resource :rbac .ResourceWorkspaceBuild .WithID (uuid .New ()).InOrg (orgID ).WithOwner (memberMe .Actor .ID ),
344
+ Actions :[]policy. Action { policy . ActionWorkspaceBuild } ,
345
+ Resource :rbac .ResourceWorkspace .WithID (uuid .New ()).InOrg (orgID ).WithOwner (memberMe .Actor .ID ),
335
346
AuthorizeMap :map [bool ][]authSubject {
336
347
true : {owner ,orgAdmin ,orgMemberMe },
337
348
false : {userAdmin ,otherOrgAdmin ,otherOrgMember ,templateAdmin ,memberMe },
338
349
},
339
350
},
351
+ // Some admin style resources
352
+ {
353
+ Name :"Licences" ,
354
+ Actions : []policy.Action {policy .ActionCreate ,policy .ActionRead ,policy .ActionDelete },
355
+ Resource :rbac .ResourceLicense ,
356
+ AuthorizeMap :map [bool ][]authSubject {
357
+ true : {owner },
358
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
359
+ },
360
+ },
361
+ {
362
+ Name :"DeploymentStats" ,
363
+ Actions : []policy.Action {policy .ActionRead },
364
+ Resource :rbac .ResourceDeploymentStats ,
365
+ AuthorizeMap :map [bool ][]authSubject {
366
+ true : {owner },
367
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
368
+ },
369
+ },
370
+ {
371
+ Name :"DeploymentConfig" ,
372
+ Actions : []policy.Action {policy .ActionRead },
373
+ Resource :rbac .ResourceDeploymentConfig ,
374
+ AuthorizeMap :map [bool ][]authSubject {
375
+ true : {owner },
376
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
377
+ },
378
+ },
379
+ {
380
+ Name :"DebugInfo" ,
381
+ Actions : []policy.Action {policy .ActionUse },
382
+ Resource :rbac .ResourceDebugInfo ,
383
+ AuthorizeMap :map [bool ][]authSubject {
384
+ true : {owner },
385
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
386
+ },
387
+ },
388
+ {
389
+ Name :"Replicas" ,
390
+ Actions : []policy.Action {policy .ActionRead },
391
+ Resource :rbac .ResourceReplicas ,
392
+ AuthorizeMap :map [bool ][]authSubject {
393
+ true : {owner },
394
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
395
+ },
396
+ },
397
+ {
398
+ Name :"TailnetCoordinator" ,
399
+ Actions :crud ,
400
+ Resource :rbac .ResourceTailnetCoordinator ,
401
+ AuthorizeMap :map [bool ][]authSubject {
402
+ true : {owner },
403
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
404
+ },
405
+ },
406
+ {
407
+ Name :"AuditLogs" ,
408
+ Actions : []policy.Action {policy .ActionRead },
409
+ Resource :rbac .ResourceAuditLog ,
410
+ AuthorizeMap :map [bool ][]authSubject {
411
+ true : {owner },
412
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
413
+ },
414
+ },
415
+ {
416
+ Name :"ProvisionerDaemons" ,
417
+ Actions : []policy.Action {policy .ActionCreate ,policy .ActionUpdate ,policy .ActionDelete },
418
+ Resource :rbac .ResourceProvisionerDaemon .InOrg (orgID ),
419
+ AuthorizeMap :map [bool ][]authSubject {
420
+ true : {owner ,templateAdmin ,orgAdmin },
421
+ false : {otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,userAdmin },
422
+ },
423
+ },
424
+ {
425
+ Name :"ProvisionerDaemonsRead" ,
426
+ Actions : []policy.Action {policy .ActionRead },
427
+ Resource :rbac .ResourceProvisionerDaemon .InOrg (orgID ),
428
+ AuthorizeMap :map [bool ][]authSubject {
429
+ // This should be fixed when multi-org goes live
430
+ true : {owner ,templateAdmin ,orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,userAdmin },
431
+ false : {},
432
+ },
433
+ },
434
+ {
435
+ Name :"UserProvisionerDaemons" ,
436
+ Actions : []policy.Action {policy .ActionCreate ,policy .ActionUpdate ,policy .ActionDelete },
437
+ Resource :rbac .ResourceProvisionerDaemon .WithOwner (currentUser .String ()).InOrg (orgID ),
438
+ AuthorizeMap :map [bool ][]authSubject {
439
+ true : {owner ,templateAdmin ,orgMemberMe ,orgAdmin },
440
+ false : {memberMe ,otherOrgAdmin ,otherOrgMember ,userAdmin },
441
+ },
442
+ },
443
+ {
444
+ Name :"System" ,
445
+ Actions :crud ,
446
+ Resource :rbac .ResourceSystem ,
447
+ AuthorizeMap :map [bool ][]authSubject {
448
+ true : {owner },
449
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
450
+ },
451
+ },
452
+ {
453
+ Name :"Oauth2App" ,
454
+ Actions : []policy.Action {policy .ActionCreate ,policy .ActionUpdate ,policy .ActionDelete },
455
+ Resource :rbac .ResourceOauth2App ,
456
+ AuthorizeMap :map [bool ][]authSubject {
457
+ true : {owner },
458
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
459
+ },
460
+ },
461
+ {
462
+ Name :"Oauth2AppRead" ,
463
+ Actions : []policy.Action {policy .ActionRead },
464
+ Resource :rbac .ResourceOauth2App ,
465
+ AuthorizeMap :map [bool ][]authSubject {
466
+ true : {owner ,orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
467
+ false : {},
468
+ },
469
+ },
470
+ {
471
+ Name :"Oauth2AppSecret" ,
472
+ Actions :crud ,
473
+ Resource :rbac .ResourceOauth2AppSecret ,
474
+ AuthorizeMap :map [bool ][]authSubject {
475
+ true : {owner },
476
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
477
+ },
478
+ },
479
+ {
480
+ Name :"Oauth2Token" ,
481
+ Actions :crud ,
482
+ Resource :rbac .ResourceOauth2AppCodeToken ,
483
+ AuthorizeMap :map [bool ][]authSubject {
484
+ true : {owner },
485
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
486
+ },
487
+ },
488
+ {
489
+ Name :"WorkspaceProxy" ,
490
+ Actions : []policy.Action {policy .ActionCreate ,policy .ActionUpdate ,policy .ActionDelete },
491
+ Resource :rbac .ResourceWorkspaceProxy ,
492
+ AuthorizeMap :map [bool ][]authSubject {
493
+ true : {owner },
494
+ false : {orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
495
+ },
496
+ },
497
+ {
498
+ Name :"WorkspaceProxyRead" ,
499
+ Actions : []policy.Action {policy .ActionRead },
500
+ Resource :rbac .ResourceWorkspaceProxy ,
501
+ AuthorizeMap :map [bool ][]authSubject {
502
+ true : {owner ,orgAdmin ,otherOrgAdmin ,otherOrgMember ,memberMe ,orgMemberMe ,templateAdmin ,userAdmin },
503
+ false : {},
504
+ },
505
+ },
506
+ }
507
+
508
+ // We expect every permission to be tested above.
509
+ remainingPermissions := make (map [string ]map [policy.Action ]bool )
510
+ for rtype ,perms := range policy .RBACPermissions {
511
+ remainingPermissions [rtype ]= make (map [policy.Action ]bool )
512
+ for action := range perms .Actions {
513
+ remainingPermissions [rtype ][action ]= true
514
+ }
340
515
}
341
516
342
517
for _ ,c := range testCases {
343
518
c := c
519
+ // nolint:tparallel -- These share the same remainingPermissions map
344
520
t .Run (c .Name ,func (t * testing.T ) {
345
- t .Parallel ()
346
521
remainingSubjs := make (map [string ]struct {})
347
522
for _ ,subj := range requiredSubjects {
348
523
remainingSubjs [subj .Name ]= struct {}{}
@@ -359,6 +534,8 @@ func TestRolePermissions(t *testing.T) {
359
534
if actor .Scope == nil {
360
535
actor .Scope = rbac .ScopeAll
361
536
}
537
+
538
+ delete (remainingPermissions [c .Resource .Type ],action )
362
539
err := auth .Authorize (context .Background (),actor ,action ,c .Resource )
363
540
if result {
364
541
assert .NoError (t ,err ,fmt .Sprintf ("Should pass: %s" ,msg ))
@@ -371,6 +548,15 @@ func TestRolePermissions(t *testing.T) {
371
548
require .Empty (t ,remainingSubjs ,"test should cover all subjects" )
372
549
})
373
550
}
551
+
552
+ for rtype ,v := range remainingPermissions {
553
+ // nolint:tparallel -- Making a subtest for easier diagnosing failures.
554
+ t .Run (fmt .Sprintf ("%s-AllActions" ,rtype ),func (t * testing.T ) {
555
+ if len (v )> 0 {
556
+ assert .Equal (t ,map [policy.Action ]bool {},v ,"remaining permissions should be empty for type %q" ,rtype )
557
+ }
558
+ })
559
+ }
374
560
}
375
561
376
562
func TestIsOrgRole (t * testing.T ) {