diff --git a/pkg/openapi/validation.go b/pkg/openapi/validation.go index 71b8fa4b43..204bb50cfc 100644 --- a/pkg/openapi/validation.go +++ b/pkg/openapi/validation.go @@ -1,11 +1,15 @@ package openapi import ( + "encoding/json" + "errors" "fmt" "strconv" "strings" "sync" + "github.com/nirmata/kyverno/pkg/engine/utils" + "github.com/nirmata/kyverno/data" "github.com/golang/glog" @@ -44,10 +48,29 @@ func init() { } } -func ValidatePolicyMutation(policy v1.ClusterPolicy) error { +func ValidatePolicyFields(policy v1.ClusterPolicy) error { openApiGlobalState.mutex.RLock() defer openApiGlobalState.mutex.RUnlock() + policyRaw, err := json.Marshal(policy) + if err != nil { + return err + } + + policyUnst, err := utils.ConvertToUnstructured(policyRaw) + if err != nil { + return err + } + + err = ValidateResource(*policyUnst.DeepCopy(), "ClusterPolicy") + if err != nil { + return err + } + + return validatePolicyMutation(policy) +} + +func validatePolicyMutation(policy v1.ClusterPolicy) error { var kindToRules = make(map[string][]v1.Rule) for _, rule := range policy.Spec.Rules { if rule.HasMutate() { @@ -156,8 +179,17 @@ func getSchemaDocument() (*openapi_v2.Document, error) { // For crd, we do not store definition in document func getSchemaFromDefinitions(kind string) (proto.Schema, error) { + if kind == "" { + return nil, errors.New("invalid kind") + } + path := proto.NewPath(kind) - return (&proto.Definitions{}).ParseSchema(openApiGlobalState.definitions[kind], &path) + definition := openApiGlobalState.definitions[kind] + if definition == nil { + return nil, errors.New("could not find definition") + } + + return (&proto.Definitions{}).ParseSchema(definition, &path) } func generateEmptyResource(kindSchema *openapi_v2.Schema) interface{} { diff --git a/pkg/openapi/validation_test.go b/pkg/openapi/validation_test.go index 813c2ed15b..4c245b7100 100644 --- a/pkg/openapi/validation_test.go +++ b/pkg/openapi/validation_test.go @@ -52,7 +52,37 @@ func Test_ValidateMutationPolicy(t *testing.T) { _ = json.Unmarshal(tc.policy, &policy) var errMessage string - err := ValidatePolicyMutation(policy) + err := validatePolicyMutation(policy) + if err != nil { + errMessage = err.Error() + } + + if errMessage != tc.errMessage { + t.Errorf("\nTestcase [%v] failed:\nExpected Error: %v\nGot Error: %v", i+1, tc.errMessage, errMessage) + } + } + +} + +func Test_ValidatePolicyFields(t *testing.T) { + + tcs := []struct { + description string + policy []byte + errMessage string + }{ + { + description: "Dealing with invalid fields in the policy", + policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"disallow-root-user"},"validationFailureAction":"enforce","spec":{"background":false,"rules":[{"name":"validate-runAsNonRoot","match":{"resources":{"kinds":["Pod"]}},"exclude":{"resources":{"kinds":["Pod"]}},"validate":{"message":"Running as root user is not allowed. Set runAsNonRoot to true","anyPattern":[{"spec":{"securityContext":{"runAsNonRoot":true}}},{"spec":{"containers":[{"securityContext":{"runAsNonRoot":true}}]}}]}}]}}`), + }, + } + + for i, tc := range tcs { + policy := v1.ClusterPolicy{} + _ = json.Unmarshal(tc.policy, &policy) + + var errMessage string + err := ValidatePolicyFields(policy) if err != nil { errMessage = err.Error() } diff --git a/pkg/policy/validate.go b/pkg/policy/validate.go index 4789687afa..c855546622 100644 --- a/pkg/policy/validate.go +++ b/pkg/policy/validate.go @@ -82,7 +82,7 @@ func Validate(p kyverno.ClusterPolicy) error { } } - if err := openapi.ValidatePolicyMutation(p); err != nil { + if err := openapi.ValidatePolicyFields(p); err != nil { return err }