diff --git a/backend/go.mod b/backend/go.mod index 4524f4eb..8226148f 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -8,7 +8,7 @@ require ( github.com/gin-contrib/cors v1.4.0 github.com/gin-gonic/gin v1.9.1 github.com/go-logr/logr v1.2.4 - github.com/kyverno/kyverno v1.11.0-beta.1 + github.com/kyverno/kyverno v1.5.0-rc1.0.20230921213230-3c76cf511867 github.com/loopfz/gadgeto v0.11.3 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 @@ -137,6 +137,7 @@ require ( github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-chi/chi v4.1.2+incompatible // indirect github.com/go-errors/errors v1.5.1 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-ldap/ldap/v3 v3.4.6 // indirect diff --git a/backend/go.sum b/backend/go.sum index 471b5667..ed3c4efc 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -512,6 +512,8 @@ github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxm github.com/go-critic/go-critic v0.5.6/go.mod h1:cVjj0DfqewQVIlIAGexPCaGaZDAqGE29PYDDADIVNEo= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -1039,8 +1041,8 @@ github.com/kyverno/go-jmespath v0.4.1-0.20230705123211-d067dc3d6613 h1:M0uOLuCAZ github.com/kyverno/go-jmespath v0.4.1-0.20230705123211-d067dc3d6613/go.mod h1:yzDHaKovQy16rjN4kFnjF+IdNoN4p1ndw+va6+B8zUU= github.com/kyverno/go-jmespath/internal/testify v1.5.2-0.20230630133209-945021c749d9 h1:lL311dF3a2aeNibJj8v+uhFU3XkvRHZmCtAdSPOrQYY= github.com/kyverno/go-jmespath/internal/testify v1.5.2-0.20230630133209-945021c749d9/go.mod h1:XRxUGHIiCy1WYma1CdfdO1WOhIe8dLPTENaZr5D1ex4= -github.com/kyverno/kyverno v1.11.0-beta.1 h1:pICon1vz0CwIm3YVQL185q9kW0QM09Xu2JY/vh9wKyY= -github.com/kyverno/kyverno v1.11.0-beta.1/go.mod h1:xQfQwdPstbC//8ZSLz5ttZOLFMdsuGVgI7Y45DlYzBg= +github.com/kyverno/kyverno v1.5.0-rc1.0.20230921213230-3c76cf511867 h1:ew74ekVA0WR2Ndv34CgXwYglWzQ12if/fxgxvwVMxQY= +github.com/kyverno/kyverno v1.5.0-rc1.0.20230921213230-3c76cf511867/go.mod h1:xQfQwdPstbC//8ZSLz5ttZOLFMdsuGVgI7Y45DlYzBg= github.com/ldez/gomoddirectives v0.2.1/go.mod h1:sGicqkRgBOg//JfpXwkB9Hj0X5RyJ7mlACM5B9f6Me4= github.com/ldez/tagliatelle v0.2.0/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= @@ -1394,8 +1396,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= diff --git a/backend/pkg/cluster/cm_resolver.go b/backend/pkg/cluster/cm_resolver.go index 7a1b593a..3a7c55a1 100644 --- a/backend/pkg/cluster/cm_resolver.go +++ b/backend/pkg/cluster/cm_resolver.go @@ -4,11 +4,10 @@ import ( "context" "errors" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/convert" "github.com/kyverno/kyverno/pkg/clients/dclient" engineapi "github.com/kyverno/kyverno/pkg/engine/api" corev1 "k8s.io/api/core/v1" - - "github.com/kyverno/playground/backend/pkg/resource/convert" ) type clientBasedResolver struct { diff --git a/backend/pkg/exception/load.go b/backend/pkg/exception/load.go new file mode 100644 index 00000000..f1bee6d6 --- /dev/null +++ b/backend/pkg/exception/load.go @@ -0,0 +1,39 @@ +package exception + +import ( + "fmt" + + kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1" + kyvernov2beta1 "github.com/kyverno/kyverno/api/kyverno/v2beta1" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/convert" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/loader" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + exceptionV1 = schema.GroupVersion(kyvernov2alpha1.GroupVersion).WithKind("PolicyException") + exceptionV2 = schema.GroupVersion(kyvernov2beta1.GroupVersion).WithKind("PolicyException") +) + +func Load(l loader.Loader, content []byte) ([]*kyvernov2alpha1.PolicyException, error) { + untyped, err := resource.LoadResources(l, content) + if err != nil { + return nil, err + } + var exceptions []*kyvernov2alpha1.PolicyException + for _, object := range untyped { + gvk := object.GroupVersionKind() + switch gvk { + case exceptionV1, exceptionV2: + exception, err := convert.To[kyvernov2alpha1.PolicyException](object) + if err != nil { + return nil, err + } + exceptions = append(exceptions, exception) + default: + return nil, fmt.Errorf("policy exception type not supported %s", gvk) + } + } + return exceptions, nil +} diff --git a/backend/pkg/utils/exception_test.go b/backend/pkg/exception/load_test.go similarity index 67% rename from backend/pkg/utils/exception_test.go rename to backend/pkg/exception/load_test.go index cd489494..959faca4 100644 --- a/backend/pkg/utils/exception_test.go +++ b/backend/pkg/exception/load_test.go @@ -1,18 +1,17 @@ -package utils_test +package exception import ( "os" "testing" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/loader" "github.com/stretchr/testify/require" "sigs.k8s.io/kubectl-validate/pkg/openapiclient" "github.com/kyverno/playground/backend/data" - "github.com/kyverno/playground/backend/pkg/resource/loader" - "github.com/kyverno/playground/backend/pkg/utils" ) -func Test_LoadPolicyExceptions(t *testing.T) { +func Test_Load(t *testing.T) { tests := []struct { name string policies string @@ -41,10 +40,10 @@ func Test_LoadPolicyExceptions(t *testing.T) { ), ) require.NoError(t, err) - if res, err := utils.LoadPolicyExceptions(loader, bytes); (err != nil) != tt.wantErr { - t.Errorf("loader.LoadPolicyExceptions() error = %v, wantErr %v", err, tt.wantErr) + if res, err := Load(loader, bytes); (err != nil) != tt.wantErr { + t.Errorf("Load() error = %v, wantErr %v", err, tt.wantErr) } else if len(res) != tt.wantLoaded { - t.Errorf("loader.LoadPolicyExceptions() loaded amount = %v, wantLoaded %v", len(res), tt.wantLoaded) + t.Errorf("Load() loaded amount = %v, wantLoaded %v", len(res), tt.wantLoaded) } }) } diff --git a/backend/pkg/utils/policy.go b/backend/pkg/policy/load.go similarity index 52% rename from backend/pkg/utils/policy.go rename to backend/pkg/policy/load.go index cafabcbe..b07e0a39 100644 --- a/backend/pkg/utils/policy.go +++ b/backend/pkg/policy/load.go @@ -1,15 +1,15 @@ -package utils +package policy import ( "fmt" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov2beta1 "github.com/kyverno/kyverno/api/kyverno/v2beta1" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/convert" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/loader" "k8s.io/api/admissionregistration/v1alpha1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - - "github.com/kyverno/playground/backend/pkg/resource/loader" ) var ( @@ -20,34 +20,34 @@ var ( vapV1alpha1 = v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicy") ) -func LoadPolicies(l loader.Loader, content []byte) ([]kyvernov1.PolicyInterface, []v1alpha1.ValidatingAdmissionPolicy, error) { - untyped, err := loader.LoadResources(l, content) +func Load(l loader.Loader, content []byte) ([]kyvernov1.PolicyInterface, []v1alpha1.ValidatingAdmissionPolicy, error) { + untyped, err := resource.LoadResources(l, content) if err != nil { return nil, nil, err } var policies []kyvernov1.PolicyInterface var vaps []v1alpha1.ValidatingAdmissionPolicy - for _, policy := range untyped { - gvk := policy.GroupVersionKind() + for _, object := range untyped { + gvk := object.GroupVersionKind() switch gvk { case policyV1, policyV2: - var typed kyvernov1.Policy - if err := runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(policy.UnstructuredContent(), &typed, true); err != nil { + typed, err := convert.To[kyvernov1.Policy](object) + if err != nil { return nil, nil, err } - policies = append(policies, &typed) + policies = append(policies, typed) case clusterPolicyV1, clusterPolicyV2: - var typed kyvernov1.ClusterPolicy - if err := runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(policy.UnstructuredContent(), &typed, true); err != nil { + typed, err := convert.To[kyvernov1.ClusterPolicy](object) + if err != nil { return nil, nil, err } - policies = append(policies, &typed) + policies = append(policies, typed) case vapV1alpha1: - var typed v1alpha1.ValidatingAdmissionPolicy - if err := runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(policy.UnstructuredContent(), &typed, true); err != nil { + typed, err := convert.To[v1alpha1.ValidatingAdmissionPolicy](object) + if err != nil { return nil, nil, err } - vaps = append(vaps, typed) + vaps = append(vaps, *typed) default: return nil, nil, fmt.Errorf("policy type not supported %s", gvk) } diff --git a/backend/pkg/utils/policy_test.go b/backend/pkg/policy/load_test.go similarity index 78% rename from backend/pkg/utils/policy_test.go rename to backend/pkg/policy/load_test.go index 1f9b07d5..d45b09cb 100644 --- a/backend/pkg/utils/policy_test.go +++ b/backend/pkg/policy/load_test.go @@ -1,15 +1,14 @@ -package utils_test +package policy import ( "os" "testing" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/loader" "github.com/stretchr/testify/require" "sigs.k8s.io/kubectl-validate/pkg/openapiclient" "github.com/kyverno/playground/backend/data" - "github.com/kyverno/playground/backend/pkg/resource/loader" - "github.com/kyverno/playground/backend/pkg/utils" ) const ( @@ -21,7 +20,7 @@ const ( policyAndVap string = "../../testdata/policy-and-vap.yaml" ) -func Test_LoadPolicies(t *testing.T) { +func Test_Load(t *testing.T) { tests := []struct { name string policies string @@ -76,12 +75,12 @@ func Test_LoadPolicies(t *testing.T) { ), ) require.NoError(t, err) - if policies, vaps, err := utils.LoadPolicies(loader, bytes); (err != nil) != tt.wantErr { - t.Errorf("loader.LoadPolicies() error = %v, wantErr %v", err, tt.wantErr) + if policies, vaps, err := Load(loader, bytes); (err != nil) != tt.wantErr { + t.Errorf("Load() error = %v, wantErr %v", err, tt.wantErr) } else if len(policies) != tt.wantPolicies { - t.Errorf("loader.LoadPolicies() loaded amount = %v, wantLoaded %v", len(policies), tt.wantPolicies) + t.Errorf("Load() loaded amount = %v, wantLoaded %v", len(policies), tt.wantPolicies) } else if len(vaps) != tt.wantVaps { - t.Errorf("loader.LoadPolicies() loaded amount = %v, wantLoaded %v", len(vaps), tt.wantVaps) + t.Errorf("Load() loaded amount = %v, wantLoaded %v", len(vaps), tt.wantVaps) } }) } diff --git a/backend/pkg/resource/convert/convert.go b/backend/pkg/resource/convert/convert.go deleted file mode 100644 index 876c2c76..00000000 --- a/backend/pkg/resource/convert/convert.go +++ /dev/null @@ -1,18 +0,0 @@ -package convert - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" -) - -func Into[T any](untyped unstructured.Unstructured, result *T) error { - return runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(untyped.UnstructuredContent(), result, true) -} - -func To[T any](untyped unstructured.Unstructured) (*T, error) { - var result T - if err := Into(untyped, &result); err != nil { - return nil, err - } - return &result, nil -} diff --git a/backend/pkg/resource/convert/convert_test.go b/backend/pkg/resource/convert/convert_test.go deleted file mode 100644 index 7b79a2b0..00000000 --- a/backend/pkg/resource/convert/convert_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package convert - -import ( - "os" - "testing" - - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "sigs.k8s.io/yaml" -) - -func TestTo(t *testing.T) { - { - data, err := os.ReadFile("../../../testdata/single-policy.yaml") - require.NoError(t, err) - - json, err := yaml.YAMLToJSON(data) - require.NoError(t, err) - - var untyped unstructured.Unstructured - require.NoError(t, untyped.UnmarshalJSON(json)) - - typed, err := To[corev1.ConfigMap](untyped) - require.Nil(t, typed) - require.Error(t, err) - } - { - data, err := os.ReadFile("../../../testdata/namespace.yaml") - require.NoError(t, err) - - json, err := yaml.YAMLToJSON(data) - require.NoError(t, err) - - var untyped unstructured.Unstructured - require.NoError(t, untyped.UnmarshalJSON(json)) - - typed, err := To[corev1.Namespace](untyped) - require.NotNil(t, typed) - require.NoError(t, err) - } -} diff --git a/backend/pkg/resource/loader/helpers.go b/backend/pkg/resource/loader/helpers.go deleted file mode 100644 index 5dc6400d..00000000 --- a/backend/pkg/resource/loader/helpers.go +++ /dev/null @@ -1,36 +0,0 @@ -package loader - -import ( - yamlutils "github.com/kyverno/kyverno/pkg/utils/yaml" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - - "github.com/kyverno/playground/backend/pkg/resource/convert" -) - -func Load[T any](l Loader, content []byte) (*T, error) { - untyped, err := l.Load(content) - if err != nil { - return nil, err - } - result, err := convert.To[T](untyped) - if err != nil { - return nil, err - } - return result, nil -} - -func LoadResources(l Loader, content []byte) ([]unstructured.Unstructured, error) { - documents, err := yamlutils.SplitDocuments(content) - if err != nil { - return nil, err - } - var resources []unstructured.Unstructured - for _, document := range documents { - untyped, err := l.Load(document) - if err != nil { - return nil, err - } - resources = append(resources, untyped) - } - return resources, nil -} diff --git a/backend/pkg/resource/loader/helpers_test.go b/backend/pkg/resource/loader/helpers_test.go deleted file mode 100644 index 64aa062d..00000000 --- a/backend/pkg/resource/loader/helpers_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package loader_test - -import ( - "testing" - - "sigs.k8s.io/kubectl-validate/pkg/openapiclient" - - "github.com/kyverno/playground/backend/pkg/resource/loader" -) - -const ( - singleResource string = `apiVersion: v1 -kind: Namespace -metadata: - name: prod-bus-app1 - labels: - purpose: production` - - multipleResources string = ` -apiVersion: v1 -kind: Pod -metadata: - labels: - run: nginx - name: nginx - namespace: default -spec: - containers: - - image: nginx - name: nginx - resources: {} ---- -apiVersion: v1 -kind: Pod -metadata: - labels: - run: redis - name: redis - namespace: default -spec: - containers: - - image: redis - name: redis - resources: {}` - - resourceWithComment string = ` -### POD ### ---- -apiVersion: v1 -kind: Pod -metadata: - labels: - run: nginx - name: nginx - namespace: default -spec: - containers: - - image: nginx - name: nginx - resources: {}` -) - -func Test_LoadResources(t *testing.T) { - l, err := loader.New(openapiclient.NewHardcodedBuiltins("1.27")) - if err != nil { - t.Fatal(err) - } - tests := []struct { - name string - resources string - wantLoaded int - wantErr bool - }{ - { - name: "load no resource with empy string", - resources: "", - wantLoaded: 0, - wantErr: false, - }, - { - name: "load single resource", - resources: singleResource, - wantLoaded: 1, - wantErr: false, - }, - { - name: "load multiple resources", - resources: multipleResources, - wantLoaded: 2, - wantErr: false, - }, - { - name: "load resource with comment", - resources: resourceWithComment, - wantLoaded: 1, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if res, err := loader.LoadResources(l, []byte(tt.resources)); (err != nil) != tt.wantErr { - t.Errorf("loader.Resources() error = %v, wantErr %v", err, tt.wantErr) - } else if len(res) != tt.wantLoaded { - t.Errorf("loader.Resources() loaded amount = %v, wantLoaded %v", len(res), tt.wantLoaded) - } - }) - } -} diff --git a/backend/pkg/resource/loader/loader.go b/backend/pkg/resource/loader/loader.go deleted file mode 100644 index a016036e..00000000 --- a/backend/pkg/resource/loader/loader.go +++ /dev/null @@ -1,39 +0,0 @@ -package loader - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/client-go/openapi" - "sigs.k8s.io/kubectl-validate/pkg/validator" -) - -type Loader interface { - Load([]byte) (unstructured.Unstructured, error) -} - -type loader struct { - validator *validator.Validator -} - -func New(client openapi.Client) (Loader, error) { - factory, err := validator.New(client) - if err != nil { - return nil, err - } - return &loader{ - validator: factory, - }, nil -} - -func (l *loader) Load(document []byte) (unstructured.Unstructured, error) { - _, result, err := l.validator.Parse(document) - if err != nil { - return unstructured.Unstructured{}, fmt.Errorf("failed to parse document (%w)", err) - } - // TODO: remove DeepCopy when fixed upstream - if err := l.validator.Validate(result.DeepCopy()); err != nil { - return unstructured.Unstructured{}, fmt.Errorf("failed to validate resource (%w)", err) - } - return *result, nil -} diff --git a/backend/pkg/resource/loader/loader_test.go b/backend/pkg/resource/loader/loader_test.go deleted file mode 100644 index 1d08aba8..00000000 --- a/backend/pkg/resource/loader/loader_test.go +++ /dev/null @@ -1,177 +0,0 @@ -package loader - -import ( - "errors" - "os" - "reflect" - "testing" - - "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/client-go/openapi" - "sigs.k8s.io/kubectl-validate/pkg/openapiclient" - "sigs.k8s.io/kubectl-validate/pkg/validator" - "sigs.k8s.io/yaml" - - "github.com/kyverno/playground/backend/data" -) - -type errClient struct{} - -func (errClient) Paths() (map[string]openapi.GroupVersion, error) { - return nil, errors.New("error") -} - -func TestNew(t *testing.T) { - tests := []struct { - name string - client openapi.Client - want Loader - wantErr bool - }{{ - name: "err client", - client: errClient{}, - wantErr: true, - }, { - name: "builtin", - client: openapiclient.NewHardcodedBuiltins("1.27"), - want: func() Loader { - validator, err := validator.New(openapiclient.NewHardcodedBuiltins("1.27")) - require.NoError(t, err) - return &loader{ - validator: validator, - } - }(), - }, { - name: "invalid local", - client: openapiclient.NewLocalSchemaFiles(data.Schemas(), "blam"), - want: func() Loader { - validator, err := validator.New(openapiclient.NewLocalSchemaFiles(data.Schemas(), "blam")) - require.NoError(t, err) - return &loader{ - validator: validator, - } - }(), - }, { - name: "composite - no clients", - client: openapiclient.NewComposite(), - want: func() Loader { - validator, err := validator.New(openapiclient.NewComposite()) - require.NoError(t, err) - return &loader{ - validator: validator, - } - }(), - }, { - name: "composite - err client", - client: openapiclient.NewComposite(errClient{}), - wantErr: true, - }, { - name: "composite - with err client", - client: openapiclient.NewComposite(openapiclient.NewHardcodedBuiltins("1.27"), errClient{}), - wantErr: true, - }, { - name: "composite - invalid local", - client: openapiclient.NewComposite(openapiclient.NewLocalSchemaFiles(data.Schemas(), "blam")), - want: func() Loader { - validator, err := validator.New(openapiclient.NewComposite(openapiclient.NewLocalSchemaFiles(data.Schemas(), "blam"))) - require.NoError(t, err) - return &loader{ - validator: validator, - } - }(), - }} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := New(tt.client) - if (err != nil) != tt.wantErr { - t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("New() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_loader_Load(t *testing.T) { - loadFile := func(path string) []byte { - bytes, err := os.ReadFile(path) - require.NoError(t, err) - return bytes - } - newLoader := func(client openapi.Client) Loader { - loader, err := New(client) - require.NoError(t, err) - return loader - } - toUnstructured := func(data []byte) unstructured.Unstructured { - json, err := yaml.YAMLToJSON(data) - require.NoError(t, err) - var result unstructured.Unstructured - require.NoError(t, result.UnmarshalJSON(json)) - if result.GetCreationTimestamp().Time.IsZero() { - require.NoError(t, unstructured.SetNestedField(result.UnstructuredContent(), nil, "metadata", "creationTimestamp")) - } - return result - } - tests := []struct { - name string - loader Loader - document []byte - want unstructured.Unstructured - wantErr bool - }{{ - name: "nil", - loader: newLoader(openapiclient.NewLocalSchemaFiles(data.Schemas(), "schemas")), - wantErr: true, - }, { - name: "empty GVK", - loader: newLoader(openapiclient.NewLocalSchemaFiles(data.Schemas(), "schemas")), - document: []byte(`foo: bar`), - wantErr: true, - }, { - name: "not yaml", - loader: newLoader(openapiclient.NewLocalSchemaFiles(data.Schemas(), "schemas")), - document: []byte(` - foo - bar - - baz`), - wantErr: true, - }, { - name: "unknown GVK", - loader: newLoader(openapiclient.NewLocalSchemaFiles(data.Schemas(), "schemas")), - document: loadFile("../../../testdata/namespace.yaml"), - wantErr: true, - }, { - name: "bad schema", - loader: newLoader(openapiclient.NewHardcodedBuiltins("1.27")), - document: []byte(` - apiVersion: v1 - kind: Namespace - bad: field - metadata: - name: prod-bus-app1 - labels: - purpose: production`), - wantErr: true, - }, { - name: "ok", - loader: newLoader(openapiclient.NewHardcodedBuiltins("1.27")), - document: loadFile("../../../testdata/namespace.yaml"), - want: toUnstructured(loadFile("../../../testdata/namespace.yaml")), - }} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.loader.Load(tt.document) - if (err != nil) != tt.wantErr { - t.Errorf("loader.Load() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("loader.Load() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/backend/pkg/server/api/engine/handler.go b/backend/pkg/server/api/engine/handler.go index 8b2d28b3..88241489 100644 --- a/backend/pkg/server/api/engine/handler.go +++ b/backend/pkg/server/api/engine/handler.go @@ -6,6 +6,7 @@ import ( "github.com/Masterminds/semver/v3" "github.com/gin-gonic/gin" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/loader" engineapi "github.com/kyverno/kyverno/pkg/engine/api" "github.com/loopfz/gadgeto/tonic" "sigs.k8s.io/kubectl-validate/pkg/openapiclient" @@ -13,7 +14,6 @@ import ( "github.com/kyverno/playground/backend/data" "github.com/kyverno/playground/backend/pkg/cluster" "github.com/kyverno/playground/backend/pkg/engine" - "github.com/kyverno/playground/backend/pkg/resource/loader" ) func newEngineHandler(cl cluster.Cluster, config APIConfiguration) (gin.HandlerFunc, error) { diff --git a/backend/pkg/server/api/engine/request.go b/backend/pkg/server/api/engine/request.go index d8bd06a3..4d8ebc2d 100644 --- a/backend/pkg/server/api/engine/request.go +++ b/backend/pkg/server/api/engine/request.go @@ -5,6 +5,8 @@ import ( kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/loader" "k8s.io/api/admissionregistration/v1alpha1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -15,8 +17,8 @@ import ( "github.com/kyverno/playground/backend/data" "github.com/kyverno/playground/backend/pkg/cluster" "github.com/kyverno/playground/backend/pkg/engine/models" - "github.com/kyverno/playground/backend/pkg/resource/loader" - "github.com/kyverno/playground/backend/pkg/utils" + "github.com/kyverno/playground/backend/pkg/exception" + "github.com/kyverno/playground/backend/pkg/policy" ) type EngineRequest struct { @@ -40,30 +42,30 @@ func (r *EngineRequest) LoadParameters() (*models.Parameters, error) { } func (r *EngineRequest) LoadPolicies(policyLoader loader.Loader) ([]kyvernov1.PolicyInterface, []v1alpha1.ValidatingAdmissionPolicy, error) { - return utils.LoadPolicies(policyLoader, []byte(r.Policies)) + return policy.Load(policyLoader, []byte(r.Policies)) } func (r *EngineRequest) LoadResources(resourceLoader loader.Loader) ([]unstructured.Unstructured, error) { - return loader.LoadResources(resourceLoader, []byte(r.Resources)) + return resource.LoadResources(resourceLoader, []byte(r.Resources)) } func (r *EngineRequest) LoadClusterResources(resourceLoader loader.Loader) ([]unstructured.Unstructured, error) { - return loader.LoadResources(resourceLoader, []byte(r.ClusterResources)) + return resource.LoadResources(resourceLoader, []byte(r.ClusterResources)) } func (r *EngineRequest) LoadOldResources(resourceLoader loader.Loader) ([]unstructured.Unstructured, error) { - return loader.LoadResources(resourceLoader, []byte(r.OldResources)) + return resource.LoadResources(resourceLoader, []byte(r.OldResources)) } func (r *EngineRequest) LoadPolicyExceptions(resourceLoader loader.Loader) ([]*kyvernov2alpha1.PolicyException, error) { - return utils.LoadPolicyExceptions(resourceLoader, []byte(r.PolicyExceptions)) + return exception.Load(resourceLoader, []byte(r.PolicyExceptions)) } func (r *EngineRequest) LoadConfig(resourceLoader loader.Loader) (*corev1.ConfigMap, error) { if len(r.Config) == 0 { return nil, nil } - return loader.Load[corev1.ConfigMap](resourceLoader, []byte(r.Config)) + return resource.Load[corev1.ConfigMap](resourceLoader, []byte(r.Config)) } func (r *EngineRequest) ResourceLoader(cluster cluster.Cluster, kubeVersion string, config APIConfiguration) (loader.Loader, error) { diff --git a/backend/pkg/utils/exception.go b/backend/pkg/utils/exception.go deleted file mode 100644 index 6d122b72..00000000 --- a/backend/pkg/utils/exception.go +++ /dev/null @@ -1,24 +0,0 @@ -package utils - -import ( - kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1" - - "github.com/kyverno/playground/backend/pkg/resource/convert" - "github.com/kyverno/playground/backend/pkg/resource/loader" -) - -func LoadPolicyExceptions(l loader.Loader, content []byte) ([]*kyvernov2alpha1.PolicyException, error) { - untyped, err := loader.LoadResources(l, content) - if err != nil { - return nil, err - } - var exceptions []*kyvernov2alpha1.PolicyException - for _, object := range untyped { - exception, err := convert.To[kyvernov2alpha1.PolicyException](object) - if err != nil { - return nil, err - } - exceptions = append(exceptions, exception) - } - return exceptions, nil -}