Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
004ef42
chore: renamed store referenece path into cluster field
OlegErshov Dec 30, 2025
241afff
feat: introduce v1alpha2 api version
OlegErshov Dec 30, 2025
2e443df
feat: renamed field in v1alpha1 version and introduced a migration fu…
OlegErshov Jan 8, 2026
81fc9ff
Merge branch 'main' into feat/authz-model-store-path-renaming
OlegErshov Jan 8, 2026
a365296
Merge branch 'main' into feat/authz-model-store-path-renaming
OlegErshov Jan 8, 2026
97d8597
fix: updated resource schema
OlegErshov Jan 8, 2026
3fda111
use patch instead of update
OlegErshov Jan 8, 2026
c2b74bd
chore:fixed typos
OlegErshov Jan 8, 2026
743f27f
Merge branch 'main' into feat/authz-model-store-path-renaming
OlegErshov Jan 9, 2026
d946016
chore: little refactoring
OlegErshov Jan 9, 2026
5925c7e
fixed typo
OlegErshov Jan 9, 2026
14e5504
Merge branch 'main' into feat/authz-model-store-path-renaming
OlegErshov Jan 12, 2026
d4a75a1
added back deprecated path field
OlegErshov Jan 12, 2026
b3118cf
moved migration at the beggining of the operator run function
OlegErshov Jan 12, 2026
ab20dd6
Merge branch 'main' into feat/authz-model-store-path-renaming
OlegErshov Jan 12, 2026
9171299
Merge branch 'main' into feat/authz-model-store-path-renaming
OlegErshov Jan 13, 2026
7f465f2
switched to the typed approach
OlegErshov Jan 13, 2026
63b57aa
placed logicalClusterClientFromKey function usage only within Run fun…
OlegErshov Jan 13, 2026
0ab79ab
Merge branch 'main' into feat/authz-model-store-path-renaming
OlegErshov Jan 14, 2026
3801798
Merge branch 'main' into feat/authz-model-store-path-renaming
OlegErshov Jan 16, 2026
654abaf
fix: addressed import errors
OlegErshov Jan 16, 2026
b28566f
fix: addressed linter errors
OlegErshov Jan 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ vars:
CRD_DIRECTORY: config/crd/bases
KCP_APIGEN_VERSION: v0.21.0
KCP_VERSION: 0.28.3
GOLANGCI_LINT_VERSION: v2.5.0
GOLANGCI_LINT_VERSION: v2.8.0
GOARCH:
sh: go env GOARCH
GOOS:
Expand Down
8 changes: 6 additions & 2 deletions api/v1alpha1/authorizationmodel_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import (
)

type WorkspaceStoreRef struct {
Name string `json:"name"`
Path string `json:"path"`
Name string `json:"name"`
Cluster string `json:"cluster"`
// Path is deprecated. Use Cluster instead.
// +kubebuilder:validation:Optional
// +kubebuilder:deprecatedversion:warning="v1alpha1"
Path string `json:"path,omitempty"`
}

// AuthorizationModelSpec defines the desired state of AuthorizationModel.
Expand Down
2 changes: 1 addition & 1 deletion cmd/initializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ var initializerCmd = &cobra.Command{
utilruntime.Must(sourcev1.AddToScheme(runtimeScheme))
utilruntime.Must(helmv2.AddToScheme(runtimeScheme))

orgClient, err := logicalClusterClientFromKey(mgr.GetLocalManager(), log)(logicalcluster.Name("root:orgs"))
orgClient, err := logicalClusterClientFromKey(mgr.GetLocalManager().GetConfig(), log)(logicalcluster.Name("root:orgs"))
if err != nil {
setupLog.Error(err, "Failed to create org client")
os.Exit(1)
Expand Down
56 changes: 52 additions & 4 deletions cmd/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ var (

type NewLogicalClusterClientFunc func(clusterKey logicalcluster.Name) (client.Client, error)

func logicalClusterClientFromKey(mgr ctrl.Manager, log *logger.Logger) NewLogicalClusterClientFunc {
func logicalClusterClientFromKey(config *rest.Config, log *logger.Logger) NewLogicalClusterClientFunc {
return func(clusterKey logicalcluster.Name) (client.Client, error) {
cfg := rest.CopyConfig(mgr.GetConfig())
cfg := rest.CopyConfig(config)

parsed, err := url.Parse(cfg.Host)
if err != nil {
Expand Down Expand Up @@ -78,6 +78,13 @@ var operatorCmd = &cobra.Command{
return err
}

if operatorCfg.MigrateAuthorizationModels {
if err := migrateAuthorizationModels(ctx, restCfg, scheme, logicalClusterClientFromKey(restCfg, log)); err != nil {
log.Error().Err(err).Msg("migration failed")
return err
}
}

if defaultCfg.Sentry.Dsn != "" {
err := sentry.Start(ctx,
defaultCfg.Sentry.Dsn, defaultCfg.Environment, defaultCfg.Region,
Expand Down Expand Up @@ -140,7 +147,7 @@ var operatorCmd = &cobra.Command{
return err
}

orgClient, err := logicalClusterClientFromKey(mgr.GetLocalManager(), log)(logicalcluster.Name("root:orgs"))
orgClient, err := logicalClusterClientFromKey(mgr.GetLocalManager().GetConfig(), log)(logicalcluster.Name("root:orgs"))
if err != nil {
log.Error().Err(err).Msg("Failed to create org client")
return err
Expand Down Expand Up @@ -193,9 +200,50 @@ var operatorCmd = &cobra.Command{
},
}

// this function can be removed after the operator has migrated the authz models in all environments
func migrateAuthorizationModels(ctx context.Context, config *rest.Config, scheme *runtime.Scheme, getClusterClient NewLogicalClusterClientFunc) error {
allClient, err := controller.GetAllClient(config, scheme)
if err != nil {
return fmt.Errorf("failed to create all-cluster client: %w", err)
}

var models corev1alpha1.AuthorizationModelList
if err := allClient.List(ctx, &models); err != nil {
return fmt.Errorf("failed to list AuthorizationModels: %w", err)
}

for i := range models.Items {
item := &models.Items[i]

if item.Spec.StoreRef.Cluster != "" {
continue
}

if item.Spec.StoreRef.Path == "" {
return fmt.Errorf("AuthorizationModel %s has empty cluster field and no path field to migrate from", item.GetName())
}

clusterName := logicalcluster.From(item)
clusterClient, err := getClusterClient(clusterName)
if err != nil {
return fmt.Errorf("failed to create cluster client for AuthorizationModel %s (cluster %s): %w", item.GetName(), clusterName, err)
}

original := item.DeepCopy()
item.Spec.StoreRef.Cluster = item.Spec.StoreRef.Path

patch := client.MergeFrom(original)
if err := clusterClient.Patch(ctx, item, patch); err != nil {
return fmt.Errorf("failed to patch AuthorizationModel %s: %w", item.GetName(), err)
}
}

log.Info().Msg("AuthorizationModel migration completed")
return nil
}

func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))

utilruntime.Must(kcptenancyv1alphav1.AddToScheme(scheme))
utilruntime.Must(corev1alpha1.AddToScheme(scheme))
utilruntime.Must(apisv1alpha1.AddToScheme(scheme))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,16 @@ spec:
type: string
storeRef:
properties:
cluster:
type: string
name:
type: string
path:
description: Path is deprecated. Use Cluster instead.
type: string
required:
- cluster
- name
- path
type: object
tuples:
items:
Expand Down
2 changes: 1 addition & 1 deletion config/resources/apiexport-core.platform-mesh.io.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ metadata:
name: core.platform-mesh.io
spec:
latestResourceSchemas:
- v250718-a64f278.authorizationmodels.core.platform-mesh.io
- v250718-a64f278.stores.core.platform-mesh.io
- v251007-1d3512f.invites.core.platform-mesh.io
- v251215-8997bd4.identityproviderconfigurations.core.platform-mesh.io
- v260112-5925c7e.authorizationmodels.core.platform-mesh.io
status: {}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: apis.kcp.io/v1alpha1
kind: APIResourceSchema
metadata:
creationTimestamp: null
name: v250718-a64f278.authorizationmodels.core.platform-mesh.io
name: v260112-5925c7e.authorizationmodels.core.platform-mesh.io
spec:
group: core.platform-mesh.io
names:
Expand Down Expand Up @@ -40,13 +40,16 @@ spec:
type: string
storeRef:
properties:
cluster:
type: string
name:
type: string
path:
description: Path is deprecated. Use Cluster instead.
type: string
required:
- cluster
- name
- path
type: object
tuples:
items:
Expand Down
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Config struct {
DevelopmentAllowUnverifiedEmails bool `mapstructure:"development-allow-unverified-emails" default:"false"`
InitializerName string `mapstructure:"initializer-name" default:"root:security"`
DomainCALookup bool `mapstructure:"domain-ca-lookup" default:"false"`
MigrateAuthorizationModels bool `mapstructure:"migrate-authorization-models" default:"false"`
HttpClientTimeoutSeconds int `mapstructure:"http-client-timeout-seconds" default:"30"`
IDP struct {
// SMTP settings
Expand Down
9 changes: 5 additions & 4 deletions internal/controller/apibinding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ import (
mcmanager "sigs.k8s.io/multicluster-runtime/pkg/manager"
mcreconcile "sigs.k8s.io/multicluster-runtime/pkg/reconcile"

"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/rest"

kcpv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
"github.com/kcp-dev/logicalcluster/v3"
)

func getAllClient(mcMgr mcmanager.Manager) (client.Client, error) {
allCfg := rest.CopyConfig(mcMgr.GetLocalManager().GetConfig())
func GetAllClient(config *rest.Config, schema *runtime.Scheme) (client.Client, error) {
allCfg := rest.CopyConfig(config)

parsed, err := url.Parse(allCfg.Host)
if err != nil {
Expand All @@ -47,7 +48,7 @@ func getAllClient(mcMgr mcmanager.Manager) (client.Client, error) {
log.Info().Str("host", allCfg.Host).Msg("using host")

allClient, err := client.New(allCfg, client.Options{
Scheme: mcMgr.GetLocalManager().GetScheme(),
Scheme: schema,
})
if err != nil {
return nil, err
Expand All @@ -56,7 +57,7 @@ func getAllClient(mcMgr mcmanager.Manager) (client.Client, error) {
}

func NewAPIBindingReconciler(logger *logger.Logger, mcMgr mcmanager.Manager) *APIBindingReconciler {
allclient, err := getAllClient(mcMgr)
allclient, err := GetAllClient(mcMgr.GetLocalManager().GetConfig(), mcMgr.GetLocalManager().GetScheme())
if err != nil {
log.Fatal().Err(err).Msg("unable to create new client")
}
Expand Down
4 changes: 2 additions & 2 deletions internal/controller/store_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type StoreReconciler struct {
}

func NewStoreReconciler(log *logger.Logger, fga openfgav1.OpenFGAServiceClient, mcMgr mcmanager.Manager) *StoreReconciler {
allClient, err := getAllClient(mcMgr)
allClient, err := GetAllClient(mcMgr.GetLocalManager().GetConfig(), mcMgr.GetLocalManager().GetScheme())
if err != nil {
log.Fatal().Err(err).Msg("unable to create new client")
}
Expand Down Expand Up @@ -80,7 +80,7 @@ func (r *StoreReconciler) SetupWithManager(mgr mcmanager.Manager, cfg *platforme
Name: model.Spec.StoreRef.Name,
},
},
ClusterName: model.Spec.StoreRef.Path,
ClusterName: model.Spec.StoreRef.Cluster,
},
}
}),
Expand Down
16 changes: 8 additions & 8 deletions internal/subroutine/authorization_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine"
"github.com/platform-mesh/golang-commons/errors"
"github.com/platform-mesh/golang-commons/logger"
"github.com/platform-mesh/security-operator/api/v1alpha1"
securityv1alpha1 "github.com/platform-mesh/security-operator/api/v1alpha1"
"google.golang.org/protobuf/encoding/protojson"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -100,23 +100,23 @@ func (a *authorizationModelSubroutine) Finalize(ctx context.Context, instance ru
return ctrl.Result{}, nil
}

func getRelatedAuthorizationModels(ctx context.Context, k8s client.Client, store *v1alpha1.Store) (v1alpha1.AuthorizationModelList, error) {
func getRelatedAuthorizationModels(ctx context.Context, k8s client.Client, store *securityv1alpha1.Store) (securityv1alpha1.AuthorizationModelList, error) {

storeClusterKey, ok := mccontext.ClusterFrom(ctx)
if !ok {
return v1alpha1.AuthorizationModelList{}, fmt.Errorf("unable to get cluster key from context")
return securityv1alpha1.AuthorizationModelList{}, fmt.Errorf("unable to get cluster key from context")
}

allCtx := mccontext.WithCluster(ctx, "")
allAuthorizationModels := v1alpha1.AuthorizationModelList{}
allAuthorizationModels := securityv1alpha1.AuthorizationModelList{}

if err := k8s.List(allCtx, &allAuthorizationModels); err != nil {
return v1alpha1.AuthorizationModelList{}, err
return securityv1alpha1.AuthorizationModelList{}, err
}

var extendingModules v1alpha1.AuthorizationModelList
var extendingModules securityv1alpha1.AuthorizationModelList
for _, model := range allAuthorizationModels.Items {
if model.Spec.StoreRef.Name != store.Name || model.Spec.StoreRef.Path != storeClusterKey {
if model.Spec.StoreRef.Name != store.Name || model.Spec.StoreRef.Cluster != storeClusterKey {
continue
}

Expand All @@ -128,7 +128,7 @@ func getRelatedAuthorizationModels(ctx context.Context, k8s client.Client, store

func (a *authorizationModelSubroutine) Process(ctx context.Context, instance runtimeobject.RuntimeObject) (reconcile.Result, errors.OperatorError) {
log := logger.LoadLoggerFromContext(ctx)
store := instance.(*v1alpha1.Store)
store := instance.(*securityv1alpha1.Store)

extendingModules, err := getRelatedAuthorizationModels(ctx, a.allClient, store)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions internal/subroutine/authorization_model_generation.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,8 @@ func (a *AuthorizationModelGenerationSubroutine) Process(ctx context.Context, in
model.Spec = securityv1alpha1.AuthorizationModelSpec{
Model: buffer.String(),
StoreRef: securityv1alpha1.WorkspaceStoreRef{
Name: accountInfo.Spec.Organization.Name,
Path: accountInfo.Spec.Organization.OriginClusterId,
Name: accountInfo.Spec.Organization.Name,
Cluster: accountInfo.Spec.Organization.OriginClusterId,
},
}
return nil
Expand Down
Loading
Loading