Files
0b7669f30d Tighten validation on channel member role updates (#37075)
* Add tests for channel member role scope validation

Co-authored-by: mattermost-code <[email protected]>

* Restrict channel member roles to channel scope

Co-authored-by: mattermost-code <[email protected]>

* Expand channel member role validation tests

Co-authored-by: mattermost-code <[email protected]>

* Use exact built-in role ID matching for channel member scope validation

Replace prefix-based GetBuiltInRoleScope with a map of known built-in role
IDs so custom roles with team_/system_ prefixes are not misclassified.
Also fix golangci modernize lint by using strings.FieldsSeq.

Co-authored-by: mattermost-code <[email protected]>

* Simplify channel member role validation

- Remove GetBuiltInRoleScope function and builtInRoleScopes map
- Replace with direct check against channelScopedBuiltInRoles set
- Add isBuiltInRole helper to check if role is built-in
- Update app layer to use IsValidChannelMemberRoles function
- Remove TestGetBuiltInRoleScope test (function no longer exists)

This simplifies the validation by only defining the channel-scoped
roles we need to check against, rather than maintaining a full map
of all built-in roles and their scopes.

Co-authored-by: Maria A Nunez <[email protected]>

* Fix golangci-lint: use slices.Contains in isBuiltInRole

Replace manual loop with slices.Contains for better performance
and to satisfy the modernize linter rule.

Co-authored-by: Maria A Nunez <[email protected]>

* Remove channelScopedBuiltInRoles map, check roles directly

Simplify IsValidChannelMemberRoles by directly checking against the
3 channel role constants instead of maintaining a separate map.

Co-authored-by: Maria A Nunez <[email protected]>

* Use role.BuiltIn property instead of isBuiltInRole helper

- App layer now uses role.BuiltIn directly since it has the role object
- Model layer checks BuiltInSchemeManagedRoleIDs inline without helper
- Removed isBuiltInRole helper function entirely

Co-authored-by: Maria A Nunez <[email protected]>

* Fix dual-layer drift in channel member role validation

Use MakeDefaultRoles/role.BuiltIn as the single source of truth for
built-in role detection.  Introduces IsChannelScopedBuiltInRole and a
lazy builtInRoleSet so both the model (IsValidChannelMemberRoles) and
the app layer (updateChannelMemberRolesInternal) share one allow-list.

Closes the system_custom_group_admin gap: it has BuiltIn=true but was
absent from BuiltInSchemeManagedRoleIDs, so the model layer silently
passed it while the app layer correctly rejected it.  Now both layers
reject it consistently.

* Fix builtInRoleSet discriminant to use BuiltInSchemeManagedRoleIDs

The previous commit derived the built-in role set from MakeDefaultRoles()
role.BuiltIn, which caused custom_group_user (BuiltIn=false, for unrelated
WebSocket broadcast-scope reasons) to be treated as a custom role and pass
IsValidChannelMemberRoles, contradicting the API-layer test.

Fix:
- Add SystemCustomGroupAdminRoleId to BuiltInSchemeManagedRoleIDs (the
  original gap that started this work)
- Derive builtInRoleSet from BuiltInSchemeManagedRoleIDs, which correctly
  covers both custom_group_user and system_custom_group_admin
- Revert custom_group_user model-test expectation to valid: false, now
  consistent with the API integration test

* Build builtInRoleSet in init() instead of sync.OnceValue

* Align app-layer channel role check with model predicate

Introduce model.IsBuiltInRole so IsValidChannelMemberRoles (API/model) and
updateChannelMemberRolesInternal (app) share one source of truth for which
roles are built-in. The app layer previously keyed off role.BuiltIn, which is
false for custom_group_user, so plugin/bulk-import callers bypassing the API
check could assign it as a channel member role. Also correct the comments
that mislabeled BuiltInSchemeManagedRoleIDs as all scheme-managed.

---------

Co-authored-by: mattermost-code <[email protected]>
Co-authored-by: Maria A Nunez <[email protected]>

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-25 19:08:30 -04:00

614 lines
20 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package model
import (
"slices"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestChannelModeratedPermissionsChangedByPatch(t *testing.T) {
testCases := []struct {
Name string
Permissions []string
PatchPermissions []string
Expected []string
}{
{
"Empty patch returns empty slice",
[]string{},
[]string{},
[]string{},
},
{
"Adds permissions to empty initial permissions list",
[]string{},
[]string{PermissionCreatePost.Id, PermissionAddReaction.Id},
[]string{ChannelModeratedPermissions[0], ChannelModeratedPermissions[1]},
},
{
"Ignores non moderated permissions in initial permissions list",
[]string{PermissionAssignBot.Id},
[]string{PermissionCreatePost.Id, PermissionRemoveReaction.Id},
[]string{ChannelModeratedPermissions[0], ChannelModeratedPermissions[1]},
},
{
"Adds removed moderated permissions from initial permissions list",
[]string{PermissionCreatePost.Id},
[]string{},
[]string{PermissionCreatePost.Id},
},
{
"No changes returns empty slice",
[]string{PermissionCreatePost.Id, PermissionAssignBot.Id},
[]string{PermissionCreatePost.Id},
[]string{},
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
baseRole := &Role{Permissions: tc.Permissions}
rolePatch := &RolePatch{Permissions: &tc.PatchPermissions}
result := ChannelModeratedPermissionsChangedByPatch(baseRole, rolePatch)
assert.ElementsMatch(t, tc.Expected, result)
})
}
}
func TestRolePatchFromChannelModerationsPatch(t *testing.T) {
createPosts := ChannelModeratedPermissions[0]
createReactions := ChannelModeratedPermissions[1]
manageMembers := ChannelModeratedPermissions[2]
channelMentions := ChannelModeratedPermissions[3]
basePermissions := []string{
PermissionAddReaction.Id,
PermissionRemoveReaction.Id,
PermissionCreatePost.Id,
PermissionUseChannelMentions.Id,
PermissionManagePublicChannelMembers.Id,
PermissionUploadFile.Id,
PermissionGetPublicLink.Id,
}
baseModeratedPermissions := []string{
PermissionAddReaction.Id,
PermissionRemoveReaction.Id,
PermissionCreatePost.Id,
PermissionManagePublicChannelMembers.Id,
PermissionUseChannelMentions.Id,
}
testCases := []struct {
Name string
Permissions []string
ChannelModerationsPatch []*ChannelModerationPatch
RoleName string
ExpectedPatchPermissions []string
}{
{
"Patch to member role adding a permission that already exists",
basePermissions,
[]*ChannelModerationPatch{
{
Name: &createReactions,
Roles: &ChannelModeratedRolesPatch{Members: new(true)},
},
},
"members",
baseModeratedPermissions,
},
{
"Patch to member role with moderation patch for guest role",
basePermissions,
[]*ChannelModerationPatch{
{
Name: &createReactions,
Roles: &ChannelModeratedRolesPatch{Guests: new(true)},
},
},
"members",
baseModeratedPermissions,
},
{
"Patch to guest role with moderation patch for member role",
basePermissions,
[]*ChannelModerationPatch{
{
Name: &createReactions,
Roles: &ChannelModeratedRolesPatch{Members: new(true)},
},
},
"guests",
baseModeratedPermissions,
},
{
"Patch to member role removing multiple channel moderated permissions",
basePermissions,
[]*ChannelModerationPatch{
{
Name: &createReactions,
Roles: &ChannelModeratedRolesPatch{Members: new(false)},
},
{
Name: &manageMembers,
Roles: &ChannelModeratedRolesPatch{Members: new(false)},
},
{
Name: &channelMentions,
Roles: &ChannelModeratedRolesPatch{Members: new(false)},
},
},
"members",
[]string{PermissionCreatePost.Id},
},
{
"Patch to guest role removing multiple channel moderated permissions",
basePermissions,
[]*ChannelModerationPatch{
{
Name: &createReactions,
Roles: &ChannelModeratedRolesPatch{Guests: new(false)},
},
{
Name: &manageMembers,
Roles: &ChannelModeratedRolesPatch{Guests: new(false)},
},
{
Name: &channelMentions,
Roles: &ChannelModeratedRolesPatch{Guests: new(false)},
},
},
"guests",
[]string{PermissionCreatePost.Id},
},
{
"Patch enabling and removing multiple channel moderated permissions ",
[]string{PermissionAddReaction.Id, PermissionManagePublicChannelMembers.Id},
[]*ChannelModerationPatch{
{
Name: &createReactions,
Roles: &ChannelModeratedRolesPatch{Members: new(false)},
},
{
Name: &manageMembers,
Roles: &ChannelModeratedRolesPatch{Members: new(false)},
},
{
Name: &channelMentions,
Roles: &ChannelModeratedRolesPatch{Members: new(true)},
},
{
Name: &createPosts,
Roles: &ChannelModeratedRolesPatch{Members: new(true)},
},
},
"members",
[]string{PermissionCreatePost.Id, PermissionUseChannelMentions.Id},
},
{
"Patch enabling a partially enabled permission",
[]string{PermissionAddReaction.Id},
[]*ChannelModerationPatch{
{
Name: &createReactions,
Roles: &ChannelModeratedRolesPatch{Members: new(true)},
},
},
"members",
[]string{PermissionAddReaction.Id, PermissionRemoveReaction.Id},
},
{
"Patch disabling a partially disabled permission",
[]string{PermissionAddReaction.Id},
[]*ChannelModerationPatch{
{
Name: &createReactions,
Roles: &ChannelModeratedRolesPatch{Members: new(false)},
},
{
Name: &createPosts,
Roles: &ChannelModeratedRolesPatch{Members: new(true)},
},
},
"members",
[]string{PermissionCreatePost.Id},
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
baseRole := &Role{Permissions: tc.Permissions}
rolePatch := baseRole.RolePatchFromChannelModerationsPatch(tc.ChannelModerationsPatch, tc.RoleName)
assert.ElementsMatch(t, tc.ExpectedPatchPermissions, *rolePatch.Permissions)
})
}
}
func TestGetChannelModeratedPermissions(t *testing.T) {
tests := []struct {
Name string
Permissions []string
ChannelType ChannelType
Expected map[string]bool
}{
{
"Filters non moderated permissions",
[]string{PermissionCreateBot.Id},
ChannelTypeOpen,
map[string]bool{},
},
{
"Returns a map of moderated permissions",
[]string{PermissionCreatePost.Id, PermissionAddReaction.Id, PermissionRemoveReaction.Id, PermissionManagePublicChannelMembers.Id, PermissionManagePrivateChannelMembers.Id, PermissionUseChannelMentions.Id},
ChannelTypeOpen,
map[string]bool{
ChannelModeratedPermissions[0]: true,
ChannelModeratedPermissions[1]: true,
ChannelModeratedPermissions[2]: true,
ChannelModeratedPermissions[3]: true,
},
},
{
"Returns a map of moderated permissions when non moderated present",
[]string{PermissionCreatePost.Id, PermissionCreateDirectChannel.Id},
ChannelTypeOpen,
map[string]bool{
ChannelModeratedPermissions[0]: true,
},
},
{
"Returns a nothing when no permissions present",
[]string{},
ChannelTypeOpen,
map[string]bool{},
},
}
for _, tc := range tests {
t.Run(tc.Name, func(t *testing.T) {
role := &Role{Permissions: tc.Permissions}
moderatedPermissions := role.GetChannelModeratedPermissions(tc.ChannelType)
for permission := range moderatedPermissions {
assert.Equal(t, moderatedPermissions[permission], tc.Expected[permission])
}
})
}
}
func TestAddAncillaryPermissions(t *testing.T) {
tests := []struct {
Name string
Permissions []string
Expected []string
}{
{
"Add For ReadUserManagementUsers",
[]string{PermissionSysconsoleReadUserManagementUsers.Id},
[]string{PermissionSysconsoleReadUserManagementUsers.Id, PermissionReadOtherUsersTeams.Id},
},
{
"Add For ReadCompliance",
[]string{PermissionSysconsoleReadComplianceComplianceMonitoring.Id},
[]string{PermissionSysconsoleReadComplianceComplianceMonitoring.Id, PermissionReadAudits.Id},
},
{
"Add None",
[]string{PermissionSysconsoleReadComplianceCustomTermsOfService.Id},
[]string{PermissionSysconsoleReadComplianceCustomTermsOfService.Id},
},
}
for _, tc := range tests {
t.Run(tc.Name, func(t *testing.T) {
permissions := AddAncillaryPermissions(tc.Permissions)
assert.Equal(t, permissions, tc.Expected)
})
}
}
func TestMakeDefaultRolesContainsNewManagerRoles(t *testing.T) {
roles := MakeDefaultRoles()
t.Run("system_shared_channel_manager role exists with correct permissions", func(t *testing.T) {
role, ok := roles[SharedChannelManagerRoleId]
require.True(t, ok, "system_shared_channel_manager role should exist in MakeDefaultRoles")
assert.Equal(t, "system_shared_channel_manager", role.Name)
assert.True(t, role.BuiltIn, "role should be built-in")
assert.False(t, role.SchemeManaged, "role should not be scheme-managed")
assert.True(t, slices.Contains(role.Permissions, PermissionManageSharedChannels.Id),
"role should have manage_shared_channels permission")
assert.False(t, slices.Contains(role.Permissions, PermissionManageSecureConnections.Id),
"role should NOT have manage_secure_connections permission")
})
t.Run("roles are included in NewSystemRoleIDs", func(t *testing.T) {
assert.True(t, slices.Contains(NewSystemRoleIDs, SharedChannelManagerRoleId),
"system_shared_channel_manager should be in NewSystemRoleIDs")
})
t.Run("system_admin includes manage_oauth by default", func(t *testing.T) {
role, ok := roles[SystemAdminRoleId]
require.True(t, ok, "system_admin role should exist in MakeDefaultRoles")
assert.True(t, slices.Contains(role.Permissions, PermissionManageOAuth.Id),
"system_admin should include manage_oauth")
assert.True(t, slices.ContainsFunc(AllPermissions, func(permission *Permission) bool {
return permission.Id == PermissionManageOAuth.Id
}), "manage_oauth should be part of AllPermissions")
assert.False(t, slices.ContainsFunc(DeprecatedPermissions, func(permission *Permission) bool {
return permission.Id == PermissionManageOAuth.Id
}), "manage_oauth should not remain deprecated")
})
}
func TestManageAgentPermissionsDefinition(t *testing.T) {
assert.Equal(t, "manage_own_agent", PermissionManageOwnAgent.Id)
assert.Equal(t, "authentication.permissions.manage_own_agent.name", PermissionManageOwnAgent.Name)
assert.Equal(t, "authentication.permissions.manage_own_agent.description", PermissionManageOwnAgent.Description)
assert.Equal(t, PermissionScopeSystem, PermissionManageOwnAgent.Scope,
"manage_own_agent should have system scope")
assert.True(t, slices.ContainsFunc(AllPermissions, func(p *Permission) bool {
return p.Id == PermissionManageOwnAgent.Id
}), "manage_own_agent should be in AllPermissions")
assert.Equal(t, "manage_others_agent", PermissionManageOthersAgent.Id)
assert.Equal(t, "authentication.permissions.manage_others_agent.name", PermissionManageOthersAgent.Name)
assert.Equal(t, "authentication.permissions.manage_others_agent.description", PermissionManageOthersAgent.Description)
assert.Equal(t, PermissionScopeSystem, PermissionManageOthersAgent.Scope,
"manage_others_agent should have system scope")
assert.True(t, slices.ContainsFunc(AllPermissions, func(p *Permission) bool {
return p.Id == PermissionManageOthersAgent.Id
}), "manage_others_agent should be in AllPermissions")
}
func TestRoleIsValidWithoutId(t *testing.T) {
validRole := func() *Role {
return &Role{
Name: "test_role",
DisplayName: "Test Role",
Description: "A test role.",
Permissions: []string{PermissionCreatePost.Id},
}
}
t.Run("valid role returns nil", func(t *testing.T) {
assert.NoError(t, validRole().IsValidWithoutId())
})
t.Run("empty name", func(t *testing.T) {
r := validRole()
r.Name = ""
assert.ErrorContains(t, r.IsValidWithoutId(), "invalid role name")
})
t.Run("name too long", func(t *testing.T) {
r := validRole()
r.Name = strings.Repeat("a", RoleNameMaxLength+1)
assert.ErrorContains(t, r.IsValidWithoutId(), "invalid role name")
})
t.Run("name with invalid characters", func(t *testing.T) {
r := validRole()
r.Name = "invalid-name"
assert.ErrorContains(t, r.IsValidWithoutId(), "invalid role name")
})
t.Run("empty display name", func(t *testing.T) {
r := validRole()
r.DisplayName = ""
assert.ErrorContains(t, r.IsValidWithoutId(), "display name must not be empty")
})
t.Run("display name too long", func(t *testing.T) {
r := validRole()
r.DisplayName = strings.Repeat("a", RoleDisplayNameMaxLength+1)
err := r.IsValidWithoutId()
assert.ErrorContains(t, err, "display name")
assert.ErrorContains(t, err, "exceeds maximum length")
})
t.Run("description too long", func(t *testing.T) {
r := validRole()
r.Description = strings.Repeat("a", RoleDescriptionMaxLength+1)
assert.ErrorContains(t, r.IsValidWithoutId(), "description exceeds maximum length")
})
t.Run("unknown permission", func(t *testing.T) {
r := validRole()
r.Permissions = []string{"not_a_real_permission"}
err := r.IsValidWithoutId()
require.ErrorContains(t, err, "unknown permission")
assert.ErrorContains(t, err, "not_a_real_permission")
})
t.Run("no permissions is valid", func(t *testing.T) {
r := validRole()
r.Permissions = nil
assert.NoError(t, r.IsValidWithoutId())
})
}
func TestRoleUnknownPermissions(t *testing.T) {
t.Run("returns nil when all permissions are known", func(t *testing.T) {
r := &Role{
Permissions: []string{PermissionCreatePost.Id, PermissionCreateEmojis.Id},
}
assert.Empty(t, r.UnknownPermissions())
})
t.Run("tolerates deprecated permissions", func(t *testing.T) {
require.NotEmpty(t, DeprecatedPermissions)
r := &Role{
Permissions: []string{PermissionCreatePost.Id, DeprecatedPermissions[0].Id},
}
assert.Empty(t, r.UnknownPermissions())
})
t.Run("returns only the permissions this build does not recognize", func(t *testing.T) {
r := &Role{
Permissions: []string{PermissionCreatePost.Id, "manage_own_agent_from_the_future", "another_unknown"},
}
assert.ElementsMatch(t, []string{"manage_own_agent_from_the_future", "another_unknown"}, r.UnknownPermissions())
})
t.Run("empty permissions yields no unknowns", func(t *testing.T) {
assert.Empty(t, (&Role{}).UnknownPermissions())
})
}
func TestRoleClone(t *testing.T) {
schemeId := NewId()
original := &Role{
Id: NewId(),
Name: "test_role",
DisplayName: "Test Role",
Description: "desc",
CreateAt: 1000,
UpdateAt: 2000,
DeleteAt: 0,
Permissions: []string{"invite_user", "add_user_to_team"},
SchemeManaged: true,
BuiltIn: false,
SchemeId: &schemeId,
}
t.Run("clone equals original", func(t *testing.T) {
cloned := original.Clone()
assert.Equal(t, original, cloned)
})
t.Run("permissions are deep copied", func(t *testing.T) {
cloned := original.Clone()
cloned.Permissions[0] = "mutated"
assert.Equal(t, "invite_user", original.Permissions[0])
})
t.Run("scheme id pointer is deep copied", func(t *testing.T) {
cloned := original.Clone()
require.NotSame(t, original.SchemeId, cloned.SchemeId)
*cloned.SchemeId = NewId()
assert.Equal(t, schemeId, *original.SchemeId)
})
t.Run("nil permissions stays nil", func(t *testing.T) {
r := &Role{}
assert.Nil(t, r.Clone().Permissions)
})
t.Run("nil scheme id stays nil", func(t *testing.T) {
r := &Role{}
assert.Nil(t, r.Clone().SchemeId)
})
}
func TestRoleIsValid(t *testing.T) {
validRole := func() *Role {
return &Role{
Id: NewId(),
Name: "test_role",
DisplayName: "Test Role",
Permissions: []string{PermissionCreatePost.Id},
}
}
t.Run("valid role returns nil", func(t *testing.T) {
assert.NoError(t, validRole().IsValid())
})
t.Run("empty id", func(t *testing.T) {
r := validRole()
r.Id = ""
assert.ErrorContains(t, r.IsValid(), "invalid role id")
})
t.Run("invalid id", func(t *testing.T) {
r := validRole()
r.Id = "not-a-valid-id!"
assert.ErrorContains(t, r.IsValid(), "invalid role id")
})
t.Run("propagates IsValidWithoutId error", func(t *testing.T) {
r := validRole()
r.DisplayName = ""
assert.ErrorContains(t, r.IsValid(), "display name must not be empty")
})
}
func TestIsValidChannelMemberRoles(t *testing.T) {
tests := []struct {
name string
roles string
valid bool
}{
{name: "channel user only", roles: ChannelUserRoleId, valid: true},
{name: "channel user and admin", roles: ChannelUserRoleId + " " + ChannelAdminRoleId, valid: true},
{name: "channel guest only", roles: ChannelGuestRoleId, valid: true},
{name: "custom role with channel user", roles: ChannelUserRoleId + " custom_role", valid: true},
{name: "prefixed custom team role with channel user", roles: ChannelUserRoleId + " team_custom", valid: true},
{name: "prefixed custom system role with channel user", roles: ChannelUserRoleId + " system_custom", valid: true},
{name: "team user with channel user", roles: ChannelUserRoleId + " " + TeamUserRoleId, valid: false},
{name: "team post all with channel user", roles: ChannelUserRoleId + " " + TeamPostAllRoleId, valid: false},
{name: "system user with channel user", roles: ChannelUserRoleId + " " + SystemUserRoleId, valid: false},
{name: "system manager with channel user", roles: ChannelUserRoleId + " " + SystemManagerRoleId, valid: false},
{name: "system post all with channel user", roles: ChannelUserRoleId + " " + SystemPostAllRoleId, valid: false},
{name: "system read only admin with channel user", roles: ChannelUserRoleId + " " + SystemReadOnlyAdminRoleId, valid: false},
{name: "custom group user with channel user", roles: ChannelUserRoleId + " " + CustomGroupUserRoleId, valid: false},
{name: "system custom group admin with channel user", roles: ChannelUserRoleId + " " + SystemCustomGroupAdminRoleId, valid: false},
{name: "invalid role name", roles: "invalid-role", valid: false},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert.Equal(t, tc.valid, IsValidChannelMemberRoles(tc.roles))
})
}
}
func TestIsBuiltInRole(t *testing.T) {
tests := []struct {
name string
roleName string
builtIn bool
}{
{name: "channel user", roleName: ChannelUserRoleId, builtIn: true},
{name: "system manager", roleName: SystemManagerRoleId, builtIn: true},
{name: "system custom group admin", roleName: SystemCustomGroupAdminRoleId, builtIn: true},
// custom_group_user is built-in even though its role.BuiltIn flag is false.
{name: "custom group user", roleName: CustomGroupUserRoleId, builtIn: true},
{name: "custom role", roleName: "custom_role", builtIn: false},
{name: "prefixed custom system role", roleName: "system_custom", builtIn: false},
{name: "empty", roleName: "", builtIn: false},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert.Equal(t, tc.builtIn, IsBuiltInRole(tc.roleName))
})
}
}
func TestManageAgentPermissionsDefaultRoles(t *testing.T) {
roles := MakeDefaultRoles()
for _, tc := range []struct {
roleId string
expectOwn bool
expectOthers bool
}{
{SystemAdminRoleId, true, true},
{SystemUserRoleId, true, false},
{SystemGuestRoleId, false, false},
} {
t.Run(tc.roleId, func(t *testing.T) {
role, ok := roles[tc.roleId]
require.True(t, ok, "%s role should exist", tc.roleId)
assert.Equal(t, tc.expectOwn, slices.Contains(role.Permissions, PermissionManageOwnAgent.Id),
"%s manage_own_agent permission presence", tc.roleId)
assert.Equal(t, tc.expectOthers, slices.Contains(role.Permissions, PermissionManageOthersAgent.Id),
"%s manage_others_agent permission presence", tc.roleId)
})
}
}