1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-15 17:51:20 +00:00
kyverno/pkg/engine/validation.go
2019-05-14 18:20:41 -07:00

102 lines
2.9 KiB
Go

package engine
import (
"encoding/json"
"fmt"
"log"
kubepolicy "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
"github.com/nirmata/kube-policy/pkg/engine/mutation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) bool {
var resource interface{}
json.Unmarshal(rawResource, &resource)
allowed := true
for i, rule := range policy.Spec.Rules {
// Checks for preconditions
// TODO: Rework PolicyEngine interface that it receives not a policy, but mutation object for
// Mutate, validation for Validate and so on. It will allow to bring this checks outside of PolicyEngine
// to common part as far as they present for all: mutation, validation, generation
err := rule.Validate()
if err != nil {
log.Printf("Rule has invalid structure: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
continue
}
ok, err := mutation.ResourceMeetsRules(rawResource, rule.ResourceDescription, gvk)
if err != nil {
log.Printf("Rule has invalid data: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
continue
}
if !ok {
log.Printf("Rule is not applicable to the request: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
continue
}
if rule.Validation == nil {
continue
}
if err := traverseAndValidate(resource, rule.Validation.Pattern); err != nil {
log.Printf("Validation with the rule %s has failed %s: %s\n", rule.Name, err.Error(), *rule.Validation.Message)
allowed = false
} else {
log.Printf("Validation rule %s is successful %s: %s\n", rule.Name, err.Error(), *rule.Validation.Message)
}
}
return allowed
}
func traverseAndValidate(resourcePart, patternPart interface{}) error {
switch pattern := patternPart.(type) {
case map[string]interface{}:
dictionary, ok := resourcePart.(map[string]interface{})
if !ok {
return fmt.Errorf("Validating error: expected %T, found %T", patternPart, resourcePart)
}
var err error
for key, value := range pattern {
err = traverseAndValidate(dictionary[key], value)
}
return err
case []interface{}:
array, ok := resourcePart.([]interface{})
if !ok {
return fmt.Errorf("Validating error: expected %T, found %T", patternPart, resourcePart)
}
var err error
for i, value := range pattern {
err = traverseAndValidate(array[i], value)
}
return err
case string:
str := resourcePart.(string)
if !checkForWildcard(str, pattern) {
return fmt.Errorf("Value %s has not passed wildcard check %s", str, pattern)
}
default:
return fmt.Errorf("Received unknown type: %T", patternPart)
}
return nil
}
func checkForWildcard(value, pattern string) bool {
return value == pattern
}
func checkForOperator(value int, pattern string) bool {
return true
}