diff --git a/pkg/mutation/mutators/assign/assign_mutator.go b/pkg/mutation/mutators/assign/assign_mutator.go index 4315deb3ee3..266f4b03922 100644 --- a/pkg/mutation/mutators/assign/assign_mutator.go +++ b/pkg/mutation/mutators/assign/assign_mutator.go @@ -118,6 +118,9 @@ func (m *Mutator) String() string { // MutatorForAssign returns a mutator built from the given assign instance. func MutatorForAssign(assign *mutationsunversioned.Assign) (*Mutator, error) { + if err := core.ValidateName(assign.Name); err != nil { + return nil, err + } // This is not always set by the kubernetes API server assign.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: mutationsv1beta1.GroupVersion.Group, Kind: "Assign"}) diff --git a/pkg/mutation/mutators/assign/assign_mutator_test.go b/pkg/mutation/mutators/assign/assign_mutator_test.go index af4a19ef071..00070335814 100644 --- a/pkg/mutation/mutators/assign/assign_mutator_test.go +++ b/pkg/mutation/mutators/assign/assign_mutator_test.go @@ -11,6 +11,8 @@ import ( mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned" "github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata" "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match" + "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/core" + "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/testhelpers" path "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester" "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types" "github.com/stretchr/testify/require" @@ -1073,11 +1075,32 @@ func nestedMapSlice(u map[string]interface{}, fields ...string) ([]map[string]in return out, nil } -// Tests the Assign mutator MutatorForAssign call with an empty spec for graceful handling. -func Test_Assign_emptySpec(t *testing.T) { - assign := &mutationsunversioned.Assign{} - mutator, err := MutatorForAssign(assign) +func Test_Assign_errors(t *testing.T) { + for _, tt := range []struct { + name string + mut *mutationsunversioned.Assign + errMsg string + }{ + { + name: "empty path", + mut: &mutationsunversioned.Assign{}, + errMsg: "empty path", + }, + { + name: "name > 63", + mut: &mutationsunversioned.Assign{ + ObjectMeta: metav1.ObjectMeta{ + Name: testhelpers.BigName(), + }, + }, + errMsg: core.ErrNameLength.Error(), + }, + } { + t.Run(tt.name, func(t *testing.T) { + mutator, err := MutatorForAssign(tt.mut) - require.ErrorContains(t, err, "empty path") - require.Nil(t, mutator) + require.ErrorContains(t, err, tt.errMsg) + require.Nil(t, mutator) + }) + } } diff --git a/pkg/mutation/mutators/assignimage/assignimage_mutator.go b/pkg/mutation/mutators/assignimage/assignimage_mutator.go index d0862538a15..3417421e6d9 100644 --- a/pkg/mutation/mutators/assignimage/assignimage_mutator.go +++ b/pkg/mutation/mutators/assignimage/assignimage_mutator.go @@ -115,6 +115,10 @@ func (m *Mutator) String() string { // MutatorForAssignImage returns a mutator built from // the given assignImage instance. func MutatorForAssignImage(assignImage *mutationsunversioned.AssignImage) (*Mutator, error) { + if err := core.ValidateName(assignImage.Name); err != nil { + return nil, err + } + // This is not always set by the kubernetes API server assignImage.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: mutationsv1beta1.GroupVersion.Group, Kind: "AssignImage"}) diff --git a/pkg/mutation/mutators/assignimage/assignimage_mutator_test.go b/pkg/mutation/mutators/assignimage/assignimage_mutator_test.go index 854637146a8..f7672de1a7c 100644 --- a/pkg/mutation/mutators/assignimage/assignimage_mutator_test.go +++ b/pkg/mutation/mutators/assignimage/assignimage_mutator_test.go @@ -8,7 +8,10 @@ import ( mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned" "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match" + "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/core" + "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/testhelpers" "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types" + "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -392,3 +395,33 @@ func TestMutatorForAssignImage(t *testing.T) { }) } } + +func Test_AssignImage_errors(t *testing.T) { + for _, tt := range []struct { + name string + mut *mutationsunversioned.AssignImage + errMsg string + }{ + { + name: "empty path", + mut: &mutationsunversioned.AssignImage{}, + errMsg: "empty path", + }, + { + name: "name > 63", + mut: &mutationsunversioned.AssignImage{ + ObjectMeta: metav1.ObjectMeta{ + Name: testhelpers.BigName(), + }, + }, + errMsg: core.ErrNameLength.Error(), + }, + } { + t.Run(tt.name, func(t *testing.T) { + mutator, err := MutatorForAssignImage(tt.mut) + + require.ErrorContains(t, err, tt.errMsg) + require.Nil(t, mutator) + }) + } +} diff --git a/pkg/mutation/mutators/assignmeta/assignmeta_mutator.go b/pkg/mutation/mutators/assignmeta/assignmeta_mutator.go index 634ec643231..84d7a29f608 100644 --- a/pkg/mutation/mutators/assignmeta/assignmeta_mutator.go +++ b/pkg/mutation/mutators/assignmeta/assignmeta_mutator.go @@ -124,6 +124,10 @@ func (m *Mutator) String() string { // MutatorForAssignMetadata builds a Mutator from the given AssignMetadata object. func MutatorForAssignMetadata(assignMeta *mutationsunversioned.AssignMetadata) (*Mutator, error) { + if err := core.ValidateName(assignMeta.Name); err != nil { + return nil, err + } + // This is not always set by the kubernetes API server assignMeta.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: mutationsv1beta1.GroupVersion.Group, Kind: "AssignMetadata"}) diff --git a/pkg/mutation/mutators/assignmeta/assignmeta_mutator_test.go b/pkg/mutation/mutators/assignmeta/assignmeta_mutator_test.go index 5ab99f73be6..448d48a6b32 100644 --- a/pkg/mutation/mutators/assignmeta/assignmeta_mutator_test.go +++ b/pkg/mutation/mutators/assignmeta/assignmeta_mutator_test.go @@ -6,6 +6,8 @@ import ( "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned" "github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata" + "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/core" + "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/testhelpers" "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -109,11 +111,32 @@ func TestAssignMetadata(t *testing.T) { } } -// Tests the AssignMeta mutator MutatorForAssignMetadata call with an empty spec for graceful handling. -func Test_AssignMeta_emptySpec(t *testing.T) { - assignMeta := &unversioned.AssignMetadata{} - mutator, err := MutatorForAssignMetadata(assignMeta) +func Test_AssignMetadata_errors(t *testing.T) { + for _, tt := range []struct { + name string + mut *unversioned.AssignMetadata + errMsg string + }{ + { + name: "empty spec", + mut: &unversioned.AssignMetadata{}, + errMsg: "invalid location for assignmetadata", + }, + { + name: "name > 63", + mut: &unversioned.AssignMetadata{ + ObjectMeta: metav1.ObjectMeta{ + Name: testhelpers.BigName(), + }, + }, + errMsg: core.ErrNameLength.Error(), + }, + } { + t.Run(tt.name, func(t *testing.T) { + mutator, err := MutatorForAssignMetadata(tt.mut) - require.ErrorContains(t, err, "invalid location for assignmetadat") - require.Nil(t, mutator) + require.ErrorContains(t, err, tt.errMsg) + require.Nil(t, mutator) + }) + } } diff --git a/pkg/mutation/mutators/core/errors.go b/pkg/mutation/mutators/core/errors.go index fc11957244b..224defc8e17 100644 --- a/pkg/mutation/mutators/core/errors.go +++ b/pkg/mutation/mutators/core/errors.go @@ -4,4 +4,7 @@ import "errors" // ErrNonKeyedSetter occurs when a setter that doesn't understand keyed lists // is called against a keyed list. -var ErrNonKeyedSetter = errors.New("mutator does not understand keyed lists") +var ( + ErrNonKeyedSetter = errors.New("mutator does not understand keyed lists") + ErrNameLength = errors.New("maximum name length is 63 characters") +) diff --git a/pkg/mutation/mutators/core/mutator.go b/pkg/mutation/mutators/core/mutator.go index 507448d28c5..1859fe5b27b 100644 --- a/pkg/mutation/mutators/core/mutator.go +++ b/pkg/mutation/mutators/core/mutator.go @@ -14,7 +14,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" ) -// NewTester returns a patht.Tester for the given object name, kind path and +// NewTester returns a path.Tester for the given object name, kind path and // pathtests. func NewTester(name string, kind string, path parser.Path, ptests []unversioned.PathTest) (*patht.Tester, error) { pathTests, err := gatherPathTests(name, kind, ptests) @@ -141,3 +141,11 @@ func MatchWithApplyTo(mut *types.Mutable, applies []match.ApplyTo, mat *match.Ma return matches, nil } + +func ValidateName(name string) error { + if len(name) > 63 { + return ErrNameLength + } + + return nil +} diff --git a/pkg/mutation/mutators/modifyset/modify_set_mutator.go b/pkg/mutation/mutators/modifyset/modify_set_mutator.go index 590d1920ea4..451e93fc386 100644 --- a/pkg/mutation/mutators/modifyset/modify_set_mutator.go +++ b/pkg/mutation/mutators/modifyset/modify_set_mutator.go @@ -126,6 +126,10 @@ func (m *Mutator) String() string { // MutatorForModifySet returns an Mutator built from // the given modifyset instance. func MutatorForModifySet(modifySet *mutationsunversioned.ModifySet) (*Mutator, error) { + if err := core.ValidateName(modifySet.Name); err != nil { + return nil, err + } + // This is not always set by the kubernetes API server modifySet.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: mutationsv1beta1.GroupVersion.Group, Kind: "ModifySet"}) diff --git a/pkg/mutation/mutators/modifyset/modify_set_mutator_test.go b/pkg/mutation/mutators/modifyset/modify_set_mutator_test.go index 473e214e241..6b0d05c5fe0 100644 --- a/pkg/mutation/mutators/modifyset/modify_set_mutator_test.go +++ b/pkg/mutation/mutators/modifyset/modify_set_mutator_test.go @@ -4,14 +4,38 @@ import ( "testing" mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned" + "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/core" + "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/testhelpers" "github.com/stretchr/testify/require" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// Tests the ModifySet mutator MutatorForModifySet call with an empty spec for graceful handling. -func Test_ModifySet_emptySpec(t *testing.T) { - modifySet := &mutationsunversioned.ModifySet{} - mutator, err := MutatorForModifySet(modifySet) +func Test_ModifySet_errors(t *testing.T) { + for _, tt := range []struct { + name string + mut *mutationsunversioned.ModifySet + errMsg string + }{ + { + name: "empty spec", + mut: &mutationsunversioned.ModifySet{}, + errMsg: "applyTo required for ModifySet mutator", + }, + { + name: "name > 63", + mut: &mutationsunversioned.ModifySet{ + ObjectMeta: v1.ObjectMeta{ + Name: testhelpers.BigName(), + }, + }, + errMsg: core.ErrNameLength.Error(), + }, + } { + t.Run(tt.name, func(t *testing.T) { + mutator, err := MutatorForModifySet(tt.mut) - require.ErrorContains(t, err, "applyTo required for ModifySet mutator") - require.Nil(t, mutator) + require.ErrorContains(t, err, tt.errMsg) + require.Nil(t, mutator) + }) + } } diff --git a/pkg/mutation/mutators/testhelpers/dummy_mutator.go b/pkg/mutation/mutators/testhelpers/dummy_mutator.go index bd5c0219205..3d8a846b558 100644 --- a/pkg/mutation/mutators/testhelpers/dummy_mutator.go +++ b/pkg/mutation/mutators/testhelpers/dummy_mutator.go @@ -2,6 +2,7 @@ package testhelpers import ( "reflect" + "strings" "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match" "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/core" @@ -65,3 +66,8 @@ func NewDummyMutator(name, path string, value interface{}) *DummyMutator { } return &DummyMutator{name: name, path: p, value: value} } + +// BigName returns a 64-length string. +func BigName() string { + return strings.Repeat("abigname", 8) // 8 X 8 = 64 +} diff --git a/pkg/webhook/policy.go b/pkg/webhook/policy.go index 6d4eaebd5cb..cb9c707d160 100644 --- a/pkg/webhook/policy.go +++ b/pkg/webhook/policy.go @@ -341,8 +341,11 @@ func (h *validationHandler) validateGatekeeperResources(ctx context.Context, req return true, nil } - gvk := req.AdmissionRequest.Kind + if len(req.Name) > 63 { + return false, fmt.Errorf("resource cannot have metadata.name larger than 63 char; length: %d", len(req.Name)) + } + gvk := req.AdmissionRequest.Kind switch { case gvk.Group == "templates.gatekeeper.sh" && gvk.Kind == "ConstraintTemplate": return h.validateTemplate(ctx, req) diff --git a/pkg/webhook/policy_test.go b/pkg/webhook/policy_test.go index 024ce6382b3..b2a4b8c76f7 100644 --- a/pkg/webhook/policy_test.go +++ b/pkg/webhook/policy_test.go @@ -2,9 +2,11 @@ package webhook import ( "context" + "encoding/json" "testing" "github.com/open-policy-agent/frameworks/constraint/pkg/apis/constraints" + externadatav1alpha1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/v1alpha1" templatesv1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1" constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client" "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego" @@ -18,6 +20,7 @@ import ( "github.com/open-policy-agent/gatekeeper/v3/pkg/target" "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard" testclients "github.com/open-policy-agent/gatekeeper/v3/test/clients" + "github.com/stretchr/testify/require" admissionv1 "k8s.io/api/admission/v1" authenticationv1 "k8s.io/api/authentication/v1" corev1 "k8s.io/api/core/v1" @@ -123,29 +126,25 @@ spec: - apiGroups: [""] kinds: ["Pod"] ` - - validProvider = ` -apiVersion: externaldata.gatekeeper.sh/v1alpha1 -kind: Provider -metadata: - name: dummy-provider -spec: - url: https://localhost:8080/validate - timeout: 1 - caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUIwekNDQVgyZ0F3SUJBZ0lKQUkvTTdCWWp3Qit1TUEwR0NTcUdTSWIzRFFFQkJRVUFNRVV4Q3pBSkJnTlYKQkFZVEFrRlZNUk13RVFZRFZRUUlEQXBUYjIxbExWTjBZWFJsTVNFd0h3WURWUVFLREJoSmJuUmxjbTVsZENCWAphV1JuYVhSeklGQjBlU0JNZEdRd0hoY05NVEl3T1RFeU1qRTFNakF5V2hjTk1UVXdPVEV5TWpFMU1qQXlXakJGCk1Rc3dDUVlEVlFRR0V3SkJWVEVUTUJFR0ExVUVDQXdLVTI5dFpTMVRkR0YwWlRFaE1COEdBMVVFQ2d3WVNXNTAKWlhKdVpYUWdWMmxrWjJsMGN5QlFkSGtnVEhSa01Gd3dEUVlKS29aSWh2Y05BUUVCQlFBRFN3QXdTQUpCQU5MSgpoUEhoSVRxUWJQa2xHM2liQ1Z4d0dNUmZwL3Y0WHFoZmRRSGRjVmZIYXA2TlE1V29rLzR4SUErdWkzNS9NbU5hCnJ0TnVDK0JkWjF0TXVWQ1BGWmNDQXdFQUFhTlFNRTR3SFFZRFZSME9CQllFRkp2S3M4UmZKYVhUSDA4VytTR3YKelF5S24wSDhNQjhHQTFVZEl3UVlNQmFBRkp2S3M4UmZKYVhUSDA4VytTR3Z6UXlLbjBIOE1Bd0dBMVVkRXdRRgpNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEUVFCSmxmZkpIeWJqREd4Uk1xYVJtRGhYMCs2djAyVFVLWnNXCnI1UXVWYnBRaEg2dSswVWdjVzBqcDlRd3B4b1BUTFRXR1hFV0JCQnVyeEZ3aUNCaGtRK1YKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= -` - - providerWithNoCA = ` -apiVersion: externaldata.gatekeeper.sh/v1alpha1 -kind: Provider -metadata: - name: dummy-provider -spec: - url: https://localhost:8080/validate - timeout: 1 -` ) +func validProvider() *externadatav1alpha1.Provider { + return &externadatav1alpha1.Provider{ + TypeMeta: metav1.TypeMeta{ + APIVersion: externadatav1alpha1.SchemeGroupVersion.String(), + Kind: "Provider", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-provider", + }, + Spec: externadatav1alpha1.ProviderSpec{ + URL: "https://localhost:8080/validate", + Timeout: 1, + CABundle: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUIwekNDQVgyZ0F3SUJBZ0lKQUkvTTdCWWp3Qit1TUEwR0NTcUdTSWIzRFFFQkJRVUFNRVV4Q3pBSkJnTlYKQkFZVEFrRlZNUk13RVFZRFZRUUlEQXBUYjIxbExWTjBZWFJsTVNFd0h3WURWUVFLREJoSmJuUmxjbTVsZENCWAphV1JuYVhSeklGQjBlU0JNZEdRd0hoY05NVEl3T1RFeU1qRTFNakF5V2hjTk1UVXdPVEV5TWpFMU1qQXlXakJGCk1Rc3dDUVlEVlFRR0V3SkJWVEVUTUJFR0ExVUVDQXdLVTI5dFpTMVRkR0YwWlRFaE1COEdBMVVFQ2d3WVNXNTAKWlhKdVpYUWdWMmxrWjJsMGN5QlFkSGtnVEhSa01Gd3dEUVlKS29aSWh2Y05BUUVCQlFBRFN3QXdTQUpCQU5MSgpoUEhoSVRxUWJQa2xHM2liQ1Z4d0dNUmZwL3Y0WHFoZmRRSGRjVmZIYXA2TlE1V29rLzR4SUErdWkzNS9NbU5hCnJ0TnVDK0JkWjF0TXVWQ1BGWmNDQXdFQUFhTlFNRTR3SFFZRFZSME9CQllFRkp2S3M4UmZKYVhUSDA4VytTR3YKelF5S24wSDhNQjhHQTFVZEl3UVlNQmFBRkp2S3M4UmZKYVhUSDA4VytTR3Z6UXlLbjBIOE1Bd0dBMVVkRXdRRgpNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEUVFCSmxmZkpIeWJqREd4Uk1xYVJtRGhYMCs2djAyVFVLWnNXCnI1UXVWYnBRaEg2dSswVWdjVzBqcDlRd3B4b1BUTFRXR1hFV0JCQnVyeEZ3aUNCaGtRK1YKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=", + }, + } +} + func validRegoTemplate() *templates.ConstraintTemplate { return &templates.ConstraintTemplate{ TypeMeta: metav1.TypeMeta{ @@ -502,6 +501,27 @@ func TestConstraintValidation(t *testing.T) { } } +func Test_ConstrainTemplate_Name(t *testing.T) { + h := &validationHandler{log: log} + te := validRegoTemplate() + te.Name = "abignameabignameabignameabignameabignameabignameabignameabigname" + + b, err := convertToRawExtension(te) + require.NoError(t, err) + + review := &admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Kind: metav1.GroupVersionKind(templatesv1beta1.SchemeGroupVersion.WithKind("ConstraintTemplate")), + Object: *b, + Name: te.Name, + }, + } + + got, err := h.validateGatekeeperResources(context.Background(), review) + require.False(t, got) + require.ErrorContains(t, err, "resource cannot have metadata.name larger than 63 char") +} + func TestTracing(t *testing.T) { tc := []struct { Name string @@ -866,52 +886,76 @@ func TestValidateConfigResource(t *testing.T) { func TestValidateProvider(t *testing.T) { tests := []struct { name string - provider string + provider *externadatav1alpha1.Provider want bool wantErr bool }{ { name: "valid provider", - provider: validProvider, + provider: validProvider(), want: false, wantErr: false, }, { - name: "invalid provider", - provider: "invalid", - want: false, - wantErr: true, + name: "invalid provider", + provider: func() *externadatav1alpha1.Provider { + return &externadatav1alpha1.Provider{} + }(), + want: false, + wantErr: true, }, { - name: "provider with no CA", - provider: providerWithNoCA, - want: true, - wantErr: true, + name: "provider with no CA", + provider: func() *externadatav1alpha1.Provider { + p := validProvider() + p.Spec.CABundle = "" + return p + }(), + want: true, + wantErr: true, + }, + { + name: "provider with big name", + provider: func() *externadatav1alpha1.Provider { + p := validProvider() + p.Name = "abignameabignameabignameabignameabignameabignameabignameabigname" + return p + }(), + wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := &validationHandler{log: log} - b, err := yaml.YAMLToJSON([]byte(tt.provider)) - if err != nil { - t.Fatalf("Error parsing yaml: %s", err) - } + b, err := convertToRawExtension(tt.provider) + require.NoError(t, err) req := &admission.Request{ AdmissionRequest: admissionv1.AdmissionRequest{ - Object: runtime.RawExtension{ - Raw: b, - }, + Kind: metav1.GroupVersionKind(externadatav1alpha1.SchemeGroupVersion.WithKind("Provider")), + Object: *b, + Name: tt.provider.Name, }, } - got, err := h.validateProvider(req) + got, err := h.validateGatekeeperResources(context.Background(), req) if (err != nil) != tt.wantErr { - t.Errorf("validationHandler.validateProvider() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("validationHandler.validateGatekeeperResources() error = %v, wantErr %v", err, tt.wantErr) return } if got != tt.want { - t.Errorf("validationHandler.validateProvider() = %v, want %v", got, tt.want) + t.Errorf("validationHandler.validateGatekeeperResources() = %v, want %v", got, tt.want) } }) } } + +// converts runtime.Object to runtime.RawExtension. +func convertToRawExtension(obj runtime.Object) (*runtime.RawExtension, error) { + re := &runtime.RawExtension{} + b, err := json.Marshal(obj) + if err != nil { + return nil, err + } + re.Raw = b + return re, nil +}