From d366d3c6348c58de4e7998deb3ac9a7a6874a999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= Date: Sun, 22 Mar 2026 02:37:50 +0000 Subject: [PATCH 01/23] Add BindingSubjectsEditor for RoleBinding/ClusterRoleBinding subjects Implements a typed editor for mutating the subjects list of RBAC bindings, with EnsureSubject (upsert by Kind+Name+Namespace), RemoveSubject, and Raw access. Shared by both RoleBinding and ClusterRoleBinding primitives. Co-Authored-By: Claude Opus 4.6 (1M context) --- pkg/mutation/editors/bindingsubjects.go | 55 ++++++++++ pkg/mutation/editors/bindingsubjects_test.go | 109 +++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 pkg/mutation/editors/bindingsubjects.go create mode 100644 pkg/mutation/editors/bindingsubjects_test.go diff --git a/pkg/mutation/editors/bindingsubjects.go b/pkg/mutation/editors/bindingsubjects.go new file mode 100644 index 00000000..bedb2cfc --- /dev/null +++ b/pkg/mutation/editors/bindingsubjects.go @@ -0,0 +1,55 @@ +package editors + +import rbacv1 "k8s.io/api/rbac/v1" + +// BindingSubjectsEditor provides a typed API for mutating the subjects list +// of a Kubernetes RoleBinding or ClusterRoleBinding. +// +// It exposes structured operations (EnsureSubject, RemoveSubject) as well as +// Raw() for free-form access when none of the structured methods are sufficient. +type BindingSubjectsEditor struct { + subjects *[]rbacv1.Subject +} + +// NewBindingSubjectsEditor creates a new BindingSubjectsEditor wrapping the +// given subjects slice pointer. +// +// The pointer may refer to a nil slice; methods that add subjects initialise +// it automatically. +func NewBindingSubjectsEditor(subjects *[]rbacv1.Subject) *BindingSubjectsEditor { + return &BindingSubjectsEditor{subjects: subjects} +} + +// EnsureSubject upserts a subject in the subjects list. +// +// A subject is identified by the combination of Kind, Name, and Namespace. +// If a matching subject already exists it is replaced; otherwise the new subject +// is appended. +func (e *BindingSubjectsEditor) EnsureSubject(subject rbacv1.Subject) { + for i, s := range *e.subjects { + if s.Kind == subject.Kind && s.Name == subject.Name && s.Namespace == subject.Namespace { + (*e.subjects)[i] = subject + return + } + } + *e.subjects = append(*e.subjects, subject) +} + +// RemoveSubject removes a subject identified by kind, name, and namespace +// from the subjects list. It is a no-op if no matching subject exists. +func (e *BindingSubjectsEditor) RemoveSubject(kind, name, namespace string) { + filtered := (*e.subjects)[:0] + for _, s := range *e.subjects { + if s.Kind == kind && s.Name == name && s.Namespace == namespace { + continue + } + filtered = append(filtered, s) + } + *e.subjects = filtered +} + +// Raw returns a pointer to the underlying subjects slice, allowing +// free-form modifications when the structured methods are insufficient. +func (e *BindingSubjectsEditor) Raw() *[]rbacv1.Subject { + return e.subjects +} diff --git a/pkg/mutation/editors/bindingsubjects_test.go b/pkg/mutation/editors/bindingsubjects_test.go new file mode 100644 index 00000000..86bad6f7 --- /dev/null +++ b/pkg/mutation/editors/bindingsubjects_test.go @@ -0,0 +1,109 @@ +package editors + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + rbacv1 "k8s.io/api/rbac/v1" +) + +func TestBindingSubjectsEditor_EnsureSubject_Append(t *testing.T) { + var subjects []rbacv1.Subject + e := NewBindingSubjectsEditor(&subjects) + + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "my-sa", + Namespace: "default", + }) + + require.Len(t, subjects, 1) + assert.Equal(t, "ServiceAccount", subjects[0].Kind) + assert.Equal(t, "my-sa", subjects[0].Name) + assert.Equal(t, "default", subjects[0].Namespace) +} + +func TestBindingSubjectsEditor_EnsureSubject_Upsert(t *testing.T) { + subjects := []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "my-sa", Namespace: "default", APIGroup: ""}, + } + e := NewBindingSubjectsEditor(&subjects) + + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "my-sa", + Namespace: "default", + APIGroup: "rbac.authorization.k8s.io", + }) + + require.Len(t, subjects, 1) + assert.Equal(t, "rbac.authorization.k8s.io", subjects[0].APIGroup) +} + +func TestBindingSubjectsEditor_EnsureSubject_MultipleSubjects(t *testing.T) { + var subjects []rbacv1.Subject + e := NewBindingSubjectsEditor(&subjects) + + e.EnsureSubject(rbacv1.Subject{Kind: "ServiceAccount", Name: "sa-1", Namespace: "ns-1"}) + e.EnsureSubject(rbacv1.Subject{Kind: "User", Name: "admin", Namespace: ""}) + + require.Len(t, subjects, 2) + assert.Equal(t, "sa-1", subjects[0].Name) + assert.Equal(t, "admin", subjects[1].Name) +} + +func TestBindingSubjectsEditor_RemoveSubject(t *testing.T) { + subjects := []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "keep", Namespace: "default"}, + {Kind: "ServiceAccount", Name: "remove", Namespace: "default"}, + {Kind: "User", Name: "admin", Namespace: ""}, + } + e := NewBindingSubjectsEditor(&subjects) + + e.RemoveSubject("ServiceAccount", "remove", "default") + + require.Len(t, subjects, 2) + assert.Equal(t, "keep", subjects[0].Name) + assert.Equal(t, "admin", subjects[1].Name) +} + +func TestBindingSubjectsEditor_RemoveSubject_NotPresent(t *testing.T) { + subjects := []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "keep", Namespace: "default"}, + } + e := NewBindingSubjectsEditor(&subjects) + + e.RemoveSubject("ServiceAccount", "missing", "default") + + require.Len(t, subjects, 1) + assert.Equal(t, "keep", subjects[0].Name) +} + +func TestBindingSubjectsEditor_RemoveSubject_EmptySlice(t *testing.T) { + var subjects []rbacv1.Subject + e := NewBindingSubjectsEditor(&subjects) + + e.RemoveSubject("ServiceAccount", "missing", "default") + + assert.Empty(t, subjects) +} + +func TestBindingSubjectsEditor_Raw(t *testing.T) { + subjects := []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "my-sa", Namespace: "default"}, + } + e := NewBindingSubjectsEditor(&subjects) + + raw := e.Raw() + require.NotNil(t, raw) + assert.Same(t, &subjects, raw) +} + +func TestBindingSubjectsEditor_Raw_NilSlice(t *testing.T) { + var subjects []rbacv1.Subject + e := NewBindingSubjectsEditor(&subjects) + + raw := e.Raw() + require.NotNil(t, raw) +} From 7765194f4000b033497e717a11782c2c0e771b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= Date: Sun, 22 Mar 2026 02:40:20 +0000 Subject: [PATCH 02/23] Add RoleBinding primitive package Implements builder, resource, mutator, and flavors for the RoleBinding primitive. DefaultFieldApplicator preserves the immutable roleRef from the live object. Mutator supports EditObjectMetadata and EditSubjects with plan-and-apply pattern. Co-Authored-By: Claude Opus 4.6 (1M context) --- pkg/primitives/rolebinding/builder.go | 115 +++++++++++++ pkg/primitives/rolebinding/builder_test.go | 159 ++++++++++++++++++ pkg/primitives/rolebinding/flavors.go | 25 +++ pkg/primitives/rolebinding/flavors_test.go | 124 ++++++++++++++ pkg/primitives/rolebinding/mutator.go | 108 ++++++++++++ pkg/primitives/rolebinding/mutator_test.go | 183 +++++++++++++++++++++ pkg/primitives/rolebinding/resource.go | 77 +++++++++ 7 files changed, 791 insertions(+) create mode 100644 pkg/primitives/rolebinding/builder.go create mode 100644 pkg/primitives/rolebinding/builder_test.go create mode 100644 pkg/primitives/rolebinding/flavors.go create mode 100644 pkg/primitives/rolebinding/flavors_test.go create mode 100644 pkg/primitives/rolebinding/mutator.go create mode 100644 pkg/primitives/rolebinding/mutator_test.go create mode 100644 pkg/primitives/rolebinding/resource.go diff --git a/pkg/primitives/rolebinding/builder.go b/pkg/primitives/rolebinding/builder.go new file mode 100644 index 00000000..aea14f48 --- /dev/null +++ b/pkg/primitives/rolebinding/builder.go @@ -0,0 +1,115 @@ +package rolebinding + +import ( + "fmt" + + "github.com/sourcehawk/operator-component-framework/internal/generic" + "github.com/sourcehawk/operator-component-framework/pkg/feature" + rbacv1 "k8s.io/api/rbac/v1" +) + +// Builder is a configuration helper for creating and customizing a RoleBinding Resource. +// +// It provides a fluent API for registering mutations, field application flavors, +// and data extractors. Build() validates the configuration and returns an +// initialized Resource ready for use in a reconciliation loop. +type Builder struct { + base *generic.StaticBuilder[*rbacv1.RoleBinding, *Mutator] +} + +// NewBuilder initializes a new Builder with the provided RoleBinding object. +// +// The RoleBinding object serves as the desired base state. During reconciliation +// the Resource will make the cluster's state match this base, modified by any +// registered mutations and flavors. +// +// roleRef must be set on the provided RoleBinding object. It is immutable after +// creation and is not modifiable via the mutation API. +// +// The provided RoleBinding must have both Name and Namespace set, which is +// validated during the Build() call. +func NewBuilder(rb *rbacv1.RoleBinding) *Builder { + identityFunc := func(r *rbacv1.RoleBinding) string { + return fmt.Sprintf("rbac.authorization.k8s.io/v1/RoleBinding/%s/%s", r.Namespace, r.Name) + } + + return &Builder{ + base: generic.NewStaticBuilder[*rbacv1.RoleBinding, *Mutator]( + rb, + identityFunc, + DefaultFieldApplicator, + NewMutator, + ), + } +} + +// WithMutation registers a mutation for the RoleBinding. +// +// Mutations are applied sequentially during the Mutate() phase of reconciliation, +// after the baseline field applicator and any registered flavors have run. +// A mutation with a nil Feature is applied unconditionally; one with a non-nil +// Feature is applied only when that feature is enabled. +func (b *Builder) WithMutation(m Mutation) *Builder { + b.base.WithMutation(feature.Mutation[*Mutator](m)) + return b +} + +// WithCustomFieldApplicator sets a custom strategy for applying the desired +// state to the existing RoleBinding in the cluster. +// +// The default applicator (DefaultFieldApplicator) replaces the current object +// with a deep copy of the desired object while preserving the live roleRef. +// Use a custom applicator when other controllers manage fields you need to +// preserve. +// +// The applicator receives the current object from the API server and the desired +// object from the Resource, and is responsible for merging the desired changes +// into the current object. +func (b *Builder) WithCustomFieldApplicator( + applicator func(current, desired *rbacv1.RoleBinding) error, +) *Builder { + b.base.WithCustomFieldApplicator(applicator) + return b +} + +// WithFieldApplicationFlavor registers a post-baseline field application flavor. +// +// Flavors run after the baseline applicator (default or custom) in registration +// order. They are typically used to preserve fields from the live cluster object +// that should not be overwritten by the desired state. +// +// A nil flavor is ignored. +func (b *Builder) WithFieldApplicationFlavor(flavor FieldApplicationFlavor) *Builder { + b.base.WithFieldApplicationFlavor(generic.FieldApplicationFlavor[*rbacv1.RoleBinding](flavor)) + return b +} + +// WithDataExtractor registers a function to read values from the RoleBinding +// after it has been successfully reconciled. +// +// The extractor receives a value copy of the reconciled RoleBinding. This is +// useful for surfacing generated or updated entries to other components or +// resources. +// +// A nil extractor is ignored. +func (b *Builder) WithDataExtractor(extractor func(rbacv1.RoleBinding) error) *Builder { + if extractor != nil { + b.base.WithDataExtractor(func(rb *rbacv1.RoleBinding) error { + return extractor(*rb) + }) + } + return b +} + +// Build validates the configuration and returns the initialized Resource. +// +// It returns an error if: +// - No RoleBinding object was provided. +// - The RoleBinding is missing a Name or Namespace. +func (b *Builder) Build() (*Resource, error) { + genericRes, err := b.base.Build() + if err != nil { + return nil, err + } + return &Resource{base: genericRes}, nil +} diff --git a/pkg/primitives/rolebinding/builder_test.go b/pkg/primitives/rolebinding/builder_test.go new file mode 100644 index 00000000..6fefd597 --- /dev/null +++ b/pkg/primitives/rolebinding/builder_test.go @@ -0,0 +1,159 @@ +package rolebinding + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestBuilder_Build_Validation(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + rb *rbacv1.RoleBinding + expectedErr string + }{ + { + name: "nil rolebinding", + rb: nil, + expectedErr: "object cannot be nil", + }, + { + name: "empty name", + rb: &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Namespace: "test-ns"}, + }, + expectedErr: "object name cannot be empty", + }, + { + name: "empty namespace", + rb: &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "test-rb"}, + }, + expectedErr: "object namespace cannot be empty", + }, + { + name: "valid rolebinding", + rb: &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "my-role", + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := NewBuilder(tt.rb).Build() + if tt.expectedErr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.expectedErr) + assert.Nil(t, res) + } else { + require.NoError(t, err) + require.NotNil(t, res) + assert.Equal(t, "rbac.authorization.k8s.io/v1/RoleBinding/test-ns/test-rb", res.Identity()) + } + }) + } +} + +func TestBuilder_WithMutation(t *testing.T) { + t.Parallel() + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + } + res, err := NewBuilder(rb). + WithMutation(Mutation{Name: "test-mutation"}). + Build() + require.NoError(t, err) + assert.Len(t, res.base.Mutations, 1) + assert.Equal(t, "test-mutation", res.base.Mutations[0].Name) +} + +func TestBuilder_WithCustomFieldApplicator(t *testing.T) { + t.Parallel() + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + } + called := false + applicator := func(_, _ *rbacv1.RoleBinding) error { + called = true + return nil + } + res, err := NewBuilder(rb). + WithCustomFieldApplicator(applicator). + Build() + require.NoError(t, err) + require.NotNil(t, res.base.CustomFieldApplicator) + _ = res.base.CustomFieldApplicator(nil, nil) + assert.True(t, called) +} + +func TestBuilder_WithFieldApplicationFlavor(t *testing.T) { + t.Parallel() + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + } + res, err := NewBuilder(rb). + WithFieldApplicationFlavor(PreserveCurrentLabels). + WithFieldApplicationFlavor(nil). // nil must be ignored + Build() + require.NoError(t, err) + assert.Len(t, res.base.FieldFlavors, 1) +} + +func TestBuilder_WithDataExtractor(t *testing.T) { + t.Parallel() + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + } + called := false + extractor := func(_ rbacv1.RoleBinding) error { + called = true + return nil + } + res, err := NewBuilder(rb). + WithDataExtractor(extractor). + Build() + require.NoError(t, err) + assert.Len(t, res.base.DataExtractors, 1) + require.NoError(t, res.base.DataExtractors[0](&rbacv1.RoleBinding{})) + assert.True(t, called) +} + +func TestBuilder_WithDataExtractor_Nil(t *testing.T) { + t.Parallel() + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + } + res, err := NewBuilder(rb). + WithDataExtractor(nil). + Build() + require.NoError(t, err) + assert.Len(t, res.base.DataExtractors, 0) +} + +func TestBuilder_WithDataExtractor_ErrorPropagated(t *testing.T) { + t.Parallel() + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + } + res, err := NewBuilder(rb). + WithDataExtractor(func(_ rbacv1.RoleBinding) error { + return errors.New("extractor error") + }). + Build() + require.NoError(t, err) + err = res.base.DataExtractors[0](&rbacv1.RoleBinding{}) + require.Error(t, err) + assert.Contains(t, err.Error(), "extractor error") +} diff --git a/pkg/primitives/rolebinding/flavors.go b/pkg/primitives/rolebinding/flavors.go new file mode 100644 index 00000000..9ac1d524 --- /dev/null +++ b/pkg/primitives/rolebinding/flavors.go @@ -0,0 +1,25 @@ +package rolebinding + +import ( + "github.com/sourcehawk/operator-component-framework/pkg/flavors" + rbacv1 "k8s.io/api/rbac/v1" +) + +// FieldApplicationFlavor defines a function signature for applying flavors to a +// RoleBinding resource. A flavor is called after the baseline field applicator has +// run and can be used to preserve or merge fields from the live cluster object. +type FieldApplicationFlavor flavors.FieldApplicationFlavor[*rbacv1.RoleBinding] + +// PreserveCurrentLabels ensures that any labels present on the current live +// RoleBinding but missing from the applied (desired) object are preserved. +// If a label exists in both, the applied value wins. +func PreserveCurrentLabels(applied, current, desired *rbacv1.RoleBinding) error { + return flavors.PreserveCurrentLabels[*rbacv1.RoleBinding]()(applied, current, desired) +} + +// PreserveCurrentAnnotations ensures that any annotations present on the current +// live RoleBinding but missing from the applied (desired) object are preserved. +// If an annotation exists in both, the applied value wins. +func PreserveCurrentAnnotations(applied, current, desired *rbacv1.RoleBinding) error { + return flavors.PreserveCurrentAnnotations[*rbacv1.RoleBinding]()(applied, current, desired) +} diff --git a/pkg/primitives/rolebinding/flavors_test.go b/pkg/primitives/rolebinding/flavors_test.go new file mode 100644 index 00000000..5f437f09 --- /dev/null +++ b/pkg/primitives/rolebinding/flavors_test.go @@ -0,0 +1,124 @@ +package rolebinding + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestPreserveCurrentLabels(t *testing.T) { + t.Run("adds missing labels from current", func(t *testing.T) { + applied := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"keep": "applied"}}} + current := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"extra": "current"}}} + + require.NoError(t, PreserveCurrentLabels(applied, current, nil)) + assert.Equal(t, "applied", applied.Labels["keep"]) + assert.Equal(t, "current", applied.Labels["extra"]) + }) + + t.Run("applied value wins on overlap", func(t *testing.T) { + applied := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"key": "applied"}}} + current := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"key": "current"}}} + + require.NoError(t, PreserveCurrentLabels(applied, current, nil)) + assert.Equal(t, "applied", applied.Labels["key"]) + }) + + t.Run("handles nil applied labels", func(t *testing.T) { + applied := &rbacv1.RoleBinding{} + current := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"extra": "current"}}} + + require.NoError(t, PreserveCurrentLabels(applied, current, nil)) + assert.Equal(t, "current", applied.Labels["extra"]) + }) +} + +func TestPreserveCurrentAnnotations(t *testing.T) { + t.Run("adds missing annotations from current", func(t *testing.T) { + applied := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"keep": "applied"}}} + current := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"extra": "current"}}} + + require.NoError(t, PreserveCurrentAnnotations(applied, current, nil)) + assert.Equal(t, "applied", applied.Annotations["keep"]) + assert.Equal(t, "current", applied.Annotations["extra"]) + }) + + t.Run("applied value wins on overlap", func(t *testing.T) { + applied := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"key": "applied"}}} + current := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"key": "current"}}} + + require.NoError(t, PreserveCurrentAnnotations(applied, current, nil)) + assert.Equal(t, "applied", applied.Annotations["key"]) + }) +} + +func TestFlavors_Integration(t *testing.T) { + desired := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "default", + Labels: map[string]string{"app": "desired"}, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "my-role", + }, + } + + t.Run("PreserveCurrentLabels via Mutate", func(t *testing.T) { + res, err := NewBuilder(desired). + WithFieldApplicationFlavor(PreserveCurrentLabels). + Build() + require.NoError(t, err) + + current := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"external": "keep", "app": "old"}, + }, + } + require.NoError(t, res.Mutate(current)) + + assert.Equal(t, "desired", current.Labels["app"]) + assert.Equal(t, "keep", current.Labels["external"]) + }) + + t.Run("flavors run in registration order", func(t *testing.T) { + var order []string + flavor1 := func(_, _, _ *rbacv1.RoleBinding) error { + order = append(order, "flavor1") + return nil + } + flavor2 := func(_, _, _ *rbacv1.RoleBinding) error { + order = append(order, "flavor2") + return nil + } + + res, err := NewBuilder(desired). + WithFieldApplicationFlavor(flavor1). + WithFieldApplicationFlavor(flavor2). + Build() + require.NoError(t, err) + + require.NoError(t, res.Mutate(&rbacv1.RoleBinding{})) + assert.Equal(t, []string{"flavor1", "flavor2"}, order) + }) + + t.Run("flavor error is returned", func(t *testing.T) { + flavorErr := errors.New("flavor boom") + res, err := NewBuilder(desired). + WithFieldApplicationFlavor(func(_, _, _ *rbacv1.RoleBinding) error { + return flavorErr + }). + Build() + require.NoError(t, err) + + err = res.Mutate(&rbacv1.RoleBinding{}) + require.Error(t, err) + assert.True(t, errors.Is(err, flavorErr)) + }) +} diff --git a/pkg/primitives/rolebinding/mutator.go b/pkg/primitives/rolebinding/mutator.go new file mode 100644 index 00000000..f075261c --- /dev/null +++ b/pkg/primitives/rolebinding/mutator.go @@ -0,0 +1,108 @@ +// Package rolebinding provides a builder and resource for managing Kubernetes RoleBindings. +package rolebinding + +import ( + "github.com/sourcehawk/operator-component-framework/pkg/feature" + "github.com/sourcehawk/operator-component-framework/pkg/mutation/editors" + rbacv1 "k8s.io/api/rbac/v1" +) + +// Mutation defines a mutation that is applied to a rolebinding Mutator +// only if its associated feature gate is enabled. +type Mutation feature.Mutation[*Mutator] + +type featurePlan struct { + metadataEdits []func(*editors.ObjectMetaEditor) error + subjectEdits []func(*editors.BindingSubjectsEditor) error +} + +// Mutator is a high-level helper for modifying a Kubernetes RoleBinding. +// +// It uses a "plan-and-apply" pattern: mutations are recorded first, then +// applied to the RoleBinding in a single controlled pass when Apply() is called. +// +// The Mutator maintains feature boundaries: each feature's mutations are planned +// together and applied in the order the features were registered. +// +// Mutator implements editors.ObjectMutator. +type Mutator struct { + rb *rbacv1.RoleBinding + + plans []featurePlan + active *featurePlan +} + +// NewMutator creates a new Mutator for the given RoleBinding. +func NewMutator(rb *rbacv1.RoleBinding) *Mutator { + m := &Mutator{rb: rb} + m.beginFeature() + return m +} + +// beginFeature starts a new feature planning scope. All subsequent mutation +// registrations will be grouped into this feature's plan. +func (m *Mutator) beginFeature() { + m.plans = append(m.plans, featurePlan{}) + m.active = &m.plans[len(m.plans)-1] +} + +// EditObjectMetadata records a mutation for the RoleBinding's own metadata. +// +// Metadata edits are applied before subject edits within the same feature. +// A nil edit function is ignored. +func (m *Mutator) EditObjectMetadata(edit func(*editors.ObjectMetaEditor) error) { + if edit == nil { + return + } + m.active.metadataEdits = append(m.active.metadataEdits, edit) +} + +// EditSubjects records a mutation for the RoleBinding's subjects list via a +// BindingSubjectsEditor. +// +// The editor provides structured operations (EnsureSubject, RemoveSubject) as +// well as Raw() for free-form access. Subject edits are applied after metadata +// edits within the same feature, in registration order. +// +// A nil edit function is ignored. +func (m *Mutator) EditSubjects(edit func(*editors.BindingSubjectsEditor) error) { + if edit == nil { + return + } + m.active.subjectEdits = append(m.active.subjectEdits, edit) +} + +// Apply executes all recorded mutation intents on the underlying RoleBinding. +// +// Execution order across all registered features: +// +// 1. Metadata edits (in registration order within each feature) +// 2. Subject edits (in registration order within each feature) +// +// Features are applied in the order they were registered. Later features observe +// the RoleBinding as modified by all previous features. +func (m *Mutator) Apply() error { + for _, plan := range m.plans { + // 1. Metadata edits + if len(plan.metadataEdits) > 0 { + editor := editors.NewObjectMetaEditor(&m.rb.ObjectMeta) + for _, edit := range plan.metadataEdits { + if err := edit(editor); err != nil { + return err + } + } + } + + // 2. Subject edits + if len(plan.subjectEdits) > 0 { + editor := editors.NewBindingSubjectsEditor(&m.rb.Subjects) + for _, edit := range plan.subjectEdits { + if err := edit(editor); err != nil { + return err + } + } + } + } + + return nil +} diff --git a/pkg/primitives/rolebinding/mutator_test.go b/pkg/primitives/rolebinding/mutator_test.go new file mode 100644 index 00000000..fe1b86c9 --- /dev/null +++ b/pkg/primitives/rolebinding/mutator_test.go @@ -0,0 +1,183 @@ +package rolebinding + +import ( + "testing" + + "github.com/sourcehawk/operator-component-framework/pkg/mutation/editors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func newTestRB() *rbacv1.RoleBinding { + return &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "default", + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "my-role", + }, + } +} + +// --- EditObjectMetadata --- + +func TestMutator_EditObjectMetadata(t *testing.T) { + rb := newTestRB() + m := NewMutator(rb) + m.EditObjectMetadata(func(e *editors.ObjectMetaEditor) error { + e.EnsureLabel("app", "myapp") + return nil + }) + require.NoError(t, m.Apply()) + assert.Equal(t, "myapp", rb.Labels["app"]) +} + +func TestMutator_EditObjectMetadata_Nil(t *testing.T) { + rb := newTestRB() + m := NewMutator(rb) + m.EditObjectMetadata(nil) + assert.NoError(t, m.Apply()) +} + +// --- EditSubjects --- + +func TestMutator_EditSubjects_EnsureSubject(t *testing.T) { + rb := newTestRB() + m := NewMutator(rb) + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "my-sa", + Namespace: "default", + }) + return nil + }) + require.NoError(t, m.Apply()) + require.Len(t, rb.Subjects, 1) + assert.Equal(t, "my-sa", rb.Subjects[0].Name) +} + +func TestMutator_EditSubjects_RemoveSubject(t *testing.T) { + rb := newTestRB() + rb.Subjects = []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "keep", Namespace: "default"}, + {Kind: "ServiceAccount", Name: "remove", Namespace: "default"}, + } + m := NewMutator(rb) + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.RemoveSubject("ServiceAccount", "remove", "default") + return nil + }) + require.NoError(t, m.Apply()) + require.Len(t, rb.Subjects, 1) + assert.Equal(t, "keep", rb.Subjects[0].Name) +} + +func TestMutator_EditSubjects_RawAccess(t *testing.T) { + rb := newTestRB() + m := NewMutator(rb) + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + raw := e.Raw() + *raw = append(*raw, rbacv1.Subject{ + Kind: "User", + Name: "admin", + }) + return nil + }) + require.NoError(t, m.Apply()) + require.Len(t, rb.Subjects, 1) + assert.Equal(t, "admin", rb.Subjects[0].Name) +} + +func TestMutator_EditSubjects_Nil(t *testing.T) { + rb := newTestRB() + m := NewMutator(rb) + m.EditSubjects(nil) + assert.NoError(t, m.Apply()) +} + +// --- Execution order --- + +func TestMutator_OperationOrder(t *testing.T) { + // Within a feature: metadata edits run before subject edits. + rb := newTestRB() + m := NewMutator(rb) + // Register in reverse logical order to confirm Apply() enforces category ordering. + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "my-sa", + Namespace: "default", + }) + return nil + }) + m.EditObjectMetadata(func(e *editors.ObjectMetaEditor) error { + e.EnsureLabel("order", "tested") + return nil + }) + require.NoError(t, m.Apply()) + + assert.Equal(t, "tested", rb.Labels["order"]) + require.Len(t, rb.Subjects, 1) + assert.Equal(t, "my-sa", rb.Subjects[0].Name) +} + +func TestMutator_MultipleFeatures(t *testing.T) { + rb := newTestRB() + m := NewMutator(rb) + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "sa-1", + Namespace: "default", + }) + return nil + }) + m.beginFeature() + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "sa-2", + Namespace: "default", + }) + return nil + }) + require.NoError(t, m.Apply()) + + require.Len(t, rb.Subjects, 2) + assert.Equal(t, "sa-1", rb.Subjects[0].Name) + assert.Equal(t, "sa-2", rb.Subjects[1].Name) +} + +func TestMutator_EditSubjects_ErrorPropagated(t *testing.T) { + rb := newTestRB() + m := NewMutator(rb) + m.EditSubjects(func(_ *editors.BindingSubjectsEditor) error { + return assert.AnError + }) + err := m.Apply() + require.Error(t, err) + assert.ErrorIs(t, err, assert.AnError) +} + +func TestMutator_EditObjectMetadata_ErrorPropagated(t *testing.T) { + rb := newTestRB() + m := NewMutator(rb) + m.EditObjectMetadata(func(_ *editors.ObjectMetaEditor) error { + return assert.AnError + }) + err := m.Apply() + require.Error(t, err) + assert.ErrorIs(t, err, assert.AnError) +} + +// --- ObjectMutator interface --- + +func TestMutator_ImplementsObjectMutator(_ *testing.T) { + var _ editors.ObjectMutator = (*Mutator)(nil) +} diff --git a/pkg/primitives/rolebinding/resource.go b/pkg/primitives/rolebinding/resource.go new file mode 100644 index 00000000..fe3fe6da --- /dev/null +++ b/pkg/primitives/rolebinding/resource.go @@ -0,0 +1,77 @@ +package rolebinding + +import ( + "github.com/sourcehawk/operator-component-framework/internal/generic" + rbacv1 "k8s.io/api/rbac/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// DefaultFieldApplicator replaces the current RoleBinding with a deep copy of +// the desired object, preserving the live roleRef when the resource already +// exists in the cluster. +// +// roleRef is immutable after creation in Kubernetes. If the current object has +// a non-empty ResourceVersion (indicating it was read from the API server), +// the live roleRef is preserved regardless of what the desired object declares. +func DefaultFieldApplicator(current, desired *rbacv1.RoleBinding) error { + roleRef := current.RoleRef + *current = *desired.DeepCopy() + if current.ResourceVersion != "" { + current.RoleRef = roleRef + } + return nil +} + +// Resource is a high-level abstraction for managing a Kubernetes RoleBinding +// within a controller's reconciliation loop. +// +// It implements the following component interfaces: +// - component.Resource: for basic identity and mutation behaviour. +// - component.DataExtractable: for exporting values after successful reconciliation. +// +// RoleBinding resources are static: they do not model convergence health, +// grace periods, or suspension. +type Resource struct { + base *generic.StaticResource[*rbacv1.RoleBinding, *Mutator] +} + +// Identity returns a unique identifier for the RoleBinding in the format +// "rbac.authorization.k8s.io/v1/RoleBinding//". +func (r *Resource) Identity() string { + return r.base.Identity() +} + +// Object returns a deep copy of the underlying Kubernetes RoleBinding object. +// +// The returned object implements client.Object, making it compatible with +// controller-runtime's Client for Create, Update, and Patch operations. +func (r *Resource) Object() (client.Object, error) { + return r.base.Object() +} + +// Mutate transforms the current state of a Kubernetes RoleBinding into the +// desired state. +// +// The mutation process follows this order: +// 1. Field application: the current object is updated to reflect the desired +// base state, using either DefaultFieldApplicator or a custom applicator +// if one is configured. roleRef is preserved from the live object. +// 2. Field application flavors: any registered flavors are applied in +// registration order. +// 3. Feature mutations: all registered feature-gated mutations are applied +// in order. +// +// This method is invoked by the framework during the Update phase of +// reconciliation. +func (r *Resource) Mutate(current client.Object) error { + return r.base.Mutate(current) +} + +// ExtractData executes all registered data extractor functions against a deep +// copy of the reconciled RoleBinding. +// +// This is called by the framework after successful reconciliation, allowing the +// component to read generated or updated values from the RoleBinding. +func (r *Resource) ExtractData() error { + return r.base.ExtractData() +} From 8611f3fc4215e784f58eba02f3e332d2a85a06d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= Date: Sun, 22 Mar 2026 02:41:10 +0000 Subject: [PATCH 03/23] Add RoleBinding primitive documentation Covers building, default field application (immutable roleRef), mutations, editors (BindingSubjectsEditor, ObjectMetaEditor), flavors, and guidance. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/primitives/rolebinding.md | 239 +++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 docs/primitives/rolebinding.md diff --git a/docs/primitives/rolebinding.md b/docs/primitives/rolebinding.md new file mode 100644 index 00000000..f1dc7f0d --- /dev/null +++ b/docs/primitives/rolebinding.md @@ -0,0 +1,239 @@ +# RoleBinding Primitive + +The `rolebinding` primitive is the framework's built-in static abstraction for managing Kubernetes `RoleBinding` resources. It integrates with the component lifecycle and provides a structured mutation API for managing subjects and object metadata. + +## Capabilities + +| Capability | Detail | +|-----------------------|-------------------------------------------------------------------------------------------------------------| +| **Static lifecycle** | No health tracking, grace periods, or suspension — the resource is reconciled to desired state | +| **Mutation pipeline** | Typed editors for subjects and object metadata, with a raw escape hatch for free-form access | +| **Immutable roleRef** | `roleRef` is set on the desired object and preserved from the live cluster object after initial creation | +| **Flavors** | Preserves externally-managed fields — labels and annotations not owned by the operator | +| **Data extraction** | Reads generated or updated values back from the reconciled RoleBinding after each sync cycle | + +## Building a RoleBinding Primitive + +```go +import "github.com/sourcehawk/operator-component-framework/pkg/primitives/rolebinding" + +base := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app-rolebinding", + Namespace: owner.Namespace, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "app-role", + }, + Subjects: []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "app-sa", Namespace: owner.Namespace}, + }, +} + +resource, err := rolebinding.NewBuilder(base). + WithFieldApplicationFlavor(rolebinding.PreserveCurrentLabels). + WithMutation(MySubjectMutation(owner.Spec.Version)). + Build() +``` + +`roleRef` must be set on the base object passed to `NewBuilder`. It is immutable after creation in Kubernetes and is not modifiable via the mutation API. + +## Default Field Application + +`DefaultFieldApplicator` replaces the current RoleBinding with a deep copy of the desired object, preserving the live `roleRef` when the resource already exists in the cluster (i.e. has a non-empty `ResourceVersion`). + +This ensures that: +- Every reconciliation cycle produces a clean, predictable state. +- The immutable `roleRef` from the API server is never overwritten. + +Use `WithCustomFieldApplicator` when other controllers manage fields you need to preserve: + +```go +resource, err := rolebinding.NewBuilder(base). + WithCustomFieldApplicator(func(current, desired *rbacv1.RoleBinding) error { + // Only synchronise subjects; leave other fields untouched. + current.Subjects = desired.DeepCopy().Subjects + return nil + }). + Build() +``` + +## Mutations + +Mutations are the primary mechanism for modifying a `RoleBinding` beyond its baseline. Each mutation is a named function that receives a `*Mutator` and records edit intent through typed editors. + +The `Feature` field controls when a mutation applies. Leaving it nil applies the mutation unconditionally: + +```go +func AddServiceAccountMutation(version, saName, saNamespace string) rolebinding.Mutation { + return rolebinding.Mutation{ + Name: "add-service-account", + Feature: feature.NewResourceFeature(version, nil), + Mutate: func(m *rolebinding.Mutator) error { + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: saName, + Namespace: saNamespace, + }) + return nil + }) + return nil + }, + } +} +``` + +### Boolean-gated mutations + +```go +func MonitoringSubjectMutation(version string, enabled bool) rolebinding.Mutation { + return rolebinding.Mutation{ + Name: "monitoring-subject", + Feature: feature.NewResourceFeature(version, nil).When(enabled), + Mutate: func(m *rolebinding.Mutator) error { + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "monitoring-agent", + Namespace: "monitoring", + }) + return nil + }) + return nil + }, + } +} +``` + +### Version-gated mutations + +```go +var legacyConstraint = mustSemverConstraint("< 2.0.0") + +func LegacySubjectMutation(version string) rolebinding.Mutation { + return rolebinding.Mutation{ + Name: "legacy-subject", + Feature: feature.NewResourceFeature( + version, + []feature.VersionConstraint{legacyConstraint}, + ), + Mutate: func(m *rolebinding.Mutator) error { + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.EnsureSubject(rbacv1.Subject{ + Kind: "User", + Name: "legacy-admin", + }) + return nil + }) + return nil + }, + } +} +``` + +All version constraints and `When()` conditions must be satisfied for a mutation to apply. + +## Internal Mutation Ordering + +Within a single mutation, edit operations are applied in a fixed category order regardless of the order they are recorded: + +| Step | Category | What it affects | +|------|-----------------|--------------------------------------------| +| 1 | Metadata edits | Labels and annotations on the RoleBinding | +| 2 | Subject edits | `.subjects` entries via BindingSubjectsEditor | + +Within each category, edits are applied in their registration order. Later features observe the RoleBinding as modified by all previous features. + +## Editors + +### BindingSubjectsEditor + +The primary API for modifying the subjects list. Use `m.EditSubjects` for full control: + +```go +m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "my-sa", + Namespace: "default", + }) + e.RemoveSubject("ServiceAccount", "old-sa", "default") + return nil +}) +``` + +#### EnsureSubject + +`EnsureSubject` upserts a subject by the combination of `Kind`, `Name`, and `Namespace`. If a matching subject already exists, it is replaced; otherwise the new subject is appended. + +#### RemoveSubject + +`RemoveSubject` removes a subject identified by kind, name, and namespace. It is a no-op if no matching subject exists. + +#### Raw + +`Raw()` returns a pointer to the underlying `[]rbacv1.Subject` slice for free-form access when the structured methods are insufficient: + +```go +m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + raw := e.Raw() + *raw = append(*raw, rbacv1.Subject{ + Kind: "Group", + Name: "developers", + }) + return nil +}) +``` + +### ObjectMetaEditor + +Modifies labels and annotations via `m.EditObjectMetadata`. + +Available methods: `EnsureLabel`, `RemoveLabel`, `EnsureAnnotation`, `RemoveAnnotation`, `Raw`. + +```go +m.EditObjectMetadata(func(e *editors.ObjectMetaEditor) error { + e.EnsureLabel("app.kubernetes.io/managed-by", "my-operator") + e.EnsureAnnotation("operator.example.io/version", version) + return nil +}) +``` + +## Flavors + +Flavors run after the baseline applicator and before mutations. They are used to preserve fields managed by external controllers or other tools. + +### PreserveCurrentLabels + +Preserves labels present on the live object but absent from the applied desired state. Applied labels win on overlap. + +```go +resource, err := rolebinding.NewBuilder(base). + WithFieldApplicationFlavor(rolebinding.PreserveCurrentLabels). + Build() +``` + +### PreserveCurrentAnnotations + +Preserves annotations present on the live object but absent from the applied desired state. Applied annotations win on overlap. + +```go +resource, err := rolebinding.NewBuilder(base). + WithFieldApplicationFlavor(rolebinding.PreserveCurrentAnnotations). + Build() +``` + +Multiple flavors can be registered and run in registration order. + +## Guidance + +**Set `roleRef` on the base object, not via mutations.** Kubernetes makes `roleRef` immutable after creation. The `DefaultFieldApplicator` preserves the live `roleRef` to avoid update conflicts. To change a `roleRef`, delete and recreate the RoleBinding. + +**`Feature: nil` applies unconditionally.** Omit `Feature` (leave it nil) for mutations that should always run. Use `feature.NewResourceFeature(version, constraints)` when version-based gating is needed, and chain `.When(bool)` for boolean conditions. + +**Use `EnsureSubject` for idempotent subject management.** `EnsureSubject` upserts by Kind+Name+Namespace, making it safe to call on every reconciliation without creating duplicates. + +**Register mutations in dependency order.** If mutation B relies on a subject added by mutation A, register A first. From a9bff6f3b64c9fcc5faa44dadccfd3b72db35aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= Date: Sun, 22 Mar 2026 02:42:46 +0000 Subject: [PATCH 04/23] Add RoleBinding primitive example Demonstrates building a RoleBinding with immutable roleRef, feature-gated subject mutations, version labels, field flavors, and data extraction across multiple reconciliation cycles. Co-Authored-By: Claude Opus 4.6 (1M context) --- examples/rolebinding-primitive/README.md | 30 +++++ .../rolebinding-primitive/app/controller.go | 54 +++++++++ .../features/mutations.go | 65 +++++++++++ examples/rolebinding-primitive/main.go | 106 ++++++++++++++++++ .../resources/rolebinding.go | 63 +++++++++++ 5 files changed, 318 insertions(+) create mode 100644 examples/rolebinding-primitive/README.md create mode 100644 examples/rolebinding-primitive/app/controller.go create mode 100644 examples/rolebinding-primitive/features/mutations.go create mode 100644 examples/rolebinding-primitive/main.go create mode 100644 examples/rolebinding-primitive/resources/rolebinding.go diff --git a/examples/rolebinding-primitive/README.md b/examples/rolebinding-primitive/README.md new file mode 100644 index 00000000..bf1957e1 --- /dev/null +++ b/examples/rolebinding-primitive/README.md @@ -0,0 +1,30 @@ +# RoleBinding Primitive Example + +This example demonstrates the usage of the `rolebinding` primitive within the operator component framework. +It shows how to manage a Kubernetes RoleBinding as a component of a larger application, utilising features like: + +- **Base Construction**: Initializing a RoleBinding with an immutable `roleRef` and basic metadata. +- **Feature Mutations**: Composing subjects from independent, feature-gated mutations using `EditSubjects`. +- **Metadata Mutations**: Setting version labels on the RoleBinding via `EditObjectMetadata`. +- **Field Flavors**: Preserving labels managed by external controllers using `PreserveCurrentLabels`. +- **Data Extraction**: Inspecting subjects and roleRef after each reconcile cycle. + +## Directory Structure + +- `app/`: Defines the controller that uses the component framework. The `ExampleApp` CRD is shared from `examples/shared/app`. +- `features/`: Contains modular feature definitions: + - `mutations.go`: base subject binding, version labelling, and feature-gated monitoring subject. +- `resources/`: Contains the central `NewRoleBindingResource` factory that assembles all features using `rolebinding.Builder`. +- `main.go`: A standalone entry point that demonstrates multiple reconciliation cycles with a fake client. + +## Running the Example + +```bash +go run examples/rolebinding-primitive/main.go +``` + +This will: +1. Initialize a fake Kubernetes client. +2. Create an `ExampleApp` owner object. +3. Reconcile through three spec variations, printing the subjects after each cycle. +4. Print the resulting status conditions. diff --git a/examples/rolebinding-primitive/app/controller.go b/examples/rolebinding-primitive/app/controller.go new file mode 100644 index 00000000..48c86317 --- /dev/null +++ b/examples/rolebinding-primitive/app/controller.go @@ -0,0 +1,54 @@ +// Package app provides a sample controller using the rolebinding primitive. +package app + +import ( + "context" + + sharedapp "github.com/sourcehawk/operator-component-framework/examples/shared/app" + "github.com/sourcehawk/operator-component-framework/pkg/component" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// ExampleController reconciles an ExampleApp object using the component framework. +type ExampleController struct { + client.Client + Scheme *runtime.Scheme + Recorder record.EventRecorder + Metrics component.Recorder + + // NewRoleBindingResource is a factory function to create the rolebinding resource. + // This allows us to inject the resource construction logic. + NewRoleBindingResource func(*sharedapp.ExampleApp) (component.Resource, error) +} + +// Reconcile performs the reconciliation for a single ExampleApp. +func (r *ExampleController) Reconcile(ctx context.Context, owner *sharedapp.ExampleApp) error { + // 1. Build the rolebinding resource for this owner. + rbResource, err := r.NewRoleBindingResource(owner) + if err != nil { + return err + } + + // 2. Build the component that manages the rolebinding. + comp, err := component.NewComponentBuilder(). + WithName("example-app"). + WithConditionType("AppReady"). + WithResource(rbResource, component.ResourceOptions{}). + Build() + if err != nil { + return err + } + + // 3. Execute the component reconciliation. + resCtx := component.ReconcileContext{ + Client: r.Client, + Scheme: r.Scheme, + Recorder: r.Recorder, + Metrics: r.Metrics, + Owner: owner, + } + + return comp.Reconcile(ctx, resCtx) +} diff --git a/examples/rolebinding-primitive/features/mutations.go b/examples/rolebinding-primitive/features/mutations.go new file mode 100644 index 00000000..cc3b2fb0 --- /dev/null +++ b/examples/rolebinding-primitive/features/mutations.go @@ -0,0 +1,65 @@ +// Package features provides sample mutations for the rolebinding primitive example. +package features + +import ( + "github.com/sourcehawk/operator-component-framework/pkg/feature" + "github.com/sourcehawk/operator-component-framework/pkg/mutation/editors" + "github.com/sourcehawk/operator-component-framework/pkg/primitives/rolebinding" + rbacv1 "k8s.io/api/rbac/v1" +) + +// BaseSubjectsMutation adds the application's primary service account as a +// subject. It is always enabled. +func BaseSubjectsMutation(version, saName, saNamespace string) rolebinding.Mutation { + return rolebinding.Mutation{ + Name: "base-subjects", + Feature: feature.NewResourceFeature(version, nil), + Mutate: func(m *rolebinding.Mutator) error { + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: saName, + Namespace: saNamespace, + }) + return nil + }) + return nil + }, + } +} + +// VersionLabelMutation sets the app.kubernetes.io/version label on the +// RoleBinding. It is always enabled. +func VersionLabelMutation(version string) rolebinding.Mutation { + return rolebinding.Mutation{ + Name: "version-label", + Feature: feature.NewResourceFeature(version, nil), + Mutate: func(m *rolebinding.Mutator) error { + m.EditObjectMetadata(func(e *editors.ObjectMetaEditor) error { + e.EnsureLabel("app.kubernetes.io/version", version) + return nil + }) + return nil + }, + } +} + +// MonitoringSubjectMutation adds a monitoring service account as a subject. +// It is enabled when enableMonitoring is true. +func MonitoringSubjectMutation(version string, enableMonitoring bool) rolebinding.Mutation { + return rolebinding.Mutation{ + Name: "monitoring-subject", + Feature: feature.NewResourceFeature(version, nil).When(enableMonitoring), + Mutate: func(m *rolebinding.Mutator) error { + m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { + e.EnsureSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "monitoring-agent", + Namespace: "monitoring", + }) + return nil + }) + return nil + }, + } +} diff --git a/examples/rolebinding-primitive/main.go b/examples/rolebinding-primitive/main.go new file mode 100644 index 00000000..ba1aba33 --- /dev/null +++ b/examples/rolebinding-primitive/main.go @@ -0,0 +1,106 @@ +// Package main is the entry point for the rolebinding primitive example. +package main + +import ( + "context" + "fmt" + "os" + + ocm "github.com/sourcehawk/go-crd-condition-metrics/pkg/crd-condition-metrics" + "github.com/sourcehawk/operator-component-framework/examples/rolebinding-primitive/app" + "github.com/sourcehawk/operator-component-framework/examples/rolebinding-primitive/resources" + sharedapp "github.com/sourcehawk/operator-component-framework/examples/shared/app" + rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +func main() { + // 1. Setup scheme and fake client. + scheme := runtime.NewScheme() + if err := sharedapp.AddToScheme(scheme); err != nil { + fmt.Fprintf(os.Stderr, "failed to add to scheme: %v\n", err) + os.Exit(1) + } + if err := rbacv1.AddToScheme(scheme); err != nil { + fmt.Fprintf(os.Stderr, "failed to add rbac/v1 to scheme: %v\n", err) + os.Exit(1) + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithStatusSubresource(&sharedapp.ExampleApp{}). + Build() + + // 2. Create an example Owner object. + owner := &sharedapp.ExampleApp{ + Spec: sharedapp.ExampleAppSpec{ + Version: "1.2.3", + EnableMetrics: true, + }, + } + owner.Name = "my-example-app" + owner.Namespace = "default" + + if err := fakeClient.Create(context.Background(), owner); err != nil { + fmt.Fprintf(os.Stderr, "failed to create owner: %v\n", err) + os.Exit(1) + } + + // 3. Initialize the controller. + gauge := ocm.NewOperatorConditionsGauge("example") + controller := &app.ExampleController{ + Client: fakeClient, + Scheme: scheme, + Recorder: record.NewFakeRecorder(100), + Metrics: &ocm.ConditionMetricRecorder{ + Controller: "example-controller", + OperatorConditionsGauge: gauge, + }, + NewRoleBindingResource: resources.NewRoleBindingResource, + } + + // 4. Run reconciliation with multiple spec versions to demonstrate how + // subject mutations compose from independent feature mutations. + specs := []sharedapp.ExampleAppSpec{ + { + Version: "1.2.3", + EnableMetrics: true, // monitoring subject enabled + }, + { + Version: "1.2.4", // Version upgrade + EnableMetrics: true, + }, + { + Version: "1.2.4", + EnableMetrics: false, // Disable monitoring subject + }, + } + + ctx := context.Background() + + for i, spec := range specs { + fmt.Printf("\n--- Step %d: Version=%s, Monitoring=%v ---\n", + i+1, spec.Version, spec.EnableMetrics) + + owner.Spec = spec + if err := fakeClient.Update(ctx, owner); err != nil { + fmt.Fprintf(os.Stderr, "failed to update owner: %v\n", err) + os.Exit(1) + } + + fmt.Println("Running reconciliation...") + if err := controller.Reconcile(ctx, owner); err != nil { + fmt.Fprintf(os.Stderr, "reconciliation failed: %v\n", err) + os.Exit(1) + } + + for _, cond := range owner.Status.Conditions { + fmt.Printf("Condition: %s, Status: %s, Reason: %s\n", + cond.Type, cond.Status, cond.Reason) + } + } + + fmt.Println("\nReconciliation sequence completed successfully!") +} diff --git a/examples/rolebinding-primitive/resources/rolebinding.go b/examples/rolebinding-primitive/resources/rolebinding.go new file mode 100644 index 00000000..77e69222 --- /dev/null +++ b/examples/rolebinding-primitive/resources/rolebinding.go @@ -0,0 +1,63 @@ +// Package resources provides resource implementations for the rolebinding primitive example. +package resources + +import ( + "fmt" + + "github.com/sourcehawk/operator-component-framework/examples/rolebinding-primitive/features" + sharedapp "github.com/sourcehawk/operator-component-framework/examples/shared/app" + "github.com/sourcehawk/operator-component-framework/pkg/component" + "github.com/sourcehawk/operator-component-framework/pkg/primitives/rolebinding" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// NewRoleBindingResource constructs a rolebinding primitive resource with all the features. +func NewRoleBindingResource(owner *sharedapp.ExampleApp) (component.Resource, error) { + // 1. Create the base RoleBinding object. + // + // roleRef is set here because it is immutable after creation. + // Subjects are managed via mutations. + base := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: owner.Name + "-binding", + Namespace: owner.Namespace, + Labels: map[string]string{ + "app": owner.Name, + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: owner.Name + "-role", + }, + } + + // 2. Initialize the rolebinding builder. + builder := rolebinding.NewBuilder(base) + + // 3. Register mutations in dependency order. + builder.WithMutation(features.BaseSubjectsMutation( + owner.Spec.Version, owner.Name+"-sa", owner.Namespace, + )) + builder.WithMutation(features.VersionLabelMutation(owner.Spec.Version)) + builder.WithMutation(features.MonitoringSubjectMutation( + owner.Spec.Version, owner.Spec.EnableMetrics, + )) + + // 4. Preserve labels added by external controllers. + builder.WithFieldApplicationFlavor(rolebinding.PreserveCurrentLabels) + + // 5. Extract data from the reconciled RoleBinding. + builder.WithDataExtractor(func(rb rbacv1.RoleBinding) error { + fmt.Printf("Reconciled RoleBinding: %s\n", rb.Name) + fmt.Printf(" RoleRef: %s/%s\n", rb.RoleRef.Kind, rb.RoleRef.Name) + for _, s := range rb.Subjects { + fmt.Printf(" Subject: %s/%s (ns: %s)\n", s.Kind, s.Name, s.Namespace) + } + return nil + }) + + // 6. Build the final resource. + return builder.Build() +} From 802ef5ed688a77eebc215b378afb5a9571cb8e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= Date: Sun, 22 Mar 2026 04:24:13 +0000 Subject: [PATCH 05/23] Fix DefaultFieldApplicator ResourceVersion check and add tests Address Copilot review: capture whether the object existed before overwriting *current with desired.DeepCopy(), so the live roleRef is correctly preserved on updates. Previously the check always saw the (empty) desired ResourceVersion and never restored the live roleRef. Add unit tests covering create (desired roleRef applied), update (live roleRef preserved), and deep-copy isolation. Co-Authored-By: Claude Opus 4.6 (1M context) --- pkg/primitives/rolebinding/resource.go | 3 +- pkg/primitives/rolebinding/resource_test.go | 98 +++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 pkg/primitives/rolebinding/resource_test.go diff --git a/pkg/primitives/rolebinding/resource.go b/pkg/primitives/rolebinding/resource.go index fe3fe6da..20064fb9 100644 --- a/pkg/primitives/rolebinding/resource.go +++ b/pkg/primitives/rolebinding/resource.go @@ -14,9 +14,10 @@ import ( // a non-empty ResourceVersion (indicating it was read from the API server), // the live roleRef is preserved regardless of what the desired object declares. func DefaultFieldApplicator(current, desired *rbacv1.RoleBinding) error { + existed := current.ResourceVersion != "" roleRef := current.RoleRef *current = *desired.DeepCopy() - if current.ResourceVersion != "" { + if existed { current.RoleRef = roleRef } return nil diff --git a/pkg/primitives/rolebinding/resource_test.go b/pkg/primitives/rolebinding/resource_test.go new file mode 100644 index 00000000..32db1ccd --- /dev/null +++ b/pkg/primitives/rolebinding/resource_test.go @@ -0,0 +1,98 @@ +package rolebinding + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestDefaultFieldApplicator_Create(t *testing.T) { + // When current has no ResourceVersion (new object), desired roleRef is applied. + current := &rbacv1.RoleBinding{} + desired := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "test-ns", + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "desired-role", + }, + Subjects: []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "sa", Namespace: "test-ns"}, + }, + } + + require.NoError(t, DefaultFieldApplicator(current, desired)) + + assert.Equal(t, "test-rb", current.Name) + assert.Equal(t, "desired-role", current.RoleRef.Name) + assert.Equal(t, "Role", current.RoleRef.Kind) + assert.Len(t, current.Subjects, 1) +} + +func TestDefaultFieldApplicator_Update_PreservesLiveRoleRef(t *testing.T) { + // When current has a ResourceVersion (existing object), the live roleRef + // is preserved regardless of what desired declares. + current := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "test-ns", + ResourceVersion: "12345", + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: "live-role", + }, + Subjects: []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "old-sa", Namespace: "test-ns"}, + }, + } + desired := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "test-ns", + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "desired-role", + }, + Subjects: []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "new-sa", Namespace: "test-ns"}, + }, + } + + require.NoError(t, DefaultFieldApplicator(current, desired)) + + // roleRef must be the live one, not the desired one. + assert.Equal(t, "live-role", current.RoleRef.Name) + assert.Equal(t, "ClusterRole", current.RoleRef.Kind) + // Other fields should come from desired. + assert.Len(t, current.Subjects, 1) + assert.Equal(t, "new-sa", current.Subjects[0].Name) +} + +func TestDefaultFieldApplicator_DeepCopiesDesired(t *testing.T) { + // Mutations to current after application must not affect desired. + current := &rbacv1.RoleBinding{} + desired := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "test-ns", + }, + Subjects: []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "sa", Namespace: "test-ns"}, + }, + } + + require.NoError(t, DefaultFieldApplicator(current, desired)) + + current.Subjects[0].Name = "mutated" + assert.Equal(t, "sa", desired.Subjects[0].Name) +} From de751605cd74168eaea12cd24d90ab74426c7ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= Date: Sun, 22 Mar 2026 04:49:20 +0000 Subject: [PATCH 06/23] Clarify Feature field docs to match other primitive conventions Address Copilot review comment: the mutation docs text said "Leaving it nil applies the mutation unconditionally" but the example used a non-nil Feature. Align with configmap/deployment docs by adding the clarifying sentence about unconstrained features being always enabled, and add an "// always enabled" comment to the example. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/primitives/rolebinding.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/primitives/rolebinding.md b/docs/primitives/rolebinding.md index f1dc7f0d..92f51faf 100644 --- a/docs/primitives/rolebinding.md +++ b/docs/primitives/rolebinding.md @@ -64,13 +64,13 @@ resource, err := rolebinding.NewBuilder(base). Mutations are the primary mechanism for modifying a `RoleBinding` beyond its baseline. Each mutation is a named function that receives a `*Mutator` and records edit intent through typed editors. -The `Feature` field controls when a mutation applies. Leaving it nil applies the mutation unconditionally: +The `Feature` field controls when a mutation applies. Leaving it nil applies the mutation unconditionally. A feature with no version constraints and no `When()` conditions is also always enabled: ```go func AddServiceAccountMutation(version, saName, saNamespace string) rolebinding.Mutation { return rolebinding.Mutation{ Name: "add-service-account", - Feature: feature.NewResourceFeature(version, nil), + Feature: feature.NewResourceFeature(version, nil), // always enabled Mutate: func(m *rolebinding.Mutator) error { m.EditSubjects(func(e *editors.BindingSubjectsEditor) error { e.EnsureSubject(rbacv1.Subject{ From 54425395cd2a1e08cdc0b2d95e2b28a3ad63b966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= Date: Sun, 22 Mar 2026 13:28:51 +0000 Subject: [PATCH 07/23] Add RoleRef validation in Build() and nil pointer guard in BindingSubjectsEditor - Validate that RoleRef has non-empty APIGroup, Kind, and Name during Build() so invalid RoleBindings are caught early rather than at apply time - Guard against nil pointer in NewBindingSubjectsEditor, consistent with the defensive pattern used in NewConfigMapDataEditor - Add tests for both changes and update existing builder tests to include a valid RoleRef Co-Authored-By: Claude Opus 4.6 (1M context) --- pkg/mutation/editors/bindingsubjects.go | 7 ++++- pkg/mutation/editors/bindingsubjects_test.go | 12 +++++++++ pkg/primitives/rolebinding/builder.go | 7 +++++ pkg/primitives/rolebinding/builder_test.go | 28 ++++++++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/pkg/mutation/editors/bindingsubjects.go b/pkg/mutation/editors/bindingsubjects.go index bedb2cfc..12409885 100644 --- a/pkg/mutation/editors/bindingsubjects.go +++ b/pkg/mutation/editors/bindingsubjects.go @@ -15,8 +15,13 @@ type BindingSubjectsEditor struct { // given subjects slice pointer. // // The pointer may refer to a nil slice; methods that add subjects initialise -// it automatically. +// it automatically. If a nil pointer is provided, an empty slice is allocated +// and used internally. func NewBindingSubjectsEditor(subjects *[]rbacv1.Subject) *BindingSubjectsEditor { + if subjects == nil { + empty := make([]rbacv1.Subject, 0) + subjects = &empty + } return &BindingSubjectsEditor{subjects: subjects} } diff --git a/pkg/mutation/editors/bindingsubjects_test.go b/pkg/mutation/editors/bindingsubjects_test.go index 86bad6f7..7e817418 100644 --- a/pkg/mutation/editors/bindingsubjects_test.go +++ b/pkg/mutation/editors/bindingsubjects_test.go @@ -107,3 +107,15 @@ func TestBindingSubjectsEditor_Raw_NilSlice(t *testing.T) { raw := e.Raw() require.NotNil(t, raw) } + +func TestBindingSubjectsEditor_NilPointer(t *testing.T) { + e := NewBindingSubjectsEditor(nil) + + // Should not panic; operations work on the internal slice. + e.EnsureSubject(rbacv1.Subject{Kind: "ServiceAccount", Name: "sa", Namespace: "ns"}) + e.RemoveSubject("ServiceAccount", "sa", "ns") + + raw := e.Raw() + require.NotNil(t, raw) + assert.Empty(t, *raw) +} diff --git a/pkg/primitives/rolebinding/builder.go b/pkg/primitives/rolebinding/builder.go index aea14f48..2c58b6be 100644 --- a/pkg/primitives/rolebinding/builder.go +++ b/pkg/primitives/rolebinding/builder.go @@ -106,10 +106,17 @@ func (b *Builder) WithDataExtractor(extractor func(rbacv1.RoleBinding) error) *B // It returns an error if: // - No RoleBinding object was provided. // - The RoleBinding is missing a Name or Namespace. +// - The RoleRef is missing APIGroup, Kind, or Name. func (b *Builder) Build() (*Resource, error) { genericRes, err := b.base.Build() if err != nil { return nil, err } + + ref := genericRes.DesiredObject.RoleRef + if ref.APIGroup == "" || ref.Kind == "" || ref.Name == "" { + return nil, fmt.Errorf("roleRef must have non-empty APIGroup, Kind, and Name") + } + return &Resource{base: genericRes}, nil } diff --git a/pkg/primitives/rolebinding/builder_test.go b/pkg/primitives/rolebinding/builder_test.go index 6fefd597..11dc9d09 100644 --- a/pkg/primitives/rolebinding/builder_test.go +++ b/pkg/primitives/rolebinding/builder_test.go @@ -37,6 +37,24 @@ func TestBuilder_Build_Validation(t *testing.T) { }, expectedErr: "object namespace cannot be empty", }, + { + name: "empty roleRef", + rb: &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + }, + expectedErr: "roleRef must have non-empty APIGroup, Kind, and Name", + }, + { + name: "partial roleRef missing kind", + rb: &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Name: "my-role", + }, + }, + expectedErr: "roleRef must have non-empty APIGroup, Kind, and Name", + }, { name: "valid rolebinding", rb: &rbacv1.RoleBinding{ @@ -66,10 +84,15 @@ func TestBuilder_Build_Validation(t *testing.T) { } } +func testRoleRef() rbacv1.RoleRef { + return rbacv1.RoleRef{APIGroup: "rbac.authorization.k8s.io", Kind: "Role", Name: "my-role"} +} + func TestBuilder_WithMutation(t *testing.T) { t.Parallel() rb := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + RoleRef: testRoleRef(), } res, err := NewBuilder(rb). WithMutation(Mutation{Name: "test-mutation"}). @@ -83,6 +106,7 @@ func TestBuilder_WithCustomFieldApplicator(t *testing.T) { t.Parallel() rb := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + RoleRef: testRoleRef(), } called := false applicator := func(_, _ *rbacv1.RoleBinding) error { @@ -102,6 +126,7 @@ func TestBuilder_WithFieldApplicationFlavor(t *testing.T) { t.Parallel() rb := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + RoleRef: testRoleRef(), } res, err := NewBuilder(rb). WithFieldApplicationFlavor(PreserveCurrentLabels). @@ -115,6 +140,7 @@ func TestBuilder_WithDataExtractor(t *testing.T) { t.Parallel() rb := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + RoleRef: testRoleRef(), } called := false extractor := func(_ rbacv1.RoleBinding) error { @@ -134,6 +160,7 @@ func TestBuilder_WithDataExtractor_Nil(t *testing.T) { t.Parallel() rb := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + RoleRef: testRoleRef(), } res, err := NewBuilder(rb). WithDataExtractor(nil). @@ -146,6 +173,7 @@ func TestBuilder_WithDataExtractor_ErrorPropagated(t *testing.T) { t.Parallel() rb := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{Name: "test-rb", Namespace: "test-ns"}, + RoleRef: testRoleRef(), } res, err := NewBuilder(rb). WithDataExtractor(func(_ rbacv1.RoleBinding) error { From c34b77357f0bc39f5c181f102ea5c192c91ac56b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= Date: Sun, 22 Mar 2026 19:50:49 +0000 Subject: [PATCH 08/23] Preserve server-managed metadata in default field applicator Co-Authored-By: Claude Opus 4.6 (1M context) --- pkg/primitives/rolebinding/resource.go | 16 +++--- pkg/primitives/rolebinding/resource_test.go | 58 +++++++++++++++++++++ 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/pkg/primitives/rolebinding/resource.go b/pkg/primitives/rolebinding/resource.go index 20064fb9..ad041d08 100644 --- a/pkg/primitives/rolebinding/resource.go +++ b/pkg/primitives/rolebinding/resource.go @@ -7,17 +7,17 @@ import ( ) // DefaultFieldApplicator replaces the current RoleBinding with a deep copy of -// the desired object, preserving the live roleRef when the resource already -// exists in the cluster. -// -// roleRef is immutable after creation in Kubernetes. If the current object has -// a non-empty ResourceVersion (indicating it was read from the API server), -// the live roleRef is preserved regardless of what the desired object declares. +// the desired object, preserving server-managed metadata (ResourceVersion, UID, +// Generation, etc.) and shared-controller fields (OwnerReferences, Finalizers) +// from the original current object. It also preserves the live roleRef when the +// resource already exists in the cluster, since roleRef is immutable after +// creation in Kubernetes. func DefaultFieldApplicator(current, desired *rbacv1.RoleBinding) error { - existed := current.ResourceVersion != "" + original := current.DeepCopy() roleRef := current.RoleRef *current = *desired.DeepCopy() - if existed { + generic.PreserveServerManagedFields(current, original) + if original.ResourceVersion != "" { current.RoleRef = roleRef } return nil diff --git a/pkg/primitives/rolebinding/resource_test.go b/pkg/primitives/rolebinding/resource_test.go index 32db1ccd..346cdbca 100644 --- a/pkg/primitives/rolebinding/resource_test.go +++ b/pkg/primitives/rolebinding/resource_test.go @@ -78,6 +78,64 @@ func TestDefaultFieldApplicator_Update_PreservesLiveRoleRef(t *testing.T) { assert.Equal(t, "new-sa", current.Subjects[0].Name) } +func TestDefaultFieldApplicator_PreservesServerManagedFields(t *testing.T) { + current := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "test-ns", + ResourceVersion: "12345", + UID: "abc-def", + Generation: 3, + OwnerReferences: []metav1.OwnerReference{ + {APIVersion: "v1", Kind: "Pod", Name: "other-owner", UID: "other-uid"}, + }, + Finalizers: []string{"finalizer.example.com"}, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: "live-role", + }, + } + desired := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "test-ns", + Labels: map[string]string{"app": "test"}, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "desired-role", + }, + Subjects: []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "sa", Namespace: "test-ns"}, + }, + } + + err := DefaultFieldApplicator(current, desired) + require.NoError(t, err) + + // Desired spec and labels are applied + assert.Equal(t, "test", current.Labels["app"]) + assert.Len(t, current.Subjects, 1) + assert.Equal(t, "sa", current.Subjects[0].Name) + + // Server-managed fields are preserved + assert.Equal(t, "12345", current.ResourceVersion) + assert.Equal(t, "abc-def", string(current.UID)) + assert.Equal(t, int64(3), current.Generation) + + // Shared-controller fields are preserved + assert.Len(t, current.OwnerReferences, 1) + assert.Equal(t, "other-owner", current.OwnerReferences[0].Name) + assert.Equal(t, []string{"finalizer.example.com"}, current.Finalizers) + + // roleRef is preserved from live object + assert.Equal(t, "live-role", current.RoleRef.Name) + assert.Equal(t, "ClusterRole", current.RoleRef.Kind) +} + func TestDefaultFieldApplicator_DeepCopiesDesired(t *testing.T) { // Mutations to current after application must not affect desired. current := &rbacv1.RoleBinding{} From e31c6db0f96eccbb274180e63dfcea5f9c7d2b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= Date: Sun, 22 Mar 2026 21:24:15 +0000 Subject: [PATCH 09/23] add to readme --- rolebinding-primitive | Bin 0 -> 52242260 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 rolebinding-primitive diff --git a/rolebinding-primitive b/rolebinding-primitive new file mode 100755 index 0000000000000000000000000000000000000000..37dd499b538e6a151c1ec8517242afd9e3a7c149 GIT binary patch literal 52242260 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

A==%shrWqz?KE9%Fr=yOi) zDqFfw=1fa4eioB|_M2pwKn4@h<$OQuB(hF#pViU`T0H`G<|pK2d?zc8H_q?oR!^Ow znTOPB)+NNBlX2`x%|7HJh5F~zZ2x?cYWhor1(qm{&dihuEZ;EDY2gZ~wZw+H^!pq( zD@#aiJzrl?cojdUCGmeU;j*GM`uaRnzg!D~nc4T`pGw zT(jJ=UE29)Et@F$;$CIF@>=W-za{S zv)?RbSI&O3xP+9m-z;TU&VIAFgl<>%S$5%XYIa*5c5uyv)C-gPUDQ+=d}srvOf`dB zDwa@urS$XcI|+TxXP8$e`f!^n?Ie1w0CwZkI-vODQ&~gBmS2j{Cp1*7wKs#j)u&x| z{p{0jt!L1hSaj?(oDNRB1$JjkP1HtINQ}j6cVG9rFngoX*vS~~I9G3Djhb=9ZlWkj zzY#rfSa6Z;l5joy{1}OVl&|J713K?=0Am7FRpyX?rdCc%%GcI?kAO$EKuRe#3$L^T zWAlaVrB}oj^C?Oe*^0euo6MrC?8n3JXTkhveSFo|;!4a-d@_rsXn585zRZESc^)YX zl(N_B^tG?Kw|8BGW8Lw3`(QTza0hzI5tKVjpYGt3^I{AN^l(6%aW4OWEY#&YdgL$w zpJHCT!eaK@g`DCuR@u+WLT>q{{Zw=e+a@Jn?D#d9&(!J^)#^7SFk2>b`M^Q>zdJKn zPXvC_+;;|@d06{)w(Ey?`E8rexq=+&wTbftuj99={+r1=C)+S_F8j>aLdrV&xxt-D%1 zH{a|T-P7rX`KcQaD88xD@n17pGB^Tpz!?_e2=?dBu5kso%sGbQ*VgyG^RQrOlLO36 zFr$v!b?ctsl(or@D4@^hn_k&^s{K-f z+v<9-b(Q$yqmH@a8C+|%q3S!9aQpLSUSD^m;(pFNhy8D*+=XTz!?k4g;TEmGc(J{y z>*%pOB~yPOQ<8u7aEZFyed$YdkD|9H9oG9eo?^NGvMUOEyx4~H>AVUN79&lZXMSJy zwx)1($>(&ZeDAO=s2@FAxeswqz>Lz*(;7L}dCy;T#9ix8y70bZywX>^Q3HPcG$@yX z2t)e2UTKTMPL{T?r=`RjHTnU4jL*&YO5d_-8k))L-rf&|V=2yA(dOM=VirYzVZZKH z{pP$NRKa_G?rt`l<&%ZYj$fpgMB;(*fQyW(#3!xq`S#W;jKo8cQ3HnQiHSkD^Z={j zoNN$|Z4d8#Hxj?RAY7`t;+Mmkt$S4*E`5{oBC$bHKMM^jD_oBs$vZKu{k;M7< z?~-n>T~m=`kLVs;Qcoj#rJs4F2U0a1+ml@=Klx2*H>RVd&0gtFZ&cvhJbHWI5mgvz zS6+}IoPCu{c3O}o|JBOS4nVjgfb+i+fa^a!+T`~PX)F!mBo>;@ zPo&geJJaVL+QX+0STlbW>XZEarSL?<+=86?qmA{<2FF_AFja^`D|U?%jDA=nXNGhK z41zWkTw*oC#LV4pQV?$5cTRX{%lJfphjD|SrK&K^J^@h3f%%qwQQ)0IN3cVTL*ZA8c4FSPMD`vN_DR_gONROaKqnLeyR0j4$d;JcnvpSPj%Fb)s!I3ED~ zzU2{e*ju!v{yID$PuGUs((MwB>;h7}?B?{@UhZc+u_K3NQCdW_aCsyL3wa z$=c%znE4yzL&%64eP_2fY>S$QAxJmF@%P?PS)e^%ibRqK%zO#mM_ybe`bVZri9l`k z#Y|qf?rokp)vq(_Q~zOnm4D;g&bTlNI3Cf-Nlm=i8)O&?biTU!-U;e?B(cx;flz@`$)_*Pm(#Rda;RkNjOcpX|)`j~(6~b|W~by9s_o@Dt}h zD?`cNo!W&K9=d;gVm?5l``8&M9lR!ZQ8NLU58qgk8!3OiuH1|5vquFro4FT?+A7>pz;u6mluIO=TB^_>oIl%z=m@k%83*J0tT3o#KnJRPgr>Gn{F4}PD;#!fM0ZjbX#ez!!}gl zX0)?zqHGTh6jHtPx}qCUB8X%WiET9{^yB}Ej+*8vzoRFF0n9iC=(npH_I-19kE-9x zA`?mE9R)p#iS>PyMKXFONXo(FywqLvefB95Gw~k2=k>E(5S5od70Wx1b2o?ZH+dNT zKbF2901stuRhVCss?kW|yUj-L4CUDKb_aXWZlP%#$D-Xc#Z(9S#yViBS2Up?t5^7} z!Njm9Cr%&c0nOP2c_WbL;;2*Yo8#joxykIrP+nJ2mUmkYXVWr!iL%q#m zk{DgPAI+|KW+-V*eD+Y@d=`|~HG;&2|Ms@0RVVN0&%L3aMc>1JuK#zvL|%&x#G}Na zb?q|dD5IM#JNi8e|98|s;{)Cudm1}ZZ7j*Yf3f#!rugVL?Y%U@=$P)wdQJqH7lQrj zr#PK;V|T_v5$5=xo+$ssWrQS%R^&YY^Kd^u_}Yp zx1CCN5%+V7qZO-v3?xNGoa5}12UsPtc1i7Iy1YQH4&@i+6TuJ#uEehYfXj-f@kwD{ z);$N~IvxDGOZ`tSTqnpOkVb*c6@{iwkoyGLlwxnzqNv6iM%_X|Bf4KHFAm+Dk z0pz&h8H~w4RWrfzXDI-TjXaT)vzxs#A?n49U<--)ar=a)VaSD!D6y9K}oRcE-p%{%yn1?3bZn``h8*FELJ>{sYFM zcLX~e9Nr|@D^_M<=k2yZRNsKx^X9Kfrhn1)LoB-rhjsO;u7zui4^K)|Z+(?Fys@i}*-m;1RFV>};yoHn7e zWv)!0E9sjn42AH5KrZP_pp-Y&&Tc|V^OPSx`*h}AFRRPe{oPG%dD5HDnzGZ6Vh$9rEH3?G*;n(oW;D+^IJkm8oNb}%?31f$0D-c3NJxmROYWcbR%niv(wFQevM$W zooK7(}OdTbJD4*bQAWmXJW%?AZWohCl zPN+>6a-ESLWZ$q1%zG3r-b+H1*s!2j`r>z2RQ5f-S`k3#8F4hsU!8-+0CqcG0XP;8==%#)Ic(86c9er zQq9nEaSU4`ke_xxTvdtrmQC#&iDu}%J;p7T`=6)uvUaEG=F?Gp=Y1_cgI1*3yO0DGtyv4Q__&mY-9{v)`RdO6pQzHtwo}eJ63i7;%IatbdH^pjAPY2JWoIDErntG=?EF$psx# zJ;gL~?}kmb--OI-I>m&_&|`T_otRyZb@E$|GyeGKLUa7^fl{W(*eA_0HmhMoj(jx2 z9$bgI(@)!y{R7b866yeZL0g8uCLMP+S<<-Biw}X}e%D}`O3Frj*;0Eyg(K5i(Ff2^ zLS8)YOS1~yR(+3w$|^f#6;zsyzDH`OtCYVr|E2T~t-Uq}1k6QR?DHR=nJs|Y^&RSND2XNBGaa(B~~m z7iVzLf{A2+dta! z+v2lOeu*zdK_=ra&|)rqfG*BQ+q9Nm)TTu8Wtp@O9{l($Z8bLwj&5J+^h527&EDJc ztNr>@!H(r?O})kJOlAtVq6&)xTv2AOR(I~Q?WL`k8img zHNDT4^a<0zs+eQEp8Q}$x0MWKglRI>;1qn8E;ua)q3n{T)h?Ab-z+XbIe(VBWco+h zs&;u}>wmsq{{o69gjEoDi2?ufieJ7?{8I6yDn8E@|HA!vl~8)e!fn~TC|j(Seq04w z_-*GSuxb->p`zC0{ATQLyQbT4REMTp-6iVwrQin_PX}$k4zQ1OO%1yZb3=p^ z*LoM~=J8@HPdyRqHY95?RliV zF{gDV7F9Bhex?`4EoXRAv4L3Wj@lqW*_%Wl{O{qp=J7EaHtbj$&Tq_(R&-NA_4Ka} zV&{jC(ZzQ@O&33sbu{&E7JVg0Br7G~%wW57Q?Dc{Q@3Mcb7jD$c5Mu;C%SO=t?t84j!9I z&|37IoVs+lwJH6f@T?V0Cu!PIa)Dc6!iw>SEuOQLVbDMWZ?@WqxBYErrP$^TZBaeZ zzBl=#U#q>pUSe!PX4M*87r zvxbH7{A_+N54E^A0eCmpzXLIkra@%I;0|sV8)zu*JBk>(xa$BiT)unOiL5n*o8Qi> ziBHKV=dSwqBJoS|FN{TUxlGK({*k(lVZ!VfiTd(D6>M;?E=zP-$R*jv3~u1;%WhBc zpW_BGSV2nXPam=aJO0qIn|}YTwS%R&VzJK^5V(0|eugV-Jg3Bj5X5x$3C`QQ#HLgr z1Dbm}`q(ywY-Mz}Q!BlP+SBcBzTJ9X=#}rj>tx|x46@C>L@HfKgF^Nfgtni>0*S4y z;T-px_)^+f#2!)Vq%RnLW}CcUJ2>R-*CDq= zN~hf6_z?&OrcCs1>0@PLVpc8T%}>q$01^Q)K9Lm=CBA_0%!hNGfZ&Z2ZQ=#5y?~(N zjA3v^t)#?m%&rID+y1@m9NPL}F3GmGHYXm@zL`_Z4-VDBu6_U6*1lc!{}#Wci`D-N zGA;dodh7bXw%+@l=f`?WZAjbVLRzMK!qN0p*Z;-Q(K6frn>+UZ`9)JRLf|l#nY$1I z)*9(;e>ZEYWTj6ri4!xK;)!h%c^6~-__wSd7+?!CqTt!3U5NsjSbS07>VznGUGJPI z$gGdSzs-8vg+Rzusw;sose?cuBGx+OfuzCdm=PuucA(kX?<5Z18y}n4oNvW}?vPeY zt#yaA&j^Npu#Akv^yR_`4v($8kU6mx3V-F)C<5b54j~w}A{eT-ayMnGwQr^_m3&x1 zZgV@kx6CcN+@Q-fT-x!Bl@HE}Zgd(zM!-^k{7!>HyKaqOqqn=qp;c!w$o)txfI#zzG}&d&W|vLv%6dIyu* z*dUmbH0ng9_K=ji59l&lw$2WS=I{#cUW!C8ShwzC2BLrCn}!z0JQFP{_YK7~(umGko*t$y zYI&?pRHR!H5%fEEt4$=os-r~?enURx5`;3wgYh`w_MQKwB8fns?284wXvaY2nZE7W z#;#;#_8-dLlEKkO<5Ho4|J<~8h-`7DD~z0&CpV7Om_l1)YUK1$i*>PX!J0EEa^JLx zH%i~88>^qt)>ci?NQAVJ~;O*FF9M5BUhpwK2_ zbfN)gbfQ6hHKJ{CDW%reQb+;{LShnN97o5sZf#xqw=Qj6%OX}2Xjv_?D1un`QV*8%z_y(6>F>5WF^-|x2h~;reOej4m@d8Lmc)SQ+m!4xyvwdX*EeA-(wR?PEH zZ1j8P=3?jN6V0yFy^jEBFuit0R~!GFNJ9GhSnfbL0!|+$@Fbub! zjJ2klLF;+G^{%@K6&{02Bnl07QKLgp&$1gzn2rp1<~81-$**rdJ(zms8@|O^^ePyL zmOQRHqX%j1UJ6Evt@E>*;4H+RoR$47`D-vX)KJ-LZ(@K}WPmf}@l=<8*U#-V2tsA5 zwKQ35m1lRMv0Bkc@JqC0;aZDD(y6xX5ejGJEjE}m(|7bd7kxgBUI1wZu3{Suu4d`W z=s~RSg|5T1(G@A%r$sXUM8~Cv1AQqv5Gp(g{v*C&Kka9%?EVm`32r)*G1jCQi1xz| z_fD-xE5W{P=9J21b5f%mP|wTED4*@VPj|!gVD);_gBM;gJ;46EzG;4T`&S;mSBsK& zW*~4c0yg{=@MJ?O!R&x0eD4=&wVu;_fOBXj53l+c6r)^*);>7;QIBjaBmXQvQ;Pm~ z_JIi=e`mn|p2nWJh-Hj34Q@2Ek5OWrc}(L9*tY!3lw*Rjtq?$P{^k+a$II%Mzsqjl z>b_a+OU&4x)J!AEZCROGQ)w3P(%4=U*KYH7KU0~PlhdIH1t>O_Kk3o<0(h8@wivBc`%65M*JpU&BTj$ZSnJO zZ)>XklLpaH^wxYxSL3gR-YVYqEQy$B#yB)5e@C~kX|y1)_-T^h+AbT#l523*<&N7fqmZdlm={Chc5 zIR8eO-K%jN54OG6W4LG)TkEd|+u!?7Xy;#YFvExab?>2Z;a@FTV%k~x8LS>Xyu}nTFkXqO(H)W*}X!s^k5r2WEtS}`B9l{r1 z-n+u&{9Ax2cP|46KF`IozD59mXNxu0RliOkXK}7lb}(3!k-Kd;1u3)q22+M&_0fTV zvqx4XzK>|-AUPoeC47`PBIzo|w0lU_CJ zunqlRt1;_~Pv;W~b&}|A&4UON5(Hn25L4I{@@X-TtS;ueq4cX4E6C_1Y$w9vEOgnP|3=A4uPr(On}ZiRfv z$5Zhe8dFnDteo) zI@ixUta(7|qNn*HN2klz7QH2hH&1W8w8NW6PJY0Q$rC5=;7|%X!}I`$gvci8S38%8 z2b#viodr`aVDf7|%5bLh5Sti#kwbr|N?NkvJFK#ZH8E%Vd&CzpA8gY~_Fzl@ziwZX zYqXkV|KU3VbI?DRf|0Js=QvD}0)9{8eMwtQAkAwo~*ZwS}}_Qrut$HF@BZM-%h;McP0CoAGvkraFV;ec`JF9s28OGhu!7_!_l~;k=p=h9+L?)7%Et0x{n-F z@K>ekuqb9HIfgw9V_K-Z>&#{RJ@7+q*;r=|G3By|)D5^s*4 z@ydw*$cy%8Su&4rScFFi@8B;QxWZ}A(vYo5)%-(_C8(#yKHsEiB5tc#!#R2( zdlQO0WuMs}vh?}38xu|9G>jI(b-P2DeZ6T%hgCW!ULlsGPI;g(e=`3hF7yal8~N4> z-uFK)MVsAx@q20FyZhR7>(PRN~Ih#)P0pQW(O6f8yx zyLpN<$D5-VCFoKgL$%h(-&cP_DQQD8OUzcdkB%<13ajOx8@PA*r-=IJ{$hCU%pV0~ z4PCOTB1-T^B$)u77elV(l}rip*ZdNHO?E;ys9DFT#Di%?JY8KeK$3u?j>%Yk#?w|7^=yBU$HL<L_)kZ$Lmu1o4>Pzg2TIv-fCSer18hj<0+e{f9{LM zKYwH{DK~vBGL^+ftvW)BfK$f0>jONesI+;RIHp6)X_od=l|}>p$+A0f(5Lw#2M{ho;C}+`=}*=Nk+LCmODH*o@|Q;&0>p& z&Sr`9+&sEt4uN93ibhQu%&B4Lt4~w3(T_98N_Y9Al3h%v-0$ezU#7)oYv& z@0NEHL*wijWWM;@Gc0NkQai7*)%Bt}jo%Dg;~8F!&RMGPC|lu(58bu8a|abVPujZL zyt?%LAY0vY|4ZvmvUN?k8n)6{>iwRhSni3com=hOxwogxXKLRT-aGSc#Y;c%z#Wxp z|7iQF(1Ynb&Ih353;?SB#fO{z?HcFVkZ&{q#Z#vLgDlhm9#rQl0UTp%Jue0DxnG*m ztM3MbW=-+1eem#It}(#5jR$e(<(+*vQ-#UQo&PiZ8((KX%?JV4ztMFwlnY-M$WYLY z*5L^3SUf-12kR~s^&2sG%ToH1`GI7e{ID$2SZCfuF@H`af1Xs)kbrvl(TW;zfZIi^s~DIDVV@Ev`O_ohZFtP@S}4fc1o=_#Tw5Wa|j``up7$;Ow(wnU;cpfAI?0@ueb_QmU~-hYs`0(po2Slbi4O5(HCUA+vEhH1fi7Au3+8EH^lF|yc>Ga| z3R_NLyoim$H^1a$LVS172-fM6Z&e!mAjQ2llbu+2o6NqQncfQ@Nq=>p`<3|G!)v-L zj6P@n9a&%fa?4?%=P6=jTJ4{;g+pZJ$2XnkOJ1ISac=DRBSPJu4xAVdwf)D8ufO)s z<+kimxdC7Ddz3gpCEWM5!cb1_OJ)46_n+}utyztPBP+?a-{<4gd^{sWVdlou>d-w@f?)9cTf}yU0q$#sF2WB-WmJz=wdU!J>~O0 zc>Ft>|FEmL^P8Q?HbmW7)w$7qKiR(DGthkBvh_xVY|_3}Me z=;KMMt5K8CgrJYaa3W{?q9Qw;{+a?<4zuo^p?W6-V`nSEyXkTPXe9WhU(oj!p&vN^ z&n6Sf7I_u$eVO9DhrMnnNA9Z1NrvH#mhW+@@BvU=+FEMCIT90rQ(>MNMNutjH-Yn% z!TP03GhX(gYyf+8-Bj&#f42Yr8*^Er7c_v5K>thqb42Q?^^H_plz{dw93aqN`sC_R zLK;=({5+wCa@D%f%yrF&ENj&TZob}BN@Su3y`K|8FipFU6tm$W$1*7xKT*vx; zD~n(|O%D2*_=P%?BzaG{1310Cv=fQ(wxO;*v-gi3zZLMl+y0>)Y?rJ~EntY+Qs?~b zcN_5lYFTD7#>PRRZUw{24xDocQ-C25|AKKNCRVR)ZkUJ^J;c8tG-0AnoY^i~qvSzm zaI`87I1g3ZZ|IhZW~*D}R<@FCN^&jb^Go#wbeGJHES*?gJHkIl=4JnaE>7c`#EN*C zf59&%5Wdo@wsd0T7Zdyot_AweDFY@}Z!pHO)r6fHi_}Dj<&cR`X0fxX$S_RNnJ9h- zQkzo^hxu_<1zwjEE-`Pn9>CiJ^mdT@w%8fYE9d2d`17%?V&our&X}|=j6o`~yeInb z0DpM&PaaGJNyW}3w(RzSUfESJtiTmp{@r3(^4b)@$KCgb*!PQh?_4OTzpypEunp!N zE;JbZcZ=Krmv?E9oG00eh9e+o1_}2_vp)F5rDE&Z-=A3{lLqYg-@_!}@vm%x@tzxG zM_qlnRz9=Jf{$s<-^?;=Ij)2s?@Au+t}h=$ z(>3QYFUMu+<9{a)^gsVj4kn_W<#F!6!da+qh#2f?=Y*r@lrp_HjlpHLIvg2W7VH^2 z)Iz6*oTxEC5;GT%JfpS|3fz29ZR?9q>t$1ZX!%%UfW$4u<@H&F>6}>=^1ra6c2R&b zA%C5+JO{4-34uT7R*sDo7jW^T5fjG{VtD@8SpR}Cv5;?K?auDg*wf_c>L$!)>yx8# z(+O>G#`qVk*XQ+zZK*HE?sI0<#Jb42WN27$<^+POxj7RR;LJ(&oHZZrbx~=u7avQP zfT|Hxit5)fUPKPoNypem+DIdRXRy`~2cS$)Os=^II{3MPofkHq5ya9;s&uwQuzGCS zG_X61WGDII$c4!1v1QKl7^quomi`!nfX-~fIOJb2rE+3q%1Aj1$h@zR76gR6i((bh zm1UF?v|#kq;BnU>tWU*cHIuNIn*Tg^H0O`a%I7fP=vkBW8SSDDXJnBG!2Pgt`5Y02 z{zYHZVARFV?1|S!=9q!$@iiap4NN>eGKA7s94;$mnS`(Mvps@-(1DrIy&w0x6o~N# zwA=%c)#=H}Inl(YdQ+0-&&25c+qFCzxAgr&n!Zi^;eSuxH~k3uuGs|)^ z1N36SDbwSm%^2eA=%e8LiXn9cOSxE@628nIp|)LC{;mhj=S1t4;RhP5s`tOJu6A(% zSoQw84WxhwTz?G&+E{sJtYRP+lSI`Ywv0bBHhAEe*d?OsrBHPtPygQ3H?l$-QKyI4 z^IRdj?uG=Pd|-)tJwgBVkzm!tF_Fef9tR=rZf=4TfGgsDx4zee(qx{gL*xy4iIO1H zO7vSptlZK#4$= zN&tM%5=3Cs~67_2k)N` zEd3Wizpi{||NH+U-*38D>Gyy6=A7sS8=>FvlFF-VUkFecQu$>gl_x=Lmm`&rFX!Sq z(eGz17mSTnl#e08R0RANS1f-lvHYnkmXj3z)KYFwefggH$aqoi<)Ym2Q0`K0#zVQ| zMY+lPURN2h{HY|$1fdhrXIz_c&DTjeN2A{x3O*6)t&6Od{1M>es#1+g*TQ^?w2_2HC)v{fnB3EG z`hZ2G7vF^SyS3&{q?*e~LsPQ_QHUlO#c&cFP4@%jXZ?=lCguUdO{m_P-1PDvGr7s~ zq1?85WAIUZRi?+^%uV~5#^n!ijNrpi92IEhi{TGoTuVx+KQo0`{t2e}=l?i=gfEu$h-8FqJ!TR)mK(n& z5zqgxt;h1zCOc((Qs7N2M=`O?-FssBtu1wQsapyiN;69vkLzN+nOX{y{p{3otr+q< zmLU?$M721ah%w3m7Pvt$JK@%uY!Xvh8-&o^7v6GL7sh8zb&F5zYz3^`5=`Cfgm%M3$)AYOza z_dA=g9SkonbzWke_{J&|l?E)khc(CWGj7ChWcB-lk@!4vHy;#8p_iTe&0E%Lcw zrRtFFrc8m{0b>j7ILxQ0!zRQYJK>>d?+Rzpzx&`iGbj`}gH6)GY(bAL3iYZ*bc{9m zId)n4L7;c#i^l@Q|Lg0$l`%q#P54xqlRro-r8z*1zwazX0PU!zCyvJa9bo^HnQEY> zH~V#!gBzyzwdOW;>Fe1muG#8q`0H?&zbah*T6cdIe=Ye{792ZW#qtVYz)&$v%yd~R zJ$L7?QQAXy=dWS*+MT}!**n92ey+3FPx9p*i@$u0OHtyc{qoHJmdK!C8i7%%Sf@!nR^0L@A5#UPk$%)poc5Riyly~ z=gI8l%=uCz!TvUj-{A6AJ<~tDhR~Y>z%d(M*eUQ&ReUhbmk`SaEL_AuPI& zIUn|!#7UFoW;t%Si{vfpC8Jj5d=L3(7wUQDM;q7io>set99wDFLXc1?R1fug)D~V#_WIGYB z?tdMq#u-*0>MB|c3G4}pK?tSJhkwtcI;%n5x<3ud%Kuv#T$lbz+iUhr5HU2G^|h#J zq`Ua-`+Pp-lE((^nz!%s3`$ONQ1CIDnPc_^UxbeF8LZow%zK^%RSvE`n3)6fvGZ@x z2pWIP)|#<~+R#r6$8Z&@zFFu%FX+ju;eJ2ys)uBCCn0}gcL8MEkB!M||IpT&kC~Gc z(-|%Kh^tUFp3$ay-w@rm)|3WMVsp9UNz*{1BBLL-*5v4MbD!bsF_j-73lJ7c`1i3q zGxR|dSb@#k#d|8I= z0X5f39z(Z@zwKonvHquH-LYprI0uOvSt!h~af9PzlRh`;2yT_TQE(XRcY8$+G@z|; z25vP2i*JHyfOC}xHu*4Pr15E);nrV9yfwS!?0zS|7aWGj-xQ1ynxTDmadjIawRaBI zZyxy1Bp6`zM9vpN6sZM8;>1$&XG}fDTYNVy7QqufmUqs<9Pz$=Q)bDeeEe}MPGiMc zORD}fLK2sWicI^`@zaX5NkzpQ{c!Yoe3bGd&Ud0-CCR^t1TFnN2EtN(jK(e7lje{N zdWP*wj%tAIA(&q<^Rb&zshX{1&JBa2KEVub~RkIDV~bbnEC0jZ@f-OMpMjU=$T^o`H`7q3>< z@>_qdWK$QDU|i3O3KyCCOS|JXdwX|FFX~pcWWHLX4_4R@R`C(pua58P$;b=kjyj&G zFdEHbNm3Hj4-`!}-38)EGiulXG?GJw^U7chzw=3q~tqnc|Lm-8~mLY z@R(SVoU)vp7QcC)sN|8|u!RzEnQ7l-dS?<=8I^;*i@lcI>M?4_dWqnaN%eq^KEbwS zrMPe;k26_JZa7c=qt57cQhQC-XE!SmB(43B*r-XAkbtcUN5|%$6YJfJ2EE4Oyu?-?74Hn%U$WK%J z;^R`5TbYmoP{(cKXjb*c<{<_PGr4nq`D!)}Y{3HBPyG41CRPZDu@z23yS(GH-NUv~ zEHCj#-aDhsLw$jZp4-m61J4GAGIz3dN&d%CU!65PSI(mc8dt)mzuUlgOxg139vUvk zXY@McQEC+MJ%yes>3>4|x!~kY39#x_B;JeV^?laeixYlEHzQJT?aX_I63*W?u)+Q& zcY_W?jXn~*Is+-dgW5GbI93k|?1LYjK`jIIU{}+Aq|%XDDJrZ~I%!`G#>(FnRO9jp zcxckzF3eYqUnF73I#OU2`8ILu2p0KoxP!9c2)!NB6;guxhJ2ER9!4(CuRv?Ke08Y$ zjj2~D;davm%^eMvnl05a-E1JK(FTdWuyk)TaJt7euYLiw9y~+DVQ#`H0G{y0IbqRY#M!vaUA`Qvw zV|<^9aw9{mcosqUa{9ee1j#pAJRVu+9GNa-Cc3ZrllqaU|?T zhPGVE6%%FqIdS%AE z-#qh_qI74y{+b!V@yne=>jwr=YFFm1NGgu3>lWy^yuGwC> z^+R+rVu2+1N&Da!+X-GS4G!B7oqQ=fo#Z^nfg2y-pbw&C;U9M{qZ3*ux(tKJB+ol3 zH)PQWhN{O+YG#>h&d1TyP-J^(*k-odMua14oWE)!^XAaK+mw0l^`9)|mn)W_Q=!7a zw&{~{sG;TRwOcXJ^_S{TWNG`-{AB+izRfDa^mZ!gmx}{CmK70c7M)U-WKY0M_0T3< z?XK&g8bEy2_mc7LMkgqFTy=2M(;b`Bm z4{UUE0FflX+FE`DLenerYf{;m$Vn^R4*-Th~w^%3wJj{51^lp3Og$yoj!Proq^WdqfB z#onw%zcKRTNvF8T(v7AnB9kS zi)(ju!%*Sqxn**lHbmM~QEI|M#9tbD=V%uIM6Ln|37E_SrHz6j1*mlYqfdAkiwh-1 z*j#IZBSJcCNSoXrkldc(tv_<`@UUh=HX+uB$s-P?>Z?~MJNmltuja6^23(*qUY;WqL@PXbel+?X|}5 zCA8t)u;mBUMEd4X`F7P_zN)@@?bNeqcXlgGVpHM-LY%X+b5l4Lq7kIZRgcz(%0DMK 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