This is an automated email from the ASF dual-hosted git repository.

shreemaan-abhishek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


The following commit(s) were added to refs/heads/master by this push:
     new e58f6e85 fix: reject invalid GatewayProxy plugin configuration (#2878)
e58f6e85 is described below

commit e58f6e853dfc4fe41dc22168a8c9dd6d25c82b38
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Fri Oct 9 14:40:32 2026 +0800

    fix: reject invalid GatewayProxy plugin configuration (#2878)
---
 internal/adc/translator/gateway.go                 |  30 ++++--
 .../adc/translator/gatewayproxy_plugins_test.go    | 103 +++++++++++++++++++++
 internal/adc/translator/ingressclass.go            |   8 +-
 3 files changed, 129 insertions(+), 12 deletions(-)

diff --git a/internal/adc/translator/gateway.go 
b/internal/adc/translator/gateway.go
index 68dcae81..1ab55a90 100644
--- a/internal/adc/translator/gateway.go
+++ b/internal/adc/translator/gateway.go
@@ -60,8 +60,12 @@ func (t *Translator) TranslateGateway(tctx 
*provider.TranslateContext, obj *gate
        globalRules := make(adctypes.GlobalRule)
        pluginMetadata := make(adctypes.PluginMetadata)
        // apply plugins from GatewayProxy to global rules
-       t.fillPluginsFromGatewayProxy(globalRules, &gatewayProxy)
-       t.fillPluginMetadataFromGatewayProxy(pluginMetadata, &gatewayProxy)
+       if err := t.fillPluginsFromGatewayProxy(globalRules, &gatewayProxy); 
err != nil {
+               return nil, err
+       }
+       if err := t.fillPluginMetadataFromGatewayProxy(pluginMetadata, 
&gatewayProxy); err != nil {
+               return nil, err
+       }
        result.GlobalRules = globalRules
        result.PluginMetadata = pluginMetadata
 
@@ -237,9 +241,9 @@ func (t *Translator) translateFrontendValidation(tctx 
*provider.TranslateContext
 }
 
 // fillPluginsFromGatewayProxy fill plugins from GatewayProxy to given plugins
-func (t *Translator) fillPluginsFromGatewayProxy(plugins adctypes.GlobalRule, 
gatewayProxy *v1alpha1.GatewayProxy) {
+func (t *Translator) fillPluginsFromGatewayProxy(plugins adctypes.GlobalRule, 
gatewayProxy *v1alpha1.GatewayProxy) error {
        if gatewayProxy == nil {
-               return
+               return nil
        }
 
        for _, plugin := range gatewayProxy.Spec.Plugins {
@@ -252,26 +256,32 @@ func (t *Translator) fillPluginsFromGatewayProxy(plugins 
adctypes.GlobalRule, ga
                pluginConfig := map[string]any{}
                if len(plugin.Config.Raw) > 0 {
                        if err := json.Unmarshal(plugin.Config.Raw, 
&pluginConfig); err != nil {
-                               t.Log.Error(err, "gateway proxy plugin config 
unmarshal failed", "plugin", pluginName)
-                               continue
+                               return fmt.Errorf("failed to unmarshal config 
of GatewayProxy plugin %q: %w", pluginName, err)
+                       }
+                       if pluginConfig == nil {
+                               return fmt.Errorf("config of GatewayProxy 
plugin %q must be a JSON object", pluginName)
                        }
                }
                plugins[pluginName] = pluginConfig
        }
        t.Log.V(1).Info("fill plugins for gateway proxy", "plugins", plugins)
+       return nil
 }
 
-func (t *Translator) fillPluginMetadataFromGatewayProxy(pluginMetadata 
adctypes.PluginMetadata, gatewayProxy *v1alpha1.GatewayProxy) {
+func (t *Translator) fillPluginMetadataFromGatewayProxy(pluginMetadata 
adctypes.PluginMetadata, gatewayProxy *v1alpha1.GatewayProxy) error {
        if gatewayProxy == nil {
-               return
+               return nil
        }
        for pluginName, plugin := range gatewayProxy.Spec.PluginMetadata {
                var pluginConfig map[string]any
                if err := json.Unmarshal(plugin.Raw, &pluginConfig); err != nil 
{
-                       t.Log.Error(err, "gateway proxy plugin_metadata 
unmarshal failed", "plugin", pluginName)
-                       continue
+                       return fmt.Errorf("failed to unmarshal GatewayProxy 
plugin metadata for %q: %w", pluginName, err)
+               }
+               if pluginConfig == nil {
+                       return fmt.Errorf("GatewayProxy plugin metadata for %q 
must be a JSON object", pluginName)
                }
                t.Log.V(1).Info("fill plugin_metadata for gateway proxy", 
"plugin", pluginName)
                pluginMetadata[pluginName] = pluginConfig
        }
+       return nil
 }
diff --git a/internal/adc/translator/gatewayproxy_plugins_test.go 
b/internal/adc/translator/gatewayproxy_plugins_test.go
new file mode 100644
index 00000000..a3275925
--- /dev/null
+++ b/internal/adc/translator/gatewayproxy_plugins_test.go
@@ -0,0 +1,103 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package translator
+
+import (
+       "context"
+       "testing"
+
+       "github.com/go-logr/logr"
+       "github.com/stretchr/testify/require"
+       networkingv1 "k8s.io/api/networking/v1"
+       apiextensionsv1 
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
+
+       "github.com/apache/apisix-ingress-controller/api/v1alpha1"
+       "github.com/apache/apisix-ingress-controller/internal/provider"
+       "github.com/apache/apisix-ingress-controller/internal/utils"
+)
+
+func TestGatewayProxyPluginRenderingErrors(t *testing.T) {
+       invalidConfigs := []struct {
+               name      string
+               configure func(*v1alpha1.GatewayProxy)
+               errText   string
+       }{
+               {
+                       name: "plugin config",
+                       configure: func(gatewayProxy *v1alpha1.GatewayProxy) {
+                               gatewayProxy.Spec.Plugins = 
[]v1alpha1.GatewayProxyPlugin{
+                                       {
+                                               Name:    "response-rewrite",
+                                               Enabled: true,
+                                               Config:  
apiextensionsv1.JSON{Raw: []byte(`["not-an-object"]`)},
+                                       },
+                               }
+                       },
+                       errText: `failed to unmarshal config of GatewayProxy 
plugin "response-rewrite"`,
+               },
+               {
+                       name: "plugin metadata",
+                       configure: func(gatewayProxy *v1alpha1.GatewayProxy) {
+                               gatewayProxy.Spec.PluginMetadata = 
map[string]apiextensionsv1.JSON{
+                                       "key-auth": {Raw: 
[]byte(`["not-an-object"]`)},
+                               }
+                       },
+                       errText: `failed to unmarshal GatewayProxy plugin 
metadata for "key-auth"`,
+               },
+       }
+
+       callers := []struct {
+               name      string
+               translate func(*Translator, v1alpha1.GatewayProxy) 
(*TranslateResult, error)
+       }{
+               {
+                       name: "Gateway",
+                       translate: func(tr *Translator, gatewayProxy 
v1alpha1.GatewayProxy) (*TranslateResult, error) {
+                               tctx := 
provider.NewDefaultTranslateContext(context.Background())
+                               gateway := &gatewayv1.Gateway{ObjectMeta: 
metav1.ObjectMeta{Namespace: "default", Name: "gateway"}}
+                               
tctx.GatewayProxies[utils.NamespacedNameKind(gateway)] = gatewayProxy
+                               return tr.TranslateGateway(tctx, gateway)
+                       },
+               },
+               {
+                       name: "IngressClass",
+                       translate: func(tr *Translator, gatewayProxy 
v1alpha1.GatewayProxy) (*TranslateResult, error) {
+                               tctx := 
provider.NewDefaultTranslateContext(context.Background())
+                               ingressClass := 
&networkingv1.IngressClass{ObjectMeta: metav1.ObjectMeta{Name: "apisix"}}
+                               
tctx.GatewayProxies[utils.NamespacedNameKind(ingressClass)] = gatewayProxy
+                               return tr.TranslateIngressClass(tctx, 
ingressClass)
+                       },
+               },
+       }
+
+       for _, caller := range callers {
+               for _, invalidConfig := range invalidConfigs {
+                       t.Run(caller.name+"/"+invalidConfig.name, func(t 
*testing.T) {
+                               tr := &Translator{Log: logr.Discard()}
+                               gatewayProxy := v1alpha1.GatewayProxy{}
+                               invalidConfig.configure(&gatewayProxy)
+
+                               result, err := caller.translate(tr, 
gatewayProxy)
+                               require.ErrorContains(t, err, 
invalidConfig.errText)
+                               require.Nil(t, result)
+                       })
+               }
+       }
+}
diff --git a/internal/adc/translator/ingressclass.go 
b/internal/adc/translator/ingressclass.go
index 064bd77d..9052fc56 100644
--- a/internal/adc/translator/ingressclass.go
+++ b/internal/adc/translator/ingressclass.go
@@ -38,8 +38,12 @@ func (t *Translator) TranslateIngressClass(tctx 
*provider.TranslateContext, obj
        globalRules := make(adctypes.GlobalRule)
        pluginMetadata := make(adctypes.PluginMetadata)
        // apply plugins from GatewayProxy to global rules
-       t.fillPluginsFromGatewayProxy(globalRules, &gatewayProxy)
-       t.fillPluginMetadataFromGatewayProxy(pluginMetadata, &gatewayProxy)
+       if err := t.fillPluginsFromGatewayProxy(globalRules, &gatewayProxy); 
err != nil {
+               return nil, err
+       }
+       if err := t.fillPluginMetadataFromGatewayProxy(pluginMetadata, 
&gatewayProxy); err != nil {
+               return nil, err
+       }
 
        result.GlobalRules = globalRules
        result.PluginMetadata = pluginMetadata

Reply via email to