From b0ce45e7eee833f0a572fe09d21dfa44e1b8537f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Fri, 7 Jun 2024 09:52:06 +0200 Subject: [PATCH] [Backport release/3.1.x] fix: do not sanitize plugins' config (#6138) (#6155) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: do not sanitize plugins' config This reverts commit 2d615e3df5956d6ebd4e0b0137ff6dffc20294c1. * ensure we do not sanitize plugins' config in ut Co-authored-by: Grzegorz BurzyƄski --- internal/dataplane/kongstate/kongstate.go | 4 +- .../dataplane/kongstate/kongstate_test.go | 10 +- internal/dataplane/kongstate/plugin.go | 126 +- internal/dataplane/kongstate/plugin_test.go | 1034 ++++++++--------- internal/dataplane/kongstate/types.go | 14 + 5 files changed, 489 insertions(+), 699 deletions(-) diff --git a/internal/dataplane/kongstate/kongstate.go b/internal/dataplane/kongstate/kongstate.go index da1aa7c9f3..ed449b8b00 100644 --- a/internal/dataplane/kongstate/kongstate.go +++ b/internal/dataplane/kongstate/kongstate.go @@ -47,9 +47,7 @@ func (ks *KongState) SanitizedCopy(uuidGenerator util.UUIDGenerator) *KongState return }(), CACertificates: ks.CACertificates, - Plugins: lo.Map(ks.Plugins, func(p Plugin, _ int) Plugin { - return p.SanitizedCopy() - }), + Plugins: ks.Plugins, Consumers: func() (res []Consumer) { for _, v := range ks.Consumers { res = append(res, *v.SanitizedCopy(uuidGenerator)) diff --git a/internal/dataplane/kongstate/kongstate_test.go b/internal/dataplane/kongstate/kongstate_test.go index a8feab3be1..9369d3dae5 100644 --- a/internal/dataplane/kongstate/kongstate_test.go +++ b/internal/dataplane/kongstate/kongstate_test.go @@ -58,10 +58,7 @@ func TestKongState_SanitizedCopy(t *testing.T) { Upstreams: []Upstream{{Upstream: kong.Upstream{ID: kong.String("1")}}}, Certificates: []Certificate{{Certificate: kong.Certificate{ID: kong.String("1"), Key: kong.String("secret")}}}, CACertificates: []kong.CACertificate{{ID: kong.String("1")}}, - Plugins: []Plugin{{ - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{WholeConfigIsSensitive: true}, - Plugin: kong.Plugin{ID: kong.String("1"), Config: kong.Configuration{"secret": "secretValue"}}, - }}, + Plugins: []Plugin{{Plugin: kong.Plugin{ID: kong.String("1"), Config: map[string]interface{}{"key": "secret"}}}}, Consumers: []Consumer{{ KeyAuths: []*KeyAuth{{kong.KeyAuth{ID: kong.String("1"), Key: kong.String("secret")}}}, }}, @@ -82,10 +79,7 @@ func TestKongState_SanitizedCopy(t *testing.T) { Upstreams: []Upstream{{Upstream: kong.Upstream{ID: kong.String("1")}}}, Certificates: []Certificate{{Certificate: kong.Certificate{ID: kong.String("1"), Key: redactedString}}}, CACertificates: []kong.CACertificate{{ID: kong.String("1")}}, - Plugins: []Plugin{{ - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{WholeConfigIsSensitive: true}, - Plugin: kong.Plugin{ID: kong.String("1"), Config: kong.Configuration{"secret": *redactedString}}, - }}, + Plugins: []Plugin{{Plugin: kong.Plugin{ID: kong.String("1"), Config: map[string]interface{}{"key": "secret"}}}}, // We don't redact plugins' config. Consumers: []Consumer{{ KeyAuths: []*KeyAuth{{kong.KeyAuth{ID: kong.String("1"), Key: kong.String("{vault://52fdfc07-2182-454f-963f-5f0f9a621d72}")}}}, }}, diff --git a/internal/dataplane/kongstate/plugin.go b/internal/dataplane/kongstate/plugin.go index a14de0ae14..56b7465882 100644 --- a/internal/dataplane/kongstate/plugin.go +++ b/internal/dataplane/kongstate/plugin.go @@ -4,14 +4,11 @@ import ( "encoding/json" "errors" "fmt" - "strings" jsonpatch "github.com/evanphx/json-patch/v5" "github.com/kong/go-kong/kong" - "github.com/samber/lo" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/yaml" "github.com/kong/kubernetes-ingress-controller/v3/internal/store" @@ -19,107 +16,6 @@ import ( kongv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1" ) -// Plugin represents a plugin Object in Kong. -type Plugin struct { - kong.Plugin - K8sParent client.Object - SensitiveFieldsMeta PluginSensitiveFieldsMetadata -} - -func (p Plugin) DeepCopy() Plugin { - return Plugin{ - Plugin: *p.Plugin.DeepCopy(), - K8sParent: p.K8sParent, - SensitiveFieldsMeta: p.SensitiveFieldsMeta, - } -} - -func (p Plugin) SanitizedCopy() Plugin { - // We do not want to return an error if any of below fails - the best we can do - // is to return a plugin with wholly redacted config. - // Let's have a closure returning a plugin with wholly redacted config prepared. - whollySanitized := func() Plugin { - p := p.DeepCopy() - p.Config = sanitizeWholePluginConfig(p.Config) - return p - } - - // If the whole config is sensitive, we need to redact the entire config. - if p.SensitiveFieldsMeta.WholeConfigIsSensitive { - return whollySanitized() - } - - // If there are JSON paths, we need to redact them. - if len(p.SensitiveFieldsMeta.JSONPaths) > 0 { - var patchOperations []string - for _, path := range p.SensitiveFieldsMeta.JSONPaths { - // If the path is empty, we need to sanitize the whole config. - // An empty path means that the patch is on the root of the config. - if path == "" { - return whollySanitized() - } - - patchOperations = append(patchOperations, fmt.Sprintf( - `{"op":"replace","path":"%s","value":"%s"}`, - path, - *redactedString, - )) - } - - // Decode the patch and apply it to the config. - // We need to marshal the config to JSON and then unmarshal it back to Configuration - // because the patch library works with bytes. - patch, err := jsonpatch.DecodePatch([]byte(fmt.Sprintf("[%s]", strings.Join(patchOperations, ",")))) - if err != nil { - return whollySanitized() - } - configB, err := json.Marshal(p.Config) - if err != nil { - return whollySanitized() - } - sanitizedConfigB, err := patch.Apply(configB) - if err != nil { - return whollySanitized() - } - sanitizedConfig := kong.Configuration{} - if err := json.Unmarshal(sanitizedConfigB, &sanitizedConfig); err != nil { - return whollySanitized() - } - - sanitized := p.DeepCopy() - sanitized.Config = sanitizedConfig - return sanitized - } - - // Nothing to sanitize. - return p -} - -// sanitizeWholePluginConfig redacts the entire config of a plugin by replacing all of its -// values with a redacted string. -func sanitizeWholePluginConfig(config kong.Configuration) kong.Configuration { - sanitized := config.DeepCopy() - for k := range config { - sanitized[k] = *redactedString - } - return sanitized -} - -// PluginSensitiveFieldsMetadata holds metadata about sensitive fields in a plugin's configuration. -// It can be used to sanitize them before exposing the configuration to the user (e.g. in debug dumps -// or in Konnect Admin API). -type PluginSensitiveFieldsMetadata struct { - // WholeConfigIsSensitive indicates that the entire configuration of the plugin is sensitive. - // If this is true, the configuration should be redacted entirely (each of its fields' values - // should be replaced with a redacted string). - WholeConfigIsSensitive bool - - // JSONPaths holds a list of JSON paths to sensitive fields in the plugin's configuration. - // If this is not empty, the configuration should be redacted by replacing the values of the - // fields at these paths with a redacted string. - JSONPaths []string -} - // getKongPluginOrKongClusterPlugin fetches a KongPlugin or KongClusterPlugin (as fallback) from the store. // If both are not found, an error is returned. func getKongPluginOrKongClusterPlugin(s store.Storer, namespace, name string) ( @@ -181,14 +77,6 @@ func kongPluginFromK8SClusterPlugin( } } - // Prepare sensitive fields metadata for the plugin. - sensitiveFieldsMeta := PluginSensitiveFieldsMetadata{ - JSONPaths: lo.Map(k8sPlugin.ConfigPatches, func(patch kongv1.NamespacedConfigPatch, _ int) string { - return patch.Path - }), - WholeConfigIsSensitive: k8sPlugin.ConfigFrom != nil, - } - return Plugin{ Plugin: plugin{ Name: k8sPlugin.PluginName, @@ -201,8 +89,7 @@ func kongPluginFromK8SClusterPlugin( Protocols: protocolsToStrings(k8sPlugin.Protocols), Tags: util.GenerateTagsForObject(&k8sPlugin), }.toKongPlugin(), - K8sParent: &k8sPlugin, - SensitiveFieldsMeta: sensitiveFieldsMeta, + K8sParent: &k8sPlugin, }, nil } @@ -244,14 +131,6 @@ func kongPluginFromK8SPlugin( } } - // Prepare sensitive fields metadata for the plugin. - sensitiveFieldsMeta := PluginSensitiveFieldsMetadata{ - JSONPaths: lo.Map(k8sPlugin.ConfigPatches, func(patch kongv1.ConfigPatch, _ int) string { - return patch.Path - }), - WholeConfigIsSensitive: k8sPlugin.ConfigFrom != nil, - } - return Plugin{ Plugin: plugin{ Name: k8sPlugin.PluginName, @@ -264,8 +143,7 @@ func kongPluginFromK8SPlugin( Protocols: protocolsToStrings(k8sPlugin.Protocols), Tags: util.GenerateTagsForObject(&k8sPlugin), }.toKongPlugin(), - K8sParent: &k8sPlugin, - SensitiveFieldsMeta: sensitiveFieldsMeta, + K8sParent: &k8sPlugin, }, nil } diff --git a/internal/dataplane/kongstate/plugin_test.go b/internal/dataplane/kongstate/plugin_test.go index 5faf399c26..fed7b3f1cb 100644 --- a/internal/dataplane/kongstate/plugin_test.go +++ b/internal/dataplane/kongstate/plugin_test.go @@ -5,7 +5,6 @@ import ( "github.com/kong/go-kong/kong" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -15,6 +14,7 @@ import ( ) func TestKongPluginFromK8SClusterPlugin(t *testing.T) { + assert := assert.New(t) store, _ := store.NewFakeStore(store.FakeObjects{ Secrets: []*corev1.Secret{ { @@ -32,284 +32,277 @@ func TestKongPluginFromK8SClusterPlugin(t *testing.T) { }, }, }) - + type args struct { + plugin kongv1.KongClusterPlugin + } tests := []struct { name string - plugin kongv1.KongClusterPlugin - want Plugin + args args + want kong.Plugin wantErr bool }{ { name: "basic configuration", - plugin: kongv1.KongClusterPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - InstanceName: "example", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), + args: args{ + plugin: kongv1.KongClusterPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + InstanceName: "example", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("correlation-id"), - Config: kong.Configuration{ - "header_name": "foo", - }, - Protocols: kong.StringSlice("http"), - InstanceName: kong.String("example"), + want: kong.Plugin{ + Name: kong.String("correlation-id"), + Config: kong.Configuration{ + "header_name": "foo", }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{JSONPaths: []string{}}, + Protocols: kong.StringSlice("http"), + InstanceName: kong.String("example"), }, wantErr: false, }, { name: "secret configuration", - plugin: kongv1.KongClusterPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - ConfigFrom: &kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Key: "correlation-id-config", - Secret: "conf-secret", - Namespace: "default", + args: args{ + plugin: kongv1.KongClusterPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + ConfigFrom: &kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Key: "correlation-id-config", + Secret: "conf-secret", + Namespace: "default", + }, }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("correlation-id"), - Config: kong.Configuration{ - "header_name": "foo", - }, - Protocols: kong.StringSlice("http"), - }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - WholeConfigIsSensitive: true, - JSONPaths: []string{}, + want: kong.Plugin{ + Name: kong.String("correlation-id"), + Config: kong.Configuration{ + "header_name": "foo", }, + Protocols: kong.StringSlice("http"), }, wantErr: false, }, { name: "missing secret configuration", - plugin: kongv1.KongClusterPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - ConfigFrom: &kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Key: "correlation-id-config", - Secret: "missing", - Namespace: "default", + args: args{ + plugin: kongv1.KongClusterPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + ConfigFrom: &kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Key: "correlation-id-config", + Secret: "missing", + Namespace: "default", + }, }, }, }, - want: Plugin{}, + want: kong.Plugin{}, wantErr: true, }, { name: "non-JSON configuration", - plugin: kongv1.KongClusterPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{{}`), + args: args{ + plugin: kongv1.KongClusterPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{{}`), + }, }, }, - want: Plugin{}, + want: kong.Plugin{}, wantErr: true, }, { name: "both Config and ConfigFrom set", - plugin: kongv1.KongClusterPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), - }, - ConfigFrom: &kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Key: "correlation-id-config", - Secret: "conf-secret", - Namespace: "default", + args: args{ + plugin: kongv1.KongClusterPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, + ConfigFrom: &kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Key: "correlation-id-config", + Secret: "conf-secret", + Namespace: "default", + }, }, }, }, - want: Plugin{}, + want: kong.Plugin{}, wantErr: true, }, { name: "Config and ConfigPatches set", - plugin: kongv1.KongClusterPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), - }, - ConfigPatches: []kongv1.NamespacedConfigPatch{ - { - Path: "/generator", - ValueFrom: kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Key: "correlation-id-generator", - Secret: "conf-secret", - Namespace: "default", + args: args{ + plugin: kongv1.KongClusterPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, + ConfigPatches: []kongv1.NamespacedConfigPatch{ + { + Path: "/generator", + ValueFrom: kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Key: "correlation-id-generator", + Secret: "conf-secret", + Namespace: "default", + }, }, }, }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("correlation-id"), - Config: kong.Configuration{ - "header_name": "foo", - "generator": "uuid", - }, - Protocols: kong.StringSlice("http"), - }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{"/generator"}, + want: kong.Plugin{ + Name: kong.String("correlation-id"), + Config: kong.Configuration{ + "header_name": "foo", + "generator": "uuid", }, + Protocols: kong.StringSlice("http"), }, }, { name: "configPatch on subpath of non-exist path", - plugin: kongv1.KongClusterPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "response-transformer", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"replace":{"headers":["foo:bar"]}}`), - }, - ConfigPatches: []kongv1.NamespacedConfigPatch{ - { - Path: "/add/headers", - ValueFrom: kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Namespace: "default", - Key: "response-transformer-add-headers", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongClusterPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "response-transformer", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"replace":{"headers":["foo:bar"]}}`), + }, + ConfigPatches: []kongv1.NamespacedConfigPatch{ + { + Path: "/add/headers", + ValueFrom: kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Namespace: "default", + Key: "response-transformer-add-headers", + Secret: "conf-secret", + }, }, }, }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("response-transformer"), - Config: kong.Configuration{ - "replace": map[string]interface{}{ - "headers": []interface{}{ - "foo:bar", - }, + want: kong.Plugin{ + Name: kong.String("response-transformer"), + Config: kong.Configuration{ + "replace": map[string]interface{}{ + "headers": []interface{}{ + "foo:bar", }, - "add": map[string]interface{}{ - "headers": []interface{}{ - "h1:v1", - "h2:v2", - }, + }, + "add": map[string]interface{}{ + "headers": []interface{}{ + "h1:v1", + "h2:v2", }, }, - Protocols: kong.StringSlice("http"), - }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{"/add/headers"}, }, + Protocols: kong.StringSlice("http"), }, }, { name: "empty config and configPatch for particular paths", - plugin: kongv1.KongClusterPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{}, - ConfigPatches: []kongv1.NamespacedConfigPatch{ - { - Path: "/header_name", - ValueFrom: kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Namespace: "default", - Key: "correlation-id-headername", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongClusterPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{}, + ConfigPatches: []kongv1.NamespacedConfigPatch{ + { + Path: "/header_name", + ValueFrom: kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Namespace: "default", + Key: "correlation-id-headername", + Secret: "conf-secret", + }, }, }, - }, - { - Path: "/generator", - ValueFrom: kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Namespace: "default", - Key: "correlation-id-generator", - Secret: "conf-secret", + { + Path: "/generator", + ValueFrom: kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Namespace: "default", + Key: "correlation-id-generator", + Secret: "conf-secret", + }, }, }, }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("correlation-id"), - Config: kong.Configuration{ - "header_name": "foo", - "generator": "uuid", - }, - Protocols: kong.StringSlice("http"), - }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{"/header_name", "/generator"}, + want: kong.Plugin{ + Name: kong.String("correlation-id"), + Config: kong.Configuration{ + "header_name": "foo", + "generator": "uuid", }, + Protocols: kong.StringSlice("http"), }, }, { name: "empty config and configPatch for whole object", - plugin: kongv1.KongClusterPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{}, - ConfigPatches: []kongv1.NamespacedConfigPatch{ - { - Path: "", - ValueFrom: kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Namespace: "default", - Key: "correlation-id-config", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongClusterPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{}, + ConfigPatches: []kongv1.NamespacedConfigPatch{ + { + Path: "", + ValueFrom: kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Namespace: "default", + Key: "correlation-id-config", + Secret: "conf-secret", + }, }, }, }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("correlation-id"), - Config: kong.Configuration{ - "header_name": "foo", - }, - Protocols: kong.StringSlice("http"), - }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{""}, + want: kong.Plugin{ + Name: kong.String("correlation-id"), + Config: kong.Configuration{ + "header_name": "foo", }, + Protocols: kong.StringSlice("http"), }, }, { name: "missing secret in configPatches", - plugin: kongv1.KongClusterPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), - }, - ConfigPatches: []kongv1.NamespacedConfigPatch{ - { - Path: "/generator", - ValueFrom: kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Namespace: "default", - Key: "correlation-id-generator", - Secret: "missing-secret", + args: args{ + plugin: kongv1.KongClusterPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, + ConfigPatches: []kongv1.NamespacedConfigPatch{ + { + Path: "/generator", + ValueFrom: kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Namespace: "default", + Key: "correlation-id-generator", + Secret: "missing-secret", + }, }, }, }, @@ -319,23 +312,25 @@ func TestKongPluginFromK8SClusterPlugin(t *testing.T) { }, { name: "missing key of secret in cofigPatches", - plugin: kongv1.KongClusterPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), - }, - ConfigPatches: []kongv1.NamespacedConfigPatch{ - { - Path: "/generator", - ValueFrom: kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Namespace: "default", - Key: "correlation-id-missing", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongClusterPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, + ConfigPatches: []kongv1.NamespacedConfigPatch{ + { + Path: "/generator", + ValueFrom: kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Namespace: "default", + Key: "correlation-id-missing", + Secret: "conf-secret", + }, }, }, }, @@ -345,23 +340,25 @@ func TestKongPluginFromK8SClusterPlugin(t *testing.T) { }, { name: "invalid value in configPatches", - plugin: kongv1.KongClusterPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), - }, - ConfigPatches: []kongv1.NamespacedConfigPatch{ - { - Path: "/generator", - ValueFrom: kongv1.NamespacedConfigSource{ - SecretValue: kongv1.NamespacedSecretValueFromSource{ - Namespace: "default", - Key: "correlation-id-invalid", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongClusterPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, + ConfigPatches: []kongv1.NamespacedConfigPatch{ + { + Path: "/generator", + ValueFrom: kongv1.NamespacedConfigSource{ + SecretValue: kongv1.NamespacedSecretValueFromSource{ + Namespace: "default", + Key: "correlation-id-invalid", + Secret: "conf-secret", + }, }, }, }, @@ -372,18 +369,19 @@ func TestKongPluginFromK8SClusterPlugin(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := kongPluginFromK8SClusterPlugin(store, tt.plugin) - if tt.wantErr { - require.Error(t, err) + got, err := kongPluginFromK8SClusterPlugin(store, tt.args.plugin) + if (err != nil) != tt.wantErr { + t.Errorf("kongPluginFromK8SClusterPlugin error = %v, wantErr %v", err, tt.wantErr) return } - tt.want.K8sParent = tt.plugin.DeepCopy() - assert.Equal(t, tt.want, got) + assert.Equal(tt.want, got.Plugin) + assert.NotEmpty(t, got.K8sParent) }) } } func TestKongPluginFromK8SPlugin(t *testing.T) { + assert := assert.New(t) store, _ := store.NewFakeStore(store.FakeObjects{ Secrets: []*corev1.Secret{ { @@ -401,296 +399,293 @@ func TestKongPluginFromK8SPlugin(t *testing.T) { }, }, }) + type args struct { + plugin kongv1.KongPlugin + } tests := []struct { name string - plugin kongv1.KongPlugin - want Plugin + args args + want kong.Plugin wantErr bool }{ { name: "basic configuration", - plugin: kongv1.KongPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - InstanceName: "example", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), + args: args{ + plugin: kongv1.KongPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + InstanceName: "example", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("correlation-id"), - Config: kong.Configuration{ - "header_name": "foo", - }, - Protocols: kong.StringSlice("http"), - InstanceName: kong.String("example"), + want: kong.Plugin{ + Name: kong.String("correlation-id"), + Config: kong.Configuration{ + "header_name": "foo", }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{JSONPaths: []string{}}, + Protocols: kong.StringSlice("http"), + InstanceName: kong.String("example"), }, wantErr: false, }, { name: "secret configuration", - plugin: kongv1.KongPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "default", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - ConfigFrom: &kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "correlation-id-config", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", }, - }, - }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("correlation-id"), - Config: kong.Configuration{ - "header_name": "foo", + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + ConfigFrom: &kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "correlation-id-config", + Secret: "conf-secret", + }, }, - Protocols: kong.StringSlice("http"), }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - WholeConfigIsSensitive: true, - JSONPaths: []string{}, + }, + want: kong.Plugin{ + Name: kong.String("correlation-id"), + Config: kong.Configuration{ + "header_name": "foo", }, + Protocols: kong.StringSlice("http"), }, wantErr: false, }, { name: "missing secret configuration", - plugin: kongv1.KongPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: "default", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - ConfigFrom: &kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "correlation-id-config", - Secret: "missing", + args: args{ + plugin: kongv1.KongPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + ConfigFrom: &kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "correlation-id-config", + Secret: "missing", + }, }, }, }, + want: kong.Plugin{}, wantErr: true, }, { name: "non-JSON configuration", - plugin: kongv1.KongPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{{}`), + args: args{ + plugin: kongv1.KongPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{{}`), + }, }, }, + want: kong.Plugin{}, wantErr: true, }, { name: "both Config and ConfigFrom set", - plugin: kongv1.KongPlugin{ - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), - }, - ConfigFrom: &kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "correlation-id-config", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongPlugin{ + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, + ConfigFrom: &kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "correlation-id-config", + Secret: "conf-secret", + }, }, }, }, + want: kong.Plugin{}, wantErr: true, }, { name: "config and configPatches set", - plugin: kongv1.KongPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "default", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), - }, - ConfigPatches: []kongv1.ConfigPatch{ - { - Path: "/generator", - ValueFrom: kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "correlation-id-generator", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, + ConfigPatches: []kongv1.ConfigPatch{ + { + Path: "/generator", + ValueFrom: kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "correlation-id-generator", + Secret: "conf-secret", + }, }, }, }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("correlation-id"), - Config: kong.Configuration{ - "header_name": "foo", - "generator": "uuid", - }, - Protocols: kong.StringSlice("http"), - }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{"/generator"}, + want: kong.Plugin{ + Name: kong.String("correlation-id"), + Config: kong.Configuration{ + "header_name": "foo", + "generator": "uuid", }, + Protocols: kong.StringSlice("http"), }, }, { name: "configPatch on subpath of non-exist path", - plugin: kongv1.KongPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "default", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "response-transformer", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"replace":{"headers":["foo:bar"]}}`), - }, - ConfigPatches: []kongv1.ConfigPatch{ - { - Path: "/add/headers", - ValueFrom: kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "response-transformer-add-headers", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "response-transformer", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"replace":{"headers":["foo:bar"]}}`), + }, + ConfigPatches: []kongv1.ConfigPatch{ + { + Path: "/add/headers", + ValueFrom: kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "response-transformer-add-headers", + Secret: "conf-secret", + }, }, }, }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("response-transformer"), - Config: kong.Configuration{ - "replace": map[string]interface{}{ - "headers": []interface{}{ - "foo:bar", - }, + want: kong.Plugin{ + Name: kong.String("response-transformer"), + Config: kong.Configuration{ + "replace": map[string]interface{}{ + "headers": []interface{}{ + "foo:bar", }, - "add": map[string]interface{}{ - "headers": []interface{}{ - "h1:v1", - "h2:v2", - }, + }, + "add": map[string]interface{}{ + "headers": []interface{}{ + "h1:v1", + "h2:v2", }, }, - Protocols: kong.StringSlice("http"), - }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{"/add/headers"}, }, + Protocols: kong.StringSlice("http"), }, }, { name: "empty config and configPatch for particular paths", - plugin: kongv1.KongPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "default", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{}, - ConfigPatches: []kongv1.ConfigPatch{ - { - Path: "/header_name", - ValueFrom: kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "correlation-id-headername", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{}, + ConfigPatches: []kongv1.ConfigPatch{ + { + Path: "/header_name", + ValueFrom: kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "correlation-id-headername", + Secret: "conf-secret", + }, }, }, - }, - { - Path: "/generator", - ValueFrom: kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "correlation-id-generator", - Secret: "conf-secret", + { + Path: "/generator", + ValueFrom: kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "correlation-id-generator", + Secret: "conf-secret", + }, }, }, }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("correlation-id"), - Config: kong.Configuration{ - "header_name": "foo", - "generator": "uuid", - }, - Protocols: kong.StringSlice("http"), - }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{"/header_name", "/generator"}, + want: kong.Plugin{ + Name: kong.String("correlation-id"), + Config: kong.Configuration{ + "header_name": "foo", + "generator": "uuid", }, + Protocols: kong.StringSlice("http"), }, }, { name: "empty config and configPatch for whole object", - plugin: kongv1.KongPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "default", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{}, - ConfigPatches: []kongv1.ConfigPatch{ - { - Path: "", - ValueFrom: kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "correlation-id-config", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{}, + ConfigPatches: []kongv1.ConfigPatch{ + { + Path: "", + ValueFrom: kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "correlation-id-config", + Secret: "conf-secret", + }, }, }, }, }, }, - want: Plugin{ - Plugin: kong.Plugin{ - Name: kong.String("correlation-id"), - Config: kong.Configuration{ - "header_name": "foo", - }, - Protocols: kong.StringSlice("http"), - }, - SensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{""}, + want: kong.Plugin{ + Name: kong.String("correlation-id"), + Config: kong.Configuration{ + "header_name": "foo", }, + Protocols: kong.StringSlice("http"), }, }, { name: "missing secret in configPatches", - plugin: kongv1.KongPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "default", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), - }, - ConfigPatches: []kongv1.ConfigPatch{ - { - Path: "/generator", - ValueFrom: kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "correlation-id-generator", - Secret: "missing-secret", + args: args{ + plugin: kongv1.KongPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, + ConfigPatches: []kongv1.ConfigPatch{ + { + Path: "/generator", + ValueFrom: kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "correlation-id-generator", + Secret: "missing-secret", + }, }, }, }, @@ -700,23 +695,25 @@ func TestKongPluginFromK8SPlugin(t *testing.T) { }, { name: "missing key of secret in configPatches", - plugin: kongv1.KongPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "default", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), - }, - ConfigPatches: []kongv1.ConfigPatch{ - { - Path: "/generator", - ValueFrom: kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "correlation-id-missing", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, + ConfigPatches: []kongv1.ConfigPatch{ + { + Path: "/generator", + ValueFrom: kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "correlation-id-missing", + Secret: "conf-secret", + }, }, }, }, @@ -726,23 +723,25 @@ func TestKongPluginFromK8SPlugin(t *testing.T) { }, { name: "invalid value in configPatches", - plugin: kongv1.KongPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "default", - }, - Protocols: []kongv1.KongProtocol{"http"}, - PluginName: "correlation-id", - Config: apiextensionsv1.JSON{ - Raw: []byte(`{"header_name": "foo"}`), - }, - ConfigPatches: []kongv1.ConfigPatch{ - { - Path: "/generator", - ValueFrom: kongv1.ConfigSource{ - SecretValue: kongv1.SecretValueFromSource{ - Key: "correlation-id-invalid", - Secret: "conf-secret", + args: args{ + plugin: kongv1.KongPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Protocols: []kongv1.KongProtocol{"http"}, + PluginName: "correlation-id", + Config: apiextensionsv1.JSON{ + Raw: []byte(`{"header_name": "foo"}`), + }, + ConfigPatches: []kongv1.ConfigPatch{ + { + Path: "/generator", + ValueFrom: kongv1.ConfigSource{ + SecretValue: kongv1.SecretValueFromSource{ + Key: "correlation-id-invalid", + Secret: "conf-secret", + }, }, }, }, @@ -753,108 +752,15 @@ func TestKongPluginFromK8SPlugin(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := kongPluginFromK8SPlugin(store, tt.plugin) - if tt.wantErr { - require.Error(t, err) + got, err := kongPluginFromK8SPlugin(store, tt.args.plugin) + if (err != nil) != tt.wantErr { + t.Errorf("kongPluginFromK8SPlugin error = %v, wantErr %v", err, tt.wantErr) return } // don't care about tags in this test got.Tags = nil - tt.want.K8sParent = tt.plugin.DeepCopy() - assert.Equal(t, tt.want, got) - }) - } -} - -func TestPlugin_SanitizedCopy(t *testing.T) { - testCases := []struct { - name string - config kong.Configuration - sensitiveFieldsMeta PluginSensitiveFieldsMetadata - expectedSanitizedConfig kong.Configuration - }{ - { - name: "sensitive fields are redacted with JSONPaths", - config: kong.Configuration{ - "secret": "secret-value", - "object": map[string]interface{}{ - "secretObjectField": "secret-object-field-value", - }, - }, - sensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{ - "/secret", - "/object/secretObjectField", - }, - }, - expectedSanitizedConfig: kong.Configuration{ - "secret": "{vault://redacted-value}", - "object": map[string]interface{}{ - "secretObjectField": "{vault://redacted-value}", - }, - }, - }, - { - name: "invalid JSONPath doesn't panic and redacts whole config as fallback", - config: kong.Configuration{ - "secret": "secret-value", - "object": map[string]interface{}{ - "secretObjectField": "secret-object-field-value", - }, - }, - sensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{ - "/not-existing-path", - }, - }, - expectedSanitizedConfig: kong.Configuration{ - "secret": "{vault://redacted-value}", - "object": "{vault://redacted-value}", - }, - }, - { - name: "whole config to sanitize", - config: kong.Configuration{ - "secret": "secret-value", - "object": map[string]interface{}{ - "secretObjectField": "secret-object-field-value", - }, - }, - sensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - WholeConfigIsSensitive: true, - }, - expectedSanitizedConfig: kong.Configuration{ - "secret": "{vault://redacted-value}", - "object": "{vault://redacted-value}", - }, - }, - { - name: "single empty JSON path - whole config is redacted", - config: kong.Configuration{ - "secret": "secret-value", - "object": map[string]interface{}{ - "secretObjectField": "secret-object-field-value", - }, - }, - sensitiveFieldsMeta: PluginSensitiveFieldsMetadata{ - JSONPaths: []string{""}, - }, - expectedSanitizedConfig: kong.Configuration{ - "secret": "{vault://redacted-value}", - "object": "{vault://redacted-value}", - }, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - p := Plugin{ - Plugin: kong.Plugin{ - Config: tc.config, - }, - SensitiveFieldsMeta: tc.sensitiveFieldsMeta, - } - sanitized := p.SanitizedCopy() - assert.Equal(t, tc.expectedSanitizedConfig, sanitized.Config) + assert.Equal(tt.want, got.Plugin) + assert.NotEmpty(t, got.K8sParent) }) } } diff --git a/internal/dataplane/kongstate/types.go b/internal/dataplane/kongstate/types.go index 282d81081f..fcfa7afe5a 100644 --- a/internal/dataplane/kongstate/types.go +++ b/internal/dataplane/kongstate/types.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/kong/go-kong/kong" + "sigs.k8s.io/controller-runtime/pkg/client" ) type PortMode int @@ -65,3 +66,16 @@ func (c *Certificate) SanitizedCopy() *Certificate { }, } } + +// Plugin represents a plugin Object in Kong. +type Plugin struct { + kong.Plugin + K8sParent client.Object +} + +func (p Plugin) DeepCopy() Plugin { + return Plugin{ + Plugin: *p.Plugin.DeepCopy(), + K8sParent: p.K8sParent, + } +}