@@ -326,13 +326,20 @@ func TestCustomOrganizationRole(t *testing.T) {
326
326
},
327
327
})
328
328
329
- orgAdmin ,_ := coderdtest .CreateAnotherUser (t ,owner ,first .OrganizationID ,rbac .ScopedRoleOrgAdmin (first .OrganizationID ))
329
+ orgAdmin ,orgAdminUser := coderdtest .CreateAnotherUser (t ,owner ,first .OrganizationID ,rbac .ScopedRoleOrgAdmin (first .OrganizationID ))
330
330
ctx := testutil .Context (t ,testutil .WaitMedium )
331
331
332
- //nolint:gocritic // owner is required for this
333
- createdRole ,err := orgAdmin .PatchOrganizationRole (ctx ,first .OrganizationID ,templateAdminCustom (first .OrganizationID ))
332
+ createdRole ,err := orgAdmin .PatchOrganizationRole (ctx ,templateAdminCustom (first .OrganizationID ))
334
333
require .NoError (t ,err ,"upsert role" )
335
334
335
+ //nolint:gocritic // org_admin cannot assign to themselves
336
+ _ ,err = owner .UpdateOrganizationMemberRoles (ctx ,first .OrganizationID ,orgAdminUser .ID .String (), codersdk.UpdateRoles {
337
+ // Give the user this custom role, to ensure when it is deleted, the user
338
+ // is ok to be used.
339
+ Roles : []string {createdRole .Name ,rbac .ScopedRoleOrgAdmin (first .OrganizationID ).Name },
340
+ })
341
+ require .NoError (t ,err ,"assign custom role to user" )
342
+
336
343
existingRoles ,err := orgAdmin .ListOrganizationRoles (ctx ,first .OrganizationID )
337
344
require .NoError (t ,err )
338
345
@@ -352,6 +359,75 @@ func TestCustomOrganizationRole(t *testing.T) {
352
359
return role .Name == createdRole .Name
353
360
})
354
361
require .False (t ,exists ,"custom role should be deleted" )
362
+
363
+ // Verify you can still assign roles.
364
+ // There used to be a bug that if a member had a delete role, they
365
+ // could not be assigned roles anymore.
366
+ //nolint:gocritic // org_admin cannot assign to themselves
367
+ _ ,err = owner .UpdateOrganizationMemberRoles (ctx ,first .OrganizationID ,orgAdminUser .ID .String (), codersdk.UpdateRoles {
368
+ Roles : []string {rbac .ScopedRoleOrgAdmin (first .OrganizationID ).Name },
369
+ })
370
+ require .NoError (t ,err )
371
+ })
372
+
373
+ // Verify deleting a custom role cascades to all members
374
+ t .Run ("DeleteRoleCascadeMembers" ,func (t * testing.T ) {
375
+ t .Parallel ()
376
+ dv := coderdtest .DeploymentValues (t )
377
+ dv .Experiments = []string {string (codersdk .ExperimentCustomRoles )}
378
+ owner ,first := coderdenttest .New (t ,& coderdenttest.Options {
379
+ Options :& coderdtest.Options {
380
+ DeploymentValues :dv ,
381
+ },
382
+ LicenseOptions :& coderdenttest.LicenseOptions {
383
+ Features : license.Features {
384
+ codersdk .FeatureCustomRoles :1 ,
385
+ },
386
+ },
387
+ })
388
+
389
+ orgAdmin ,orgAdminUser := coderdtest .CreateAnotherUser (t ,owner ,first .OrganizationID ,rbac .ScopedRoleOrgAdmin (first .OrganizationID ))
390
+ ctx := testutil .Context (t ,testutil .WaitMedium )
391
+
392
+ createdRole ,err := orgAdmin .PatchOrganizationRole (ctx ,templateAdminCustom (first .OrganizationID ))
393
+ require .NoError (t ,err ,"upsert role" )
394
+
395
+ customRoleIdentifier := rbac.RoleIdentifier {
396
+ Name :createdRole .Name ,
397
+ OrganizationID :first .OrganizationID ,
398
+ }
399
+
400
+ // Create a few members with the role
401
+ coderdtest .CreateAnotherUser (t ,owner ,first .OrganizationID ,customRoleIdentifier )
402
+ coderdtest .CreateAnotherUser (t ,owner ,first .OrganizationID ,rbac .ScopedRoleOrgAdmin (first .OrganizationID ),customRoleIdentifier )
403
+ coderdtest .CreateAnotherUser (t ,owner ,first .OrganizationID ,rbac .ScopedRoleOrgTemplateAdmin (first .OrganizationID ),rbac .ScopedRoleOrgAuditor (first .OrganizationID ),customRoleIdentifier )
404
+
405
+ // Verify members have the custom role
406
+ members ,err := orgAdmin .OrganizationMembers (ctx ,first .OrganizationID )
407
+ require .NoError (t ,err )
408
+ require .Len (t ,members ,5 )// 3 members + org admin + owner
409
+ for _ ,member := range members {
410
+ if member .UserID == orgAdminUser .ID || member .UserID == first .UserID {
411
+ continue
412
+ }
413
+
414
+ require .True (t ,slices .ContainsFunc (member .Roles ,func (role codersdk.SlimRole )bool {
415
+ return role .Name == customRoleIdentifier .Name
416
+ }),"member should have custom role" )
417
+ }
418
+
419
+ err = orgAdmin .DeleteOrganizationRole (ctx ,first .OrganizationID ,createdRole .Name )
420
+ require .NoError (t ,err )
421
+
422
+ // Verify the role was removed from all members
423
+ members ,err = orgAdmin .OrganizationMembers (ctx ,first .OrganizationID )
424
+ require .NoError (t ,err )
425
+ require .Len (t ,members ,5 )// 3 members + org admin + owner
426
+ for _ ,member := range members {
427
+ require .False (t ,slices .ContainsFunc (member .Roles ,func (role codersdk.SlimRole )bool {
428
+ return role .Name == customRoleIdentifier .Name
429
+ }),"role should be removed from all users" )
430
+ }
355
431
})
356
432
}
357
433