mirror of
https://github.com/hanzoai/team.git
synced 2026-10-30 14:49:35 +00:00
* MM-68830: Preserve unknown permissions during migrations on downgrade A server that was upgraded to a newer release (which introduced new permissions and wrote them into roles) and then downgraded fails fatally at startup: the permissions migration re-saves every role, and Role.Save() rejects any permission the older binary does not recognize, making the downgrade unrecoverable. Add RoleStore.SavePreservingUnknownPermissions, used only by doPermissionsMigration, which tolerates and preserves permissions this build does not recognize (logging a warning) instead of rejecting the role. The regular Save() — and therefore the role API path — stays strict, so unknown permissions cannot be introduced through user input. Unrecognized permissions are kept on disk so they are not lost on a later re-upgrade. * MM-68830: assert save forwarding in role cache tests Address review feedback: assert the underlying store's Save and SavePreservingUnknownPermissions are actually invoked (the cache invalidation defer fires regardless of forwarding), and check the returned errors. * MM-68830: address review feedback - Shorten log message in validateForSave - Rename validationRole -> roleCopy for clarity - Trim doc comments to describe behavior only - List all unknown permissions in IsValidWithoutId error - Assert specific error type in storetest * MM-68830: add Role.Clone and use it in validateForSave * MM-68830: add tests for Role.Clone * MM-68830: fix scheme id deep copy assertion in Role.Clone test
696 lines
21 KiB
Go
696 lines
21 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package storetest
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/mattermost/mattermost/server/public/shared/request"
|
|
"github.com/mattermost/mattermost/server/v8/channels/store"
|
|
)
|
|
|
|
func TestRoleStore(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) {
|
|
t.Run("Save", func(t *testing.T) { testRoleStoreSave(t, rctx, ss) })
|
|
t.Run("SavePreservingUnknownPermissions", func(t *testing.T) { testRoleStoreSavePreservingUnknownPermissions(t, rctx, ss) })
|
|
t.Run("Get", func(t *testing.T) { testRoleStoreGet(t, rctx, ss) })
|
|
t.Run("GetAll", func(t *testing.T) { testRoleStoreGetAll(t, rctx, ss) })
|
|
t.Run("GetByName", func(t *testing.T) { testRoleStoreGetByName(t, rctx, ss) })
|
|
t.Run("GetNames", func(t *testing.T) { testRoleStoreGetByNames(t, rctx, ss) })
|
|
t.Run("Delete", func(t *testing.T) { testRoleStoreDelete(t, rctx, ss) })
|
|
t.Run("PermanentDeleteAll", func(t *testing.T) { testRoleStorePermanentDeleteAll(t, rctx, ss) })
|
|
t.Run("LowerScopedChannelSchemeRoles_AllChannelSchemeRoles", func(t *testing.T) { testRoleStoreLowerScopedChannelSchemeRoles(t, rctx, ss) })
|
|
t.Run("ChannelHigherScopedPermissionsBlankTeamSchemeChannelGuest", func(t *testing.T) {
|
|
testRoleStoreChannelHigherScopedPermissionsBlankTeamSchemeChannelGuest(t, rctx, ss, s)
|
|
})
|
|
}
|
|
|
|
func testRoleStoreSave(t *testing.T, rctx request.CTX, ss store.Store) {
|
|
// Save a new role.
|
|
r1 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
d1, err := ss.Role().Save(r1)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, d1.Id, 26)
|
|
assert.Equal(t, r1.Name, d1.Name)
|
|
assert.Equal(t, r1.DisplayName, d1.DisplayName)
|
|
assert.Equal(t, r1.Description, d1.Description)
|
|
assert.Equal(t, r1.Permissions, d1.Permissions)
|
|
assert.Equal(t, r1.SchemeManaged, d1.SchemeManaged)
|
|
|
|
// Change the role permissions and update.
|
|
d1.Permissions = []string{
|
|
"invite_user",
|
|
"add_user_to_team",
|
|
"delete_public_channel",
|
|
}
|
|
|
|
d2, err := ss.Role().Save(d1)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, d2.Id, 26)
|
|
assert.Equal(t, r1.Name, d2.Name)
|
|
assert.Equal(t, r1.DisplayName, d2.DisplayName)
|
|
assert.Equal(t, r1.Description, d2.Description)
|
|
assert.Equal(t, d1.Permissions, d2.Permissions)
|
|
assert.Equal(t, r1.SchemeManaged, d2.SchemeManaged)
|
|
|
|
// Try saving one with an invalid ID set.
|
|
r3 := &model.Role{
|
|
Id: model.NewId(),
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
_, err = ss.Role().Save(r3)
|
|
assert.Error(t, err)
|
|
|
|
// Try saving one with a duplicate "name" field.
|
|
r4 := &model.Role{
|
|
Name: r1.Name,
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
_, err = ss.Role().Save(r4)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func testRoleStoreSavePreservingUnknownPermissions(t *testing.T, _ request.CTX, ss store.Store) {
|
|
// A role whose permissions are all valid for this build saves and round-trips
|
|
// unchanged, just like Save.
|
|
t.Run("preserves known permissions like Save", func(t *testing.T) {
|
|
r := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{"invite_user", "add_user_to_team"},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
saved, err := ss.Role().SavePreservingUnknownPermissions(r)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, r.Permissions, saved.Permissions)
|
|
})
|
|
|
|
// The downgrade scenario from MM-68830: an existing role gains a permission this
|
|
// build does not recognize (written by a newer release before the downgrade). The
|
|
// migration re-saves every role; Save would reject the unknown permission, but
|
|
// SavePreservingUnknownPermissions must keep it so it is not lost on a future upgrade.
|
|
t.Run("tolerates and persists unknown permissions on update", func(t *testing.T) {
|
|
unknown := "manage_own_agent_from_the_future"
|
|
|
|
// Create the role as a known-good role first (the pre-downgrade state).
|
|
existing, err := ss.Role().Save(&model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{"invite_user"},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Simulate the newer release having added an unknown permission to the role.
|
|
existing.Permissions = append(existing.Permissions, unknown)
|
|
|
|
// Sanity check: the regular Save rejects the unknown permission.
|
|
_, err = ss.Role().Save(existing)
|
|
require.Error(t, err)
|
|
|
|
saved, err := ss.Role().SavePreservingUnknownPermissions(existing)
|
|
require.NoError(t, err)
|
|
assert.Contains(t, saved.Permissions, unknown, "unknown permission should be preserved")
|
|
|
|
// It must actually be persisted, not just returned.
|
|
fetched, err := ss.Role().Get(saved.Id)
|
|
require.NoError(t, err)
|
|
assert.Contains(t, fetched.Permissions, unknown)
|
|
})
|
|
|
|
// Tolerating unknown permissions must not mask genuine structural problems.
|
|
t.Run("still rejects structurally invalid roles", func(t *testing.T) {
|
|
r := &model.Role{
|
|
Name: "invalid-name",
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{"manage_own_agent_from_the_future"},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
_, err := ss.Role().SavePreservingUnknownPermissions(r)
|
|
require.Error(t, err)
|
|
var invErr *store.ErrInvalidInput
|
|
require.ErrorAs(t, err, &invErr)
|
|
})
|
|
}
|
|
|
|
func testRoleStoreGetAll(t *testing.T, rctx request.CTX, ss store.Store) {
|
|
prev, err := ss.Role().GetAll()
|
|
require.NoError(t, err)
|
|
prevCount := len(prev)
|
|
|
|
// Save a role to test with.
|
|
r1 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
_, err = ss.Role().Save(r1)
|
|
require.NoError(t, err)
|
|
|
|
r2 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
_, err = ss.Role().Save(r2)
|
|
require.NoError(t, err)
|
|
|
|
data, err := ss.Role().GetAll()
|
|
require.NoError(t, err)
|
|
assert.Len(t, data, prevCount+2)
|
|
}
|
|
|
|
func testRoleStoreGet(t *testing.T, rctx request.CTX, ss store.Store) {
|
|
// Save a role to test with.
|
|
r1 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
d1, err := ss.Role().Save(r1)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, d1.Id, 26)
|
|
|
|
// Get a valid role
|
|
d2, err := ss.Role().Get(d1.Id)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, d1.Id, d2.Id)
|
|
assert.Equal(t, r1.Name, d2.Name)
|
|
assert.Equal(t, r1.DisplayName, d2.DisplayName)
|
|
assert.Equal(t, r1.Description, d2.Description)
|
|
assert.Equal(t, r1.Permissions, d2.Permissions)
|
|
assert.Equal(t, r1.SchemeManaged, d2.SchemeManaged)
|
|
|
|
// Get an invalid role
|
|
_, err = ss.Role().Get(model.NewId())
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func testRoleStoreGetByName(t *testing.T, rctx request.CTX, ss store.Store) {
|
|
// Save a role to test with.
|
|
r1 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
d1, err := ss.Role().Save(r1)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, d1.Id, 26)
|
|
|
|
// Get a valid role
|
|
d2, err := ss.Role().GetByName(context.Background(), d1.Name)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, d1.Id, d2.Id)
|
|
assert.Equal(t, r1.Name, d2.Name)
|
|
assert.Equal(t, r1.DisplayName, d2.DisplayName)
|
|
assert.Equal(t, r1.Description, d2.Description)
|
|
assert.Equal(t, r1.Permissions, d2.Permissions)
|
|
assert.Equal(t, r1.SchemeManaged, d2.SchemeManaged)
|
|
|
|
// Get an invalid role
|
|
_, err = ss.Role().GetByName(context.Background(), model.NewId())
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func testRoleStoreGetByNames(t *testing.T, rctx request.CTX, ss store.Store) {
|
|
// Save some roles to test with.
|
|
r1 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
r2 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"read_channel",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
r3 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"delete_private_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
d1, err := ss.Role().Save(r1)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, d1.Id, 26)
|
|
|
|
d2, err := ss.Role().Save(r2)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, d2.Id, 26)
|
|
|
|
d3, err := ss.Role().Save(r3)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, d3.Id, 26)
|
|
|
|
// Get two valid roles.
|
|
n4 := []string{r1.Name, r2.Name}
|
|
roles4, err := ss.Role().GetByNames(n4)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, roles4, 2)
|
|
assert.Contains(t, roles4, d1)
|
|
assert.Contains(t, roles4, d2)
|
|
assert.NotContains(t, roles4, d3)
|
|
|
|
// Get two invalid roles.
|
|
n5 := []string{model.NewId(), model.NewId()}
|
|
roles5, err := ss.Role().GetByNames(n5)
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, roles5)
|
|
|
|
// Get one valid one and one invalid one.
|
|
n6 := []string{r1.Name, model.NewId()}
|
|
roles6, err := ss.Role().GetByNames(n6)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, roles6, 1)
|
|
assert.Contains(t, roles6, d1)
|
|
assert.NotContains(t, roles6, d2)
|
|
assert.NotContains(t, roles6, d3)
|
|
}
|
|
|
|
func testRoleStoreDelete(t *testing.T, rctx request.CTX, ss store.Store) {
|
|
// Save a role to test with.
|
|
r1 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
d1, err := ss.Role().Save(r1)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, d1.Id, 26)
|
|
|
|
// Check the role is there.
|
|
_, err = ss.Role().Get(d1.Id)
|
|
assert.NoError(t, err)
|
|
|
|
// Delete the role.
|
|
_, err = ss.Role().Delete(d1.Id)
|
|
assert.NoError(t, err)
|
|
|
|
// Check the role is deleted there.
|
|
d2, err := ss.Role().Get(d1.Id)
|
|
assert.NoError(t, err)
|
|
assert.NotZero(t, d2.DeleteAt)
|
|
|
|
d3, err := ss.Role().GetByName(context.Background(), d1.Name)
|
|
assert.NoError(t, err)
|
|
assert.NotZero(t, d3.DeleteAt)
|
|
|
|
// Try and delete a role that does not exist.
|
|
_, err = ss.Role().Delete(model.NewId())
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func testRoleStorePermanentDeleteAll(t *testing.T, rctx request.CTX, ss store.Store) {
|
|
r1 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"invite_user",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
r2 := &model.Role{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Description: model.NewId(),
|
|
Permissions: []string{
|
|
"read_channel",
|
|
"create_public_channel",
|
|
"add_user_to_team",
|
|
},
|
|
SchemeManaged: false,
|
|
}
|
|
|
|
_, err := ss.Role().Save(r1)
|
|
require.NoError(t, err)
|
|
_, err = ss.Role().Save(r2)
|
|
require.NoError(t, err)
|
|
|
|
roles, err := ss.Role().GetByNames([]string{r1.Name, r2.Name})
|
|
assert.NoError(t, err)
|
|
assert.Len(t, roles, 2)
|
|
|
|
err = ss.Role().PermanentDeleteAll()
|
|
assert.NoError(t, err)
|
|
|
|
roles, err = ss.Role().GetByNames([]string{r1.Name, r2.Name})
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, roles)
|
|
}
|
|
|
|
func testRoleStoreLowerScopedChannelSchemeRoles(t *testing.T, rctx request.CTX, ss store.Store) {
|
|
createDefaultRoles(ss)
|
|
|
|
teamScheme1 := &model.Scheme{
|
|
DisplayName: model.NewId(),
|
|
Name: model.NewId(),
|
|
Description: model.NewId(),
|
|
Scope: model.SchemeScopeTeam,
|
|
}
|
|
teamScheme1, err := ss.Scheme().Save(teamScheme1)
|
|
require.NoError(t, err)
|
|
defer ss.Scheme().Delete(teamScheme1.Id)
|
|
|
|
teamScheme2 := &model.Scheme{
|
|
DisplayName: model.NewId(),
|
|
Name: model.NewId(),
|
|
Description: model.NewId(),
|
|
Scope: model.SchemeScopeTeam,
|
|
}
|
|
teamScheme2, err = ss.Scheme().Save(teamScheme2)
|
|
require.NoError(t, err)
|
|
defer ss.Scheme().Delete(teamScheme2.Id)
|
|
|
|
channelScheme1 := &model.Scheme{
|
|
DisplayName: model.NewId(),
|
|
Name: model.NewId(),
|
|
Description: model.NewId(),
|
|
Scope: model.SchemeScopeChannel,
|
|
}
|
|
channelScheme1, err = ss.Scheme().Save(channelScheme1)
|
|
require.NoError(t, err)
|
|
defer ss.Scheme().Delete(channelScheme1.Id)
|
|
|
|
channelScheme2 := &model.Scheme{
|
|
DisplayName: model.NewId(),
|
|
Name: model.NewId(),
|
|
Description: model.NewId(),
|
|
Scope: model.SchemeScopeChannel,
|
|
}
|
|
channelScheme2, err = ss.Scheme().Save(channelScheme2)
|
|
require.NoError(t, err)
|
|
defer ss.Scheme().Delete(channelScheme1.Id)
|
|
|
|
team1 := &model.Team{
|
|
DisplayName: "Name",
|
|
Name: "zz" + model.NewId(),
|
|
Email: MakeEmail(),
|
|
Type: model.TeamOpen,
|
|
SchemeId: &teamScheme1.Id,
|
|
}
|
|
team1, err = ss.Team().Save(team1)
|
|
require.NoError(t, err)
|
|
defer ss.Team().PermanentDelete(team1.Id)
|
|
|
|
team2 := &model.Team{
|
|
DisplayName: "Name",
|
|
Name: "zz" + model.NewId(),
|
|
Email: MakeEmail(),
|
|
Type: model.TeamOpen,
|
|
SchemeId: &teamScheme2.Id,
|
|
}
|
|
team2, err = ss.Team().Save(team2)
|
|
require.NoError(t, err)
|
|
defer ss.Team().PermanentDelete(team2.Id)
|
|
|
|
channel1 := &model.Channel{
|
|
TeamId: team1.Id,
|
|
DisplayName: "Display " + model.NewId(),
|
|
Name: "zz" + model.NewId() + "b",
|
|
Type: model.ChannelTypeOpen,
|
|
SchemeId: &channelScheme1.Id,
|
|
}
|
|
channel1, nErr := ss.Channel().Save(rctx, channel1, -1)
|
|
require.NoError(t, nErr)
|
|
defer ss.Channel().Delete(channel1.Id, 0)
|
|
|
|
channel2 := &model.Channel{
|
|
TeamId: team2.Id,
|
|
DisplayName: "Display " + model.NewId(),
|
|
Name: "zz" + model.NewId() + "b",
|
|
Type: model.ChannelTypeOpen,
|
|
SchemeId: &channelScheme2.Id,
|
|
}
|
|
channel2, nErr = ss.Channel().Save(rctx, channel2, -1)
|
|
require.NoError(t, nErr)
|
|
defer ss.Channel().Delete(channel2.Id, 0)
|
|
|
|
t.Run("ChannelRolesUnderTeamRole", func(t *testing.T) {
|
|
t.Run("guest role for the right team's channels are returned", func(t *testing.T) {
|
|
actualRoles, err := ss.Role().ChannelRolesUnderTeamRole(teamScheme1.DefaultChannelGuestRole)
|
|
require.NoError(t, err)
|
|
|
|
roleByName := make(map[string]*model.Role, len(actualRoles))
|
|
for _, role := range actualRoles {
|
|
roleByName[role.Name] = role
|
|
}
|
|
|
|
require.Contains(t, roleByName, channelScheme1.DefaultChannelGuestRole)
|
|
require.NotContains(t, roleByName, channelScheme2.DefaultChannelGuestRole)
|
|
require.NotNil(t, roleByName[channelScheme1.DefaultChannelGuestRole].SchemeId)
|
|
assert.Equal(t, channelScheme1.Id, *roleByName[channelScheme1.DefaultChannelGuestRole].SchemeId)
|
|
})
|
|
|
|
t.Run("user role for the right team's channels are returned", func(t *testing.T) {
|
|
actualRoles, err := ss.Role().ChannelRolesUnderTeamRole(teamScheme1.DefaultChannelUserRole)
|
|
require.NoError(t, err)
|
|
|
|
roleByName := make(map[string]*model.Role, len(actualRoles))
|
|
for _, role := range actualRoles {
|
|
roleByName[role.Name] = role
|
|
}
|
|
|
|
require.Contains(t, roleByName, channelScheme1.DefaultChannelUserRole)
|
|
require.NotContains(t, roleByName, channelScheme2.DefaultChannelUserRole)
|
|
require.NotNil(t, roleByName[channelScheme1.DefaultChannelUserRole].SchemeId)
|
|
assert.Equal(t, channelScheme1.Id, *roleByName[channelScheme1.DefaultChannelUserRole].SchemeId)
|
|
})
|
|
|
|
t.Run("admin role for the right team's channels are returned", func(t *testing.T) {
|
|
actualRoles, err := ss.Role().ChannelRolesUnderTeamRole(teamScheme1.DefaultChannelAdminRole)
|
|
require.NoError(t, err)
|
|
|
|
roleByName := make(map[string]*model.Role, len(actualRoles))
|
|
for _, role := range actualRoles {
|
|
roleByName[role.Name] = role
|
|
}
|
|
|
|
require.Contains(t, roleByName, channelScheme1.DefaultChannelAdminRole)
|
|
require.NotContains(t, roleByName, channelScheme2.DefaultChannelAdminRole)
|
|
require.NotNil(t, roleByName[channelScheme1.DefaultChannelAdminRole].SchemeId)
|
|
assert.Equal(t, channelScheme1.Id, *roleByName[channelScheme1.DefaultChannelAdminRole].SchemeId)
|
|
})
|
|
})
|
|
|
|
t.Run("AllChannelSchemeRoles", func(t *testing.T) {
|
|
t.Run("guest role for the right team's channels are returned", func(t *testing.T) {
|
|
actualRoles, err := ss.Role().AllChannelSchemeRoles()
|
|
require.NoError(t, err)
|
|
|
|
roleByName := make(map[string]*model.Role, len(actualRoles))
|
|
for _, role := range actualRoles {
|
|
roleByName[role.Name] = role
|
|
}
|
|
|
|
allRoleNames := []string{
|
|
channelScheme1.DefaultChannelGuestRole,
|
|
channelScheme2.DefaultChannelGuestRole,
|
|
|
|
channelScheme1.DefaultChannelUserRole,
|
|
channelScheme2.DefaultChannelUserRole,
|
|
|
|
channelScheme1.DefaultChannelAdminRole,
|
|
channelScheme2.DefaultChannelAdminRole,
|
|
}
|
|
|
|
for _, roleName := range allRoleNames {
|
|
require.Contains(t, roleByName, roleName)
|
|
}
|
|
|
|
// Roles for channelScheme1 must carry channelScheme1's ID.
|
|
for _, roleName := range []string{
|
|
channelScheme1.DefaultChannelGuestRole,
|
|
channelScheme1.DefaultChannelUserRole,
|
|
channelScheme1.DefaultChannelAdminRole,
|
|
} {
|
|
require.NotNil(t, roleByName[roleName].SchemeId)
|
|
assert.Equal(t, channelScheme1.Id, *roleByName[roleName].SchemeId)
|
|
}
|
|
|
|
// Roles for channelScheme2 must carry channelScheme2's ID.
|
|
for _, roleName := range []string{
|
|
channelScheme2.DefaultChannelGuestRole,
|
|
channelScheme2.DefaultChannelUserRole,
|
|
channelScheme2.DefaultChannelAdminRole,
|
|
} {
|
|
require.NotNil(t, roleByName[roleName].SchemeId)
|
|
assert.Equal(t, channelScheme2.Id, *roleByName[roleName].SchemeId)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
func testRoleStoreChannelHigherScopedPermissionsBlankTeamSchemeChannelGuest(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) {
|
|
teamScheme := &model.Scheme{
|
|
DisplayName: model.NewId(),
|
|
Name: model.NewId(),
|
|
Description: model.NewId(),
|
|
Scope: model.SchemeScopeTeam,
|
|
}
|
|
teamScheme, err := ss.Scheme().Save(teamScheme)
|
|
require.NoError(t, err)
|
|
defer ss.Scheme().Delete(teamScheme.Id)
|
|
|
|
channelScheme := &model.Scheme{
|
|
DisplayName: model.NewId(),
|
|
Name: model.NewId(),
|
|
Description: model.NewId(),
|
|
Scope: model.SchemeScopeChannel,
|
|
}
|
|
channelScheme, err = ss.Scheme().Save(channelScheme)
|
|
require.NoError(t, err)
|
|
defer ss.Scheme().Delete(channelScheme.Id)
|
|
|
|
team := &model.Team{
|
|
DisplayName: "Name",
|
|
Name: "zz" + model.NewId(),
|
|
Email: MakeEmail(),
|
|
Type: model.TeamOpen,
|
|
SchemeId: &teamScheme.Id,
|
|
}
|
|
team, err = ss.Team().Save(team)
|
|
require.NoError(t, err)
|
|
defer ss.Team().PermanentDelete(team.Id)
|
|
|
|
channel := &model.Channel{
|
|
TeamId: team.Id,
|
|
DisplayName: "Display " + model.NewId(),
|
|
Name: "zz" + model.NewId() + "b",
|
|
Type: model.ChannelTypeOpen,
|
|
SchemeId: &channelScheme.Id,
|
|
}
|
|
channel, nErr := ss.Channel().Save(rctx, channel, -1)
|
|
require.NoError(t, nErr)
|
|
defer ss.Channel().Delete(channel.Id, 0)
|
|
|
|
channelSchemeUserRole, err := ss.Role().GetByName(context.Background(), channelScheme.DefaultChannelUserRole)
|
|
require.NoError(t, err)
|
|
channelSchemeUserRole.Permissions = []string{}
|
|
_, err = ss.Role().Save(channelSchemeUserRole)
|
|
require.NoError(t, err)
|
|
|
|
teamSchemeUserRole, err := ss.Role().GetByName(context.Background(), teamScheme.DefaultChannelUserRole)
|
|
require.NoError(t, err)
|
|
teamSchemeUserRole.Permissions = []string{model.PermissionUploadFile.Id}
|
|
_, err = ss.Role().Save(teamSchemeUserRole)
|
|
require.NoError(t, err)
|
|
|
|
// get the channel scheme user role again and ensure that it has the permission inherited from the team
|
|
// scheme user role
|
|
roleMapBefore, err := ss.Role().ChannelHigherScopedPermissions([]string{channelSchemeUserRole.Name})
|
|
require.NoError(t, err)
|
|
|
|
// blank-out the guest role to simulate an old team scheme, ensure it's blank
|
|
result, sqlErr := s.GetMaster().Exec(fmt.Sprintf("UPDATE Schemes SET DefaultChannelGuestRole = '' WHERE Id = '%s'", teamScheme.Id))
|
|
require.NoError(t, sqlErr)
|
|
rows, serr := result.RowsAffected()
|
|
require.NoError(t, serr)
|
|
require.Equal(t, int64(1), rows)
|
|
teamScheme, err = ss.Scheme().Get(teamScheme.Id)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "", teamScheme.DefaultChannelGuestRole)
|
|
|
|
// trigger a cache clear
|
|
_, err = ss.Role().Save(channelSchemeUserRole)
|
|
require.NoError(t, err)
|
|
|
|
roleMapAfter, err := ss.Role().ChannelHigherScopedPermissions([]string{channelSchemeUserRole.Name})
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(roleMapBefore), len(roleMapAfter))
|
|
}
|