From 6fe17eede9164794c21bb1ba296b461a0f678d9c Mon Sep 17 00:00:00 2001 From: Antoine Jacquemin Date: Thu, 28 Nov 2024 20:09:37 +0100 Subject: [PATCH] list refactor fix reflection add test fix lint fix lint add valid entities fux lint Updated go-apiops (#1452) * chore: updated go-apiops to v0.1.40 * chore: release prep for v1.41.4 fux lint fix lint fix lint --- CHANGELOG.md | 17 ++ README.md | 4 +- cmd/gateway_validate.go | 51 ++++-- go.mod | 8 +- go.sum | 19 ++- tests/integration/sync_test.go | 3 + .../expected-no-skip_konnect.yaml | 1 + tests/integration/validate_test.go | 20 ++- validate/validate.go | 159 +++++++++--------- 9 files changed, 169 insertions(+), 113 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 341b793e1..e03bc6636 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Table of Contents +- [v1.41.4](#v1414) - [v1.41.3](#v1413) - [v1.41.2](#v1412) - [v1.41.1](#v1411) @@ -100,6 +101,21 @@ - [v0.2.0](#v020) - [v0.1.0](#v010) +## [v1.41.4] +> Release date: 2024/11/26 + +### Fixes +- Added validation for ensuring that cookie parameters in parameter schemas are skipped +and a warning is logged for the user while using `deck file openapi2kong` command. +[#1452](https://github.com/Kong/deck/pull/1452) +[go-apiops #255](https://github.com/Kong/go-apiops/pull/225) +- Fixed issue where creating arrays with mixed types using oneOf in OAS specifications were +failing while using `deck file openapi2kong` command. +[#1452](https://github.com/Kong/deck/pull/1452) +[go-apiops #231](https://github.com/Kong/go-apiops/pull/231) + + + ## [v1.41.3] > Release date: 2024/11/25 @@ -1867,6 +1883,7 @@ No breaking changes have been introduced in this release. Debut release of decK +[v1.41.4]: https://github.com/Kong/deck/compare/v1.41.3...v1.41.4 [v1.41.3]: https://github.com/Kong/deck/compare/v1.41.2...v1.41.3 [v1.41.2]: https://github.com/Kong/deck/compare/v1.41.1...v1.41.2 [v1.41.1]: https://github.com/Kong/deck/compare/v1.40.0...v1.41.1 diff --git a/README.md b/README.md index 356bbba30..5122cefca 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ the GitHub [release page](https://github.com/kong/deck/releases) or install by downloading the binary: ```shell -$ curl -sL https://github.com/kong/deck/releases/download/v1.41.3/deck_1.41.3_linux_amd64.tar.gz -o deck.tar.gz +$ curl -sL https://github.com/kong/deck/releases/download/v1.41.4/deck_1.41.4_linux_amd64.tar.gz -o deck.tar.gz $ tar -xf deck.tar.gz -C /tmp $ sudo cp /tmp/deck /usr/local/bin/ ``` @@ -84,7 +84,7 @@ If you are on Windows, you can download the binary from the GitHub [release page](https://github.com/kong/deck/releases) or via PowerShell: ```shell -$ curl -sL https://github.com/kong/deck/releases/download/v1.41.3/deck_1.41.3_windows_amd64.tar.gz -o deck.tar.gz +$ curl -sL https://github.com/kong/deck/releases/download/v1.41.4/deck_1.41.4_windows_amd64.tar.gz -o deck.tar.gz $ tar -xzvf deck.tar.gz ``` diff --git a/cmd/gateway_validate.go b/cmd/gateway_validate.go index 37fe97e2d..2625d9284 100644 --- a/cmd/gateway_validate.go +++ b/cmd/gateway_validate.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os" + "sort" "github.com/blang/semver/v4" "github.com/kong/deck/utils" @@ -17,13 +18,13 @@ import ( ) var ( - validateCmdKongStateFile []string - validateCmdRBACResourcesOnly bool - validateCmdCheckOnlinePluginsOnly bool - validateOnline bool - validateWorkspace string - validateParallelism int - validateKonnectCompatibility bool + validateCmdKongStateFile []string + validateCmdOnlineEntitiesFilter []string + validateCmdRBACResourcesOnly bool + validateOnline bool + validateKonnectCompatibility bool + validateWorkspace string + validateParallelism int ) func executeValidate(cmd *cobra.Command, _ []string) error { @@ -211,6 +212,26 @@ this command unless --online flag is used. if len(validateCmdKongStateFile) == 0 { validateCmdKongStateFile = []string{"-"} } + + // Iterate over the input values and validate them against the keys in entityMap + for _, value := range validateCmdOnlineEntitiesFilter { + // Check if the value is valid by comparing it with keys in EntityMap + if _, exists := validate.EntityMap[value]; !exists { + // Generate an error message with the list of valid keys + listOfKeys := make([]string, 0, len(validate.EntityMap)) + for key := range validate.EntityMap { + listOfKeys = append(listOfKeys, key) + } + // Sort the keys alphabetically + sort.Strings(listOfKeys) + + return fmt.Errorf( + "invalid value '%s' for --check-online-plugins-only; it should be a valid Kong entity. "+ + "Valid entities: %v", + value, listOfKeys, + ) + } + } return preRunSilenceEventsFlag() } @@ -238,8 +259,8 @@ this command unless --online flag is used. validateCmd.Flags().BoolVar(&validateCmdRBACResourcesOnly, "rbac-resources-only", false, "indicate that the state file(s) contains RBAC resources only (Kong Enterprise only).") - validateCmd.Flags().BoolVar(&validateCmdCheckOnlinePluginsOnly, "check-online-plugins-only", - false, "indicate that the online validation will be done only on plugins.") + validateCmd.Flags().StringSliceVarP(&validateCmdOnlineEntitiesFilter, "online-entities-list", + "", []string{}, "indicate the list of entitied that should be validate online validation.") if deprecated { validateCmd.Flags().StringSliceVarP(&validateCmdKongStateFile, "state", "s", []string{"kong.yaml"}, "file(s) containing Kong's configuration.\n"+ @@ -282,12 +303,12 @@ func validateWithKong( return []error{fmt.Errorf("parsing Kong version: %w", err)} } opts := validate.ValidatorOpts{ - Ctx: ctx, - State: ks, - Client: kongClient, - Parallelism: validateParallelism, - RBACResourcesOnly: validateCmdRBACResourcesOnly, - CheckOnlinePluginsOnly: validateCmdCheckOnlinePluginsOnly, + Ctx: ctx, + State: ks, + Client: kongClient, + Parallelism: validateParallelism, + RBACResourcesOnly: validateCmdRBACResourcesOnly, + OnlineEntitiesFilter: validateCmdOnlineEntitiesFilter, } validator := validate.NewValidator(opts) return validator.Validate(parsedFormatVersion) diff --git a/go.mod b/go.mod index 3db19f98e..4df4ce063 100644 --- a/go.mod +++ b/go.mod @@ -12,14 +12,14 @@ require ( github.com/daveshanley/vacuum v0.9.15 github.com/fatih/color v1.17.0 github.com/google/go-cmp v0.6.0 - github.com/kong/go-apiops v0.1.39 + github.com/kong/go-apiops v0.1.40 github.com/kong/go-database-reconciler v1.16.1 github.com/kong/go-kong v0.60.0 github.com/mitchellh/go-homedir v1.1.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 golang.org/x/sync v0.8.0 k8s.io/api v0.31.2 k8s.io/apiextensions-apiserver v0.31.2 @@ -189,8 +189,8 @@ require ( golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.30.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/term v0.25.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect golang.org/x/text v0.19.0 // indirect golang.org/x/tools v0.26.0 // indirect google.golang.org/protobuf v1.34.2 // indirect diff --git a/go.sum b/go.sum index 11ad319b8..dc7be4dfe 100644 --- a/go.sum +++ b/go.sum @@ -245,8 +245,8 @@ github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuOb github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kong/go-apiops v0.1.39 h1:OXUzHb6tyZ+bb1xWzpPvmZK7FNk4xtrcka8d0bRTQkI= -github.com/kong/go-apiops v0.1.39/go.mod h1:WghIt61r2b+HaeGVNWCd+aswTMHIjeP3GYK09/yYWA8= +github.com/kong/go-apiops v0.1.40 h1:Dp4IHJ3h61VeOAeQkOisf1BcOP+Ww+gpqnv14HvC6DQ= +github.com/kong/go-apiops v0.1.40/go.mod h1:CNfsa9mHFRfAhT9E2IWTul0Mi1/BldTDmFu5fWcp2us= github.com/kong/go-database-reconciler v1.16.1 h1:qcQzEuMGfpNjx3UgulBOKulKA+upmHwqw4dy6TMEV7A= github.com/kong/go-database-reconciler v1.16.1/go.mod h1:7CGvStUvUOmUnodUFsWcW3PX2bJgnaKClJ/yhNGEVIE= github.com/kong/go-kong v0.60.0 h1:CVrLXRLVE+Gl4IZ3tdvpO7xNDz3c9YLTmra/HvT4oM8= @@ -325,8 +325,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= @@ -419,8 +419,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= @@ -566,16 +567,16 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/tests/integration/sync_test.go b/tests/integration/sync_test.go index 746de8f0e..ca5e084ad 100644 --- a/tests/integration/sync_test.go +++ b/tests/integration/sync_test.go @@ -1397,6 +1397,7 @@ var ( ID: kong.String("77e6691d-67c0-446a-9401-27be2b141aae"), }, Config: kong.Configuration{ + "compound_identifier": nil, "consumer_groups": nil, "dictionary_name": string("kong_rate_limiting_counters"), "disable_penalty": bool(false), @@ -1447,6 +1448,7 @@ var ( ID: kong.String("5bcbd3a7-030b-4310-bd1d-2721ff85d236"), }, Config: kong.Configuration{ + "compound_identifier": nil, "consumer_groups": nil, "dictionary_name": string("kong_rate_limiting_counters"), "disable_penalty": bool(false), @@ -1494,6 +1496,7 @@ var ( { Name: kong.String("rate-limiting-advanced"), Config: kong.Configuration{ + "compound_identifier": nil, "consumer_groups": nil, "dictionary_name": string("kong_rate_limiting_counters"), "disable_penalty": bool(false), diff --git a/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip_konnect.yaml b/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip_konnect.yaml index aea340bc6..b99f56505 100644 --- a/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip_konnect.yaml +++ b/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip_konnect.yaml @@ -5,6 +5,7 @@ consumer_groups: - name: basic plugins: - config: + compound_identifier: null consumer_groups: null dictionary_name: kong_rate_limiting_counters disable_penalty: false diff --git a/tests/integration/validate_test.go b/tests/integration/validate_test.go index 6b2468137..03051e040 100644 --- a/tests/integration/validate_test.go +++ b/tests/integration/validate_test.go @@ -76,6 +76,22 @@ func Test_Validate_Konnect(t *testing.T) { additionalArgs: []string{"--konnect-runtime-group-name=default"}, errorExpected: false, }, + { + name: "validate with wrong online list, passed via --online-entities-list cli flag", + stateFile: "testdata/validate/kong3x.yaml", + additionalArgs: []string{"--online-entities-list=services,Routes,Plugins"}, + errorExpected: true, + errorString: "invalid value 'services' for --check-online-plugins-only; it should be a valid " + + "Kong entity. Valid entities: [ACLGroups BasicAuths CACertificates Certificates Consumers Documents " + + "FilterChains HMACAuths JWTAuths KeyAuths Oauth2Creds Plugins RBACEndpointPermissions RBACRoles Routes " + + "SNIs Services Targets Upstreams Vaults]", + }, + { + name: "validate with correct online list, passed via --online-entities-list cli flag", + stateFile: "testdata/validate/kong3x.yaml", + additionalArgs: []string{"--online-entities-list=Services,Routes,Plugins"}, + errorExpected: false, + }, } for _, tc := range tests { @@ -134,9 +150,9 @@ func Test_Validate_File(t *testing.T) { additionalArgs: []string{"--rbac-resources-only"}, }, { - name: "file validate with --check-online-plugins-only", + name: "file validate with --online-entities-list", stateFile: "testdata/validate/kong3x.yaml", - additionalArgs: []string{"--check-online-plugins-only"}, + additionalArgs: []string{"--online-entities-list=Services,Routes,Plugins"}, }, } diff --git a/validate/validate.go b/validate/validate.go index baeb572a6..2372b8cac 100644 --- a/validate/validate.go +++ b/validate/validate.go @@ -16,31 +16,55 @@ import ( ) type Validator struct { - ctx context.Context - state *state.KongState - client *kong.Client - parallelism int - rbacResourcesOnly bool - CheckOnlinePluginsOnly bool + ctx context.Context + state *state.KongState + client *kong.Client + parallelism int + rbacResourcesOnly bool + onlineEntitiesFilter []string } type ValidatorOpts struct { - Ctx context.Context - State *state.KongState - Client *kong.Client - Parallelism int - RBACResourcesOnly bool - CheckOnlinePluginsOnly bool + Ctx context.Context + State *state.KongState + Client *kong.Client + Parallelism int + RBACResourcesOnly bool + OnlineEntitiesFilter []string +} + +// Define a map of entity object field names and their corresponding string names +var EntityMap = map[string]string{ + "ACLGroups": "acls", + "BasicAuths": "basicauth_credentials", + "CACertificates": "ca_certificates", + "Certificates": "certificates", + "Consumers": "consumers", + "Documents": "documents", + "FilterChains": "filter_chains", + "HMACAuths": "hmacauth_credentials", + "JWTAuths": "jwt_secrets", + "KeyAuths": "keyauth_credentials", + "Oauth2Creds": "oauth2_credentials", + "Plugins": "plugins", + "RBACEndpointPermissions": "rbac-endpointpermission", + "RBACRoles": "rbac-role", + "Routes": "routes", + "SNIs": "snis", + "Services": "services", + "Targets": "targets", + "Upstreams": "upstreams", + "Vaults": "vaults", } func NewValidator(opt ValidatorOpts) *Validator { return &Validator{ - ctx: opt.Ctx, - state: opt.State, - client: opt.Client, - parallelism: opt.Parallelism, - rbacResourcesOnly: opt.RBACResourcesOnly, - CheckOnlinePluginsOnly: opt.CheckOnlinePluginsOnly, + ctx: opt.Ctx, + state: opt.State, + client: opt.Client, + parallelism: opt.Parallelism, + rbacResourcesOnly: opt.RBACResourcesOnly, + onlineEntitiesFilter: opt.OnlineEntitiesFilter, } } @@ -122,75 +146,48 @@ func (v *Validator) entities(obj interface{}, entityType string) []error { func (v *Validator) Validate(formatVersion semver.Version) []error { allErr := []error{} - // validate RBAC resources first. - if err := v.entities(v.state.RBACEndpointPermissions, "rbac-endpointpermission"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.RBACRoles, "rbac-role"); err != nil { - allErr = append(allErr, err...) - } if v.rbacResourcesOnly { + // validate RBAC resources first. + if err := v.entities(v.state.RBACEndpointPermissions, "rbac-endpointpermission"); err != nil { + allErr = append(allErr, err...) + } + if err := v.entities(v.state.RBACRoles, "rbac-role"); err != nil { + allErr = append(allErr, err...) + } return allErr } - // validate Plugins resources then. - if err := v.entities(v.state.Plugins, "plugins"); err != nil { - allErr = append(allErr, err...) - } - if v.CheckOnlinePluginsOnly { - return allErr + // Create a copy of entityMap with only the specififed resources to check online. + filteredEntityMap := make(map[string]string) + if len(v.onlineEntitiesFilter) > 0 { + for _, value := range v.onlineEntitiesFilter { + for key, entityName := range EntityMap { + if value == key { + filteredEntityMap[key] = entityName + } + } + } + } else { + // If no filter is specified, use the original entityMap. + filteredEntityMap = EntityMap } - if err := v.entities(v.state.Services, "services"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.ACLGroups, "acls"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.BasicAuths, "basicauth_credentials"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.CACertificates, "ca_certificates"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.Certificates, "certificates"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.Consumers, "consumers"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.Documents, "documents"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.HMACAuths, "hmacauth_credentials"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.JWTAuths, "jwt_secrets"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.KeyAuths, "keyauth_credentials"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.Oauth2Creds, "oauth2_credentials"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.Routes, "routes"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.SNIs, "snis"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.Targets, "targets"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.Upstreams, "upstreams"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.FilterChains, "filter_chains"); err != nil { - allErr = append(allErr, err...) - } - if err := v.entities(v.state.Vaults, "vaults"); err != nil { - allErr = append(allErr, err...) + // Validate each entity using the filtered entityMap + for fieldName, entityName := range filteredEntityMap { + // Use reflection to get the value of the field from v.state + valueOfState := reflect.ValueOf(v.state) + if valueOfState.Kind() == reflect.Ptr { + valueOfState = valueOfState.Elem() // Dereference if it's a pointer + } + + fieldValue := valueOfState.FieldByName(fieldName) + if fieldValue.IsValid() && fieldValue.CanInterface() { + if err := v.entities(fieldValue.Interface(), entityName); err != nil { + allErr = append(allErr, err...) + } + } else { + allErr = append(allErr, fmt.Errorf("invalid field '%s' in state", fieldName)) + } } // validate routes format with Kong 3.x