Skip to content

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
Signed-off-by: Per Goncalves da Silva <[email protected]>
  • Loading branch information
Per Goncalves da Silva committed Feb 27, 2025
1 parent 7807c56 commit 1c2f38f
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 8 deletions.
30 changes: 22 additions & 8 deletions internal/operator-controller/action/restconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,36 @@ import (

ocv1 "github.com/operator-framework/operator-controller/api/v1"
"github.com/operator-framework/operator-controller/internal/operator-controller/authentication"
"github.com/operator-framework/operator-controller/internal/operator-controller/features"
)

func ClusterExtensionUserRestConfigMapper(tokenGetter *authentication.TokenGetter) func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
saRestConfigMapper := serviceAccountRestConfigMapper(tokenGetter)
synthRestConfigMapper := sythenticUserRestConfigMapper()
const syntheticServiceAccountName = "olmv1:synthetic"

type clusterExtensionRestConfigMapper struct {
saRestConfigMapper func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error)
synthUserRestConfigMapper func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error)
}

func (m *clusterExtensionRestConfigMapper) mapper() func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
synthAuthFeatureEnabled := features.OperatorControllerFeatureGate.Enabled(features.SyntheticPermissions)
return func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
cExt := o.(*ocv1.ClusterExtension)
if cExt.Spec.ServiceAccount != nil { //nolint:staticcheck
return saRestConfigMapper(ctx, o, c)
if synthAuthFeatureEnabled && cExt.Spec.ServiceAccount.Name == syntheticServiceAccountName {
return m.synthUserRestConfigMapper(ctx, o, c)
}
return synthRestConfigMapper(ctx, o, c)
return m.saRestConfigMapper(ctx, o, c)
}
}

func ClusterExtensionUserRestConfigMapper(tokenGetter *authentication.TokenGetter) func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
m := &clusterExtensionRestConfigMapper{
saRestConfigMapper: serviceAccountRestConfigMapper(tokenGetter),
synthUserRestConfigMapper: syntheticUserRestConfigMapper(),
}
return m.mapper()
}

func sythenticUserRestConfigMapper() func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
func syntheticUserRestConfigMapper() func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
return func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
cExt := o.(*ocv1.ClusterExtension)
cc := rest.CopyConfig(c)
Expand All @@ -41,7 +55,7 @@ func serviceAccountRestConfigMapper(tokenGetter *authentication.TokenGetter) fun
return func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
cExt := o.(*ocv1.ClusterExtension)
saKey := types.NamespacedName{
Name: cExt.Spec.ServiceAccount.Name, //nolint:staticcheck
Name: cExt.Spec.ServiceAccount.Name,
Namespace: cExt.Spec.Namespace,
}
saConfig := rest.AnonymousClientConfig(c)
Expand Down
92 changes: 92 additions & 0 deletions internal/operator-controller/action/restconfig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package action

import (
"context"
"testing"

"github.com/stretchr/testify/require"
"k8s.io/client-go/rest"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"sigs.k8s.io/controller-runtime/pkg/client"

ocv1 "github.com/operator-framework/operator-controller/api/v1"
"github.com/operator-framework/operator-controller/internal/operator-controller/features"
)

const (
saAccountWrapper = "service account wrapper"
synthUserWrapper = "synthetic user wrapper"
)

func fakeRestConfigWrapper() clusterExtensionRestConfigMapper {
// The rest config's host field is artificially used to differentiate between the wrappers
return clusterExtensionRestConfigMapper{
saRestConfigMapper: func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
return &rest.Config{
Host: saAccountWrapper,
}, nil
},
synthUserRestConfigMapper: func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
return &rest.Config{
Host: synthUserWrapper,
}, nil
},
}
}

func TestMapper_SyntheticPermissionsEnabled(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.SyntheticPermissions, true)

for _, tc := range []struct {
description string
serviceAccountName string
expectedMapper string
fgEnabled bool
}{
{
description: "user service account wrapper if extension service account is _not_ called olmv1:synthetic",
serviceAccountName: "_not_:olmv1:synthetic",
expectedMapper: saAccountWrapper,
fgEnabled: true,
}, {
description: "user synthetic user wrapper is extension service account is called olmv1:synthetic",
serviceAccountName: "olmv1:synthetic",
expectedMapper: synthUserWrapper,
fgEnabled: true,
},
} {
t.Run(tc.description, func(t *testing.T) {
m := fakeRestConfigWrapper()
mapper := m.mapper()
ext := &ocv1.ClusterExtension{
Spec: ocv1.ClusterExtensionSpec{
ServiceAccount: ocv1.ServiceAccountReference{
Name: tc.serviceAccountName,
},
},
}
cfg, err := mapper(context.Background(), ext, &rest.Config{})
require.NoError(t, err)

// The rest config's host field is artificially used to differentiate between the wrappers
require.Equal(t, tc.expectedMapper, cfg.Host)
})
}
}

func TestMapper_SyntheticPermissionsDisabled(t *testing.T) {
m := fakeRestConfigWrapper()
mapper := m.mapper()
ext := &ocv1.ClusterExtension{
Spec: ocv1.ClusterExtensionSpec{
ServiceAccount: ocv1.ServiceAccountReference{
Name: "olmv1:synthetic",
},
},
}
cfg, err := mapper(context.Background(), ext, &rest.Config{})
require.NoError(t, err)

// The rest config's host field is artificially used to differentiate between the wrappers
require.Equal(t, saAccountWrapper, cfg.Host)
}
43 changes: 43 additions & 0 deletions internal/operator-controller/authentication/synthetic_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package authentication_test

import (
"testing"

"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

ocv1 "github.com/operator-framework/operator-controller/api/v1"
"github.com/operator-framework/operator-controller/internal/operator-controller/authentication"
)

func TestSyntheticUserName(t *testing.T) {
syntheticUserName := authentication.SyntheticUserName(ocv1.ClusterExtension{
ObjectMeta: metav1.ObjectMeta{
Name: "my-ext",
},
})
require.Equal(t, "olmv1:clusterextensions:my-ext:admin", syntheticUserName)
}

func TestSyntheticGroups(t *testing.T) {
syntheticGroups := authentication.SyntheticGroups(ocv1.ClusterExtension{})
require.Equal(t, []string{
"olmv1:clusterextensions:admin",
"system:authenticated",
}, syntheticGroups)
}

func TestSyntheticImpersonationConfig(t *testing.T) {
config := authentication.SyntheticImpersonationConfig(ocv1.ClusterExtension{
ObjectMeta: metav1.ObjectMeta{
Name: "my-ext",
},
})
require.Equal(t, "olmv1:clusterextensions:my-ext:admin", config.UserName)
require.Equal(t, []string{
"olmv1:clusterextensions:admin",
"system:authenticated",
}, config.Groups)
require.Empty(t, config.UID)
require.Empty(t, config.Extra)
}

0 comments on commit 1c2f38f

Please sign in to comment.