Access Control: Fix plugin async install role registration (#112123)

This commit is contained in:
Todd Treece
2025-10-10 09:44:02 -04:00
committed by GitHub
parent f4e7dfe827
commit 89da0bf178
3 changed files with 276 additions and 39 deletions
+202 -11
View File
@@ -31,7 +31,7 @@ func TestMain(m *testing.M) {
testsuite.Run(m)
}
func setupTestEnv(t testing.TB) *Service {
func setupTestEnv(t testing.TB, registerRoles bool) *Service {
t.Helper()
cfg := setting.NewCfg()
@@ -46,7 +46,11 @@ func setupTestEnv(t testing.TB) *Service {
permRegistry: permreg.ProvidePermissionRegistry(),
actionResolver: resourcepermissions.NewActionSetService(),
}
require.NoError(t, ac.RegisterFixedRoles(context.Background()))
if registerRoles {
require.NoError(t, ac.RegisterFixedRoles(context.Background()))
}
return ac
}
@@ -145,7 +149,7 @@ func TestIntegrationService_DeclareFixedRoles(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ac := setupTestEnv(t)
ac := setupTestEnv(t, true)
// Reset the registations
ac.registrations = accesscontrol.RegistrationList{}
@@ -260,7 +264,7 @@ func TestIntegrationService_DeclarePluginRoles(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ac := setupTestEnv(t)
ac := setupTestEnv(t, true)
// Reset the registations
ac.registrations = accesscontrol.RegistrationList{}
@@ -361,7 +365,7 @@ func TestIntegrationService_RegisterFixedRoles(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ac := setupTestEnv(t)
ac := setupTestEnv(t, true)
ac.registrations.Append(tt.registrations...)
@@ -389,6 +393,193 @@ func TestIntegrationService_RegisterFixedRoles(t *testing.T) {
}
}
func TestIntegrationService_DeclarePluginRoles_DynamicRegistration(t *testing.T) {
testutil.SkipIntegrationTestInShortMode(t)
tests := []struct {
name string
postRegister bool
pluginID string
registrations []plugins.RoleRegistration
wantGrantedRoles []string
wantPermissions []string
wantPermCount int
}{
{
name: "should register plugin roles before initialization",
postRegister: false,
pluginID: "test-app",
registrations: []plugins.RoleRegistration{
{
Role: plugins.Role{
Name: "Reader",
Description: "Test reader role",
Permissions: []plugins.Permission{
{Action: "test-app:read", Scope: "test-app:*"},
},
},
Grants: []string{string(identity.RoleViewer)},
},
},
wantGrantedRoles: []string{string(identity.RoleViewer)},
wantPermissions: []string{"test-app:read"},
wantPermCount: 1,
},
{
name: "should register plugin roles dynamically after initialization",
postRegister: true,
pluginID: "dynamic-app",
registrations: []plugins.RoleRegistration{
{
Role: plugins.Role{
Name: "DynamicReader",
Description: "Dynamic reader role",
Permissions: []plugins.Permission{
{Action: "dynamic-app:read", Scope: "dynamic-app:*"},
{Action: "dynamic-app:query", Scope: "dynamic-app:*"},
},
},
Grants: []string{string(identity.RoleViewer)},
},
},
wantGrantedRoles: []string{string(identity.RoleViewer)},
wantPermissions: []string{"dynamic-app:read", "dynamic-app:query"},
wantPermCount: 2,
},
{
name: "should grant to multiple roles dynamically",
postRegister: true,
pluginID: "multi-app",
registrations: []plugins.RoleRegistration{
{
Role: plugins.Role{
Name: "MultiReader",
Description: "Multi reader role",
Permissions: []plugins.Permission{
{Action: "multi-app:read", Scope: "multi-app:*"},
},
},
Grants: []string{string(identity.RoleViewer), string(identity.RoleEditor)},
},
},
wantGrantedRoles: []string{string(identity.RoleViewer), string(identity.RoleEditor)},
wantPermissions: []string{"multi-app:read"},
wantPermCount: 1,
},
{
name: "should register multiple permissions dynamically",
postRegister: true,
pluginID: "batch-app",
registrations: []plugins.RoleRegistration{
{
Role: plugins.Role{
Name: "BatchReader",
Permissions: []plugins.Permission{
{Action: "batch-app:read"},
{Action: "batch-app:write"},
{Action: "batch-app:delete"},
},
},
Grants: []string{string(identity.RoleEditor)},
},
},
wantGrantedRoles: []string{string(identity.RoleEditor)},
wantPermissions: []string{"batch-app:read", "batch-app:write", "batch-app:delete"},
wantPermCount: 3,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ac := setupTestEnv(t, tt.postRegister)
initialPermCounts := make(map[string]int)
for _, roleName := range tt.wantGrantedRoles {
if role, ok := ac.roles[roleName]; ok {
initialPermCounts[roleName] = len(role.Permissions)
}
}
err := ac.DeclarePluginRoles(context.Background(), tt.pluginID, tt.pluginID, tt.registrations)
require.NoError(t, err)
if !tt.postRegister {
err = ac.RegisterFixedRoles(context.Background())
require.NoError(t, err)
}
// Verify permissions were added to expected roles
for _, roleName := range tt.wantGrantedRoles {
role, ok := ac.roles[roleName]
require.True(t, ok, "Role %s should exist", roleName)
expectedCount := initialPermCounts[roleName] + tt.wantPermCount
assert.Equal(t, expectedCount, len(role.Permissions))
actions := make([]string, 0, len(role.Permissions))
for _, perm := range role.Permissions {
actions = append(actions, perm.Action)
}
for _, wantAction := range tt.wantPermissions {
assert.Contains(t, actions, wantAction, "Role %s should have permission %s", roleName, wantAction)
}
}
})
}
}
func TestIntegrationService_DeclarePluginRoles_UserPermissions(t *testing.T) {
testutil.SkipIntegrationTestInShortMode(t)
t.Run("dynamic registration should be reflected in user permissions", func(t *testing.T) {
ac := setupTestEnv(t, true)
// Create a test user with Viewer role
testUser := &user.SignedInUser{
UserID: 1,
OrgID: 1,
OrgRole: identity.RoleViewer,
}
// Get initial permissions
initialPerms, err := ac.getUserPermissions(context.Background(), testUser, accesscontrol.Options{})
require.NoError(t, err)
initialCount := len(initialPerms)
// Register plugin roles dynamically
err = ac.DeclarePluginRoles(context.Background(), "perm-test-app", "Perm Test App", []plugins.RoleRegistration{
{
Role: plugins.Role{
Name: "PermTester",
Description: "Permission test role",
Permissions: []plugins.Permission{
{Action: "perm-test-app:test", Scope: "perm-test-app:*"},
},
},
Grants: []string{string(identity.RoleViewer)},
},
})
require.NoError(t, err)
updatedPerms, err := ac.getUserPermissions(context.Background(), testUser, accesscontrol.Options{})
require.NoError(t, err)
require.Greater(t, len(updatedPerms), initialCount)
hasNewPerm := false
hasNewScope := false
for _, perm := range updatedPerms {
if perm.Action == "perm-test-app:test" {
hasNewPerm = true
}
if perm.Scope == "perm-test-app:*" {
hasNewScope = true
}
}
assert.True(t, hasNewPerm)
assert.True(t, hasNewScope)
})
}
func TestIntegrationService_SearchUsersPermissions(t *testing.T) {
testutil.SkipIntegrationTestInShortMode(t)
@@ -585,7 +776,7 @@ func TestIntegrationService_SearchUsersPermissions(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ac := setupTestEnv(t)
ac := setupTestEnv(t, true)
ac.roles = tt.ramRoles
ac.store = actest.FakeStore{
@@ -817,7 +1008,7 @@ func TestIntegrationService_SearchUserPermissions(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ac := setupTestEnv(t)
ac := setupTestEnv(t, true)
if tt.withActionSets {
actionSetSvc := resourcepermissions.NewActionSetService()
for set, actions := range tt.actionSets {
@@ -913,7 +1104,7 @@ func TestIntegrationService_SaveExternalServiceRole(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
ac := setupTestEnv(t)
ac := setupTestEnv(t, true)
ac.cfg.ManagedServiceAccountsEnabled = true
ac.features = featuremgmt.WithFeatures(featuremgmt.FlagExternalServiceAccounts)
for _, r := range tt.runs {
@@ -969,7 +1160,7 @@ func TestIntegrationService_DeleteExternalServiceRole(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
ac := setupTestEnv(t)
ac := setupTestEnv(t, true)
ac.cfg.ManagedServiceAccountsEnabled = true
ac.features = featuremgmt.WithFeatures(featuremgmt.FlagExternalServiceAccounts)
@@ -1006,7 +1197,7 @@ func TestIntegrationService_GetRoleByName(t *testing.T) {
t.Run("when the role does not exists, it returns an error", func(t *testing.T) {
t.Parallel()
ac := setupTestEnv(t)
ac := setupTestEnv(t, true)
ac.registrations = accesscontrol.RegistrationList{}
role, err := ac.GetRoleByName(ctx, 0, "not-found-role")
@@ -1019,7 +1210,7 @@ func TestIntegrationService_GetRoleByName(t *testing.T) {
roleName := "fixed:test:test"
ac := setupTestEnv(t)
ac := setupTestEnv(t, true)
ac.registrations = accesscontrol.RegistrationList{}
ac.registrations.Append(accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{Name: roleName},