App Installer: Authorizer support (#108419)

This commit is contained in:
Todd Treece
2025-07-22 06:45:01 -04:00
committed by GitHub
parent ec9da2678a
commit 52a0485d5b
3 changed files with 167 additions and 0 deletions
@@ -86,6 +86,27 @@ func RegisterAdmissionPlugins(
return nil
}
type AuthorizerRegistrar interface {
Register(gv schema.GroupVersion, authorizer authorizer.Authorizer)
}
func RegisterAuthorizers(
ctx context.Context,
appInstallers []appsdkapiserver.AppInstaller,
registrar AuthorizerRegistrar,
) {
logger := logging.FromContext(ctx)
for _, installer := range appInstallers {
if authorizerProvider, ok := installer.(AuthorizerProvider); ok {
authorizer := authorizerProvider.GetAuthorizer()
for _, gv := range installer.GroupVersions() {
registrar.Register(gv, authorizer)
logger.Debug("Registered authorizer", "group", gv.Group, "version", gv.Version, "app")
}
}
}
}
func BuildOpenAPIDefGetter(
appInstallers []appsdkapiserver.AppInstaller,
) func(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
@@ -0,0 +1,143 @@
package appinstaller
import (
"context"
"testing"
appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/authorization/authorizer"
)
func TestRegisterAuthorizers(t *testing.T) {
tests := []struct {
name string
appInstallers []appsdkapiserver.AppInstaller
expectedRegisters int
}{
{
name: "empty installers list",
appInstallers: []appsdkapiserver.AppInstaller{},
expectedRegisters: 0,
},
{
name: "installer without authorizer provider",
appInstallers: []appsdkapiserver.AppInstaller{
&mockAppInstaller{
groupVersions: []schema.GroupVersion{
{Group: "test.example.com", Version: "v1"},
},
},
},
expectedRegisters: 0,
},
{
name: "single installer with authorizer provider",
appInstallers: []appsdkapiserver.AppInstaller{
&mockAppInstallerWithAuth{
mockAppInstaller: &mockAppInstaller{
groupVersions: []schema.GroupVersion{
{Group: "test.example.com", Version: "v1"},
},
},
mockAuthorizer: &mockAuthorizer{},
},
},
expectedRegisters: 1,
},
{
name: "installer with multiple group versions",
appInstallers: []appsdkapiserver.AppInstaller{
&mockAppInstallerWithAuth{
mockAppInstaller: &mockAppInstaller{
groupVersions: []schema.GroupVersion{
{Group: "test.example.com", Version: "v1"},
{Group: "test.example.com", Version: "v2"},
{Group: "other.example.com", Version: "v1"},
},
},
mockAuthorizer: &mockAuthorizer{},
},
},
expectedRegisters: 3,
},
{
name: "multiple installers with mixed authorizer support",
appInstallers: []appsdkapiserver.AppInstaller{
&mockAppInstallerWithAuth{
mockAppInstaller: &mockAppInstaller{
groupVersions: []schema.GroupVersion{
{Group: "test.example.com", Version: "v1"},
},
},
mockAuthorizer: &mockAuthorizer{},
},
&mockAppInstaller{
groupVersions: []schema.GroupVersion{
{Group: "other.example.com", Version: "v1"},
},
},
&mockAppInstallerWithAuth{
mockAppInstaller: &mockAppInstaller{
groupVersions: []schema.GroupVersion{
{Group: "another.example.com", Version: "v1"},
{Group: "another.example.com", Version: "v2"},
},
},
mockAuthorizer: &mockAuthorizer{},
},
},
expectedRegisters: 3, // 1 from first installer + 2 from third installer
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
registrar := &mockAuthorizerRegistrar{}
RegisterAuthorizers(ctx, tt.appInstallers, registrar)
require.Equal(t, tt.expectedRegisters, len(registrar.registrations))
})
}
}
type mockAppInstaller struct {
appsdkapiserver.AppInstaller // Embed the interface
groupVersions []schema.GroupVersion
}
func (m *mockAppInstaller) GroupVersions() []schema.GroupVersion {
return m.groupVersions
}
type mockAppInstallerWithAuth struct {
*mockAppInstaller
mockAuthorizer authorizer.Authorizer
}
func (m *mockAppInstallerWithAuth) GetAuthorizer() authorizer.Authorizer {
return m.mockAuthorizer
}
type mockRegistration struct {
groupVersion schema.GroupVersion
authorizer authorizer.Authorizer
}
type mockAuthorizerRegistrar struct {
registrations []mockRegistration
}
func (m *mockAuthorizerRegistrar) Register(gv schema.GroupVersion, auth authorizer.Authorizer) {
m.registrations = append(m.registrations, mockRegistration{
groupVersion: gv,
authorizer: auth,
})
}
type mockAuthorizer struct{}
func (m *mockAuthorizer) Authorize(ctx context.Context, attr authorizer.Attributes) (authorizer.Decision, string, error) {
return authorizer.DecisionAllow, "test", nil
}
+3
View File
@@ -292,6 +292,9 @@ func (s *service) start(ctx context.Context) error {
return err
}
// Register authorizers from app installers
appinstaller.RegisterAuthorizers(ctx, s.appInstallers, s.authorizer)
err = applyGrafanaConfig(s.cfg, s.features, o)
if err != nil {
return err