mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
commit
e499188948
7 changed files with 444 additions and 103 deletions
|
@ -1,11 +1,9 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
|
||||
|
@ -37,7 +35,7 @@ func Generate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVers
|
|||
continue
|
||||
}
|
||||
|
||||
ok, err := mutation.ResourceMeetsRules(rawResource, rule.ResourceDescription, gvk)
|
||||
ok, err := 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
|
||||
|
@ -62,17 +60,12 @@ func Generate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVers
|
|||
// Applies "configMapGenerator" and "secretGenerator" described in PolicyRule
|
||||
// TODO: plan to support all kinds of generator
|
||||
func applyRuleGenerator(rawResource []byte, generator *kubepolicy.Generation) ([]GenerationResponse, error) {
|
||||
var generateResps []GenerationResponse
|
||||
var generationResponse []GenerationResponse
|
||||
if generator == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
err := generator.Validate()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Generator for '%s' is invalid: %s", generator.Kind, err)
|
||||
}
|
||||
|
||||
namespaceName := mutation.ParseNameFromObject(rawResource)
|
||||
generateResps = append(generateResps, GenerationResponse{generator, namespaceName})
|
||||
return generateResps, nil
|
||||
namespaceName := ParseNameFromObject(rawResource)
|
||||
generationResponse = append(generationResponse, GenerationResponse{generator, namespaceName})
|
||||
return generationResponse, nil
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
|
|||
continue
|
||||
}
|
||||
|
||||
ok, err := mutation.ResourceMeetsRules(rawResource, rule.ResourceDescription, gvk)
|
||||
ok, err := 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
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package mutation
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func assertEqDataImpl(t *testing.T, expected, actual []byte, formatModifier string) {
|
||||
if len(expected) != len(actual) {
|
||||
t.Errorf("len(expected) != len(actual): %d != %d\n1:"+formatModifier+"\n2:"+formatModifier, len(expected), len(actual), expected, actual)
|
||||
return
|
||||
}
|
||||
|
||||
for idx, val := range actual {
|
||||
if val != expected[idx] {
|
||||
t.Errorf("Slices not equal at index %d:\n1:"+formatModifier+"\n2:"+formatModifier, idx, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertEqData(t *testing.T, expected, actual []byte) {
|
||||
assertEqDataImpl(t, expected, actual, "%x")
|
||||
}
|
||||
|
||||
func assertEqStringAndData(t *testing.T, str string, data []byte) {
|
||||
assertEqDataImpl(t, []byte(str), data, "%s")
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package mutation
|
||||
package engine
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -6,10 +6,46 @@ import (
|
|||
|
||||
"github.com/minio/minio/pkg/wildcard"
|
||||
kubepolicy "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
// ResourceMeetsRules checks requests kind, name and labels to fit the policy
|
||||
func ResourceMeetsRules(resourceRaw []byte, description kubepolicy.ResourceDescription, gvk metav1.GroupVersionKind) (bool, error) {
|
||||
if description.Kind != gvk.Kind {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if resourceRaw != nil {
|
||||
meta := ParseMetadataFromObject(resourceRaw)
|
||||
name := ParseNameFromObject(resourceRaw)
|
||||
|
||||
if description.Name != nil {
|
||||
|
||||
if !wildcard.Match(*description.Name, name) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
if description.Selector != nil {
|
||||
selector, err := metav1.LabelSelectorAsSelector(description.Selector)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
labelMap := ParseLabelsFromMetadata(meta)
|
||||
|
||||
if !selector.Matches(labelMap) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func ParseMetadataFromObject(bytes []byte) map[string]interface{} {
|
||||
var objectJSON map[string]interface{}
|
||||
json.Unmarshal(bytes, &objectJSON)
|
||||
|
@ -68,38 +104,3 @@ func ParseRegexPolicyResourceName(policyResourceName string) (string, bool) {
|
|||
}
|
||||
return strings.Trim(regex[1], " "), true
|
||||
}
|
||||
|
||||
// ResourceMeetsRules checks requests kind, name and labels to fit the policy
|
||||
func ResourceMeetsRules(resourceRaw []byte, description kubepolicy.ResourceDescription, gvk metav1.GroupVersionKind) (bool, error) {
|
||||
if description.Kind != gvk.Kind {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if resourceRaw != nil {
|
||||
meta := ParseMetadataFromObject(resourceRaw)
|
||||
name := ParseNameFromObject(resourceRaw)
|
||||
|
||||
if description.Name != nil {
|
||||
|
||||
if !wildcard.Match(*description.Name, name) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
if description.Selector != nil {
|
||||
selector, err := metav1.LabelSelectorAsSelector(description.Selector)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
labelMap := ParseLabelsFromMetadata(meta)
|
||||
|
||||
if !selector.Matches(labelMap) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
|
@ -5,11 +5,14 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/minio/minio/pkg/wildcard"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// Validate handles validating admission request
|
||||
// Checks the target resourse for rules defined in the policy
|
||||
func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) bool {
|
||||
var resource interface{}
|
||||
json.Unmarshal(rawResource, &resource)
|
||||
|
@ -28,7 +31,7 @@ func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVers
|
|||
continue
|
||||
}
|
||||
|
||||
ok, err := mutation.ResourceMeetsRules(rawResource, rule.ResourceDescription, gvk)
|
||||
ok, err := 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
|
||||
|
@ -43,60 +46,196 @@ func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVers
|
|||
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)
|
||||
if !validateMap(resource, rule.Validation.Pattern) {
|
||||
log.Printf("Validation with the rule %s has failed: %s\n", rule.Name, *rule.Validation.Message)
|
||||
allowed = false
|
||||
} else {
|
||||
log.Printf("Validation rule %s is successful %s: %s\n", rule.Name, err.Error(), *rule.Validation.Message)
|
||||
log.Printf("Validation rule %s is successful\n", rule.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return allowed
|
||||
}
|
||||
|
||||
func traverseAndValidate(resourcePart, patternPart interface{}) error {
|
||||
func validateMap(resourcePart, patternPart interface{}) bool {
|
||||
pattern := patternPart.(map[string]interface{})
|
||||
resource, ok := resourcePart.(map[string]interface{})
|
||||
|
||||
if !ok {
|
||||
fmt.Printf("Validating error: expected Map, found %T\n", resourcePart)
|
||||
return false
|
||||
}
|
||||
|
||||
for key, value := range pattern {
|
||||
if wrappedWithParentheses(key) {
|
||||
key = key[1 : len(key)-1]
|
||||
}
|
||||
|
||||
if !validateMapElement(resource[key], value) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func validateArray(resourcePart, patternPart interface{}) bool {
|
||||
patternArray := patternPart.([]interface{})
|
||||
resourceArray, ok := resourcePart.([]interface{})
|
||||
|
||||
if !ok {
|
||||
fmt.Printf("Validating error: expected array, found %T\n", resourcePart)
|
||||
return false
|
||||
}
|
||||
|
||||
switch pattern := patternArray[0].(type) {
|
||||
case map[string]interface{}:
|
||||
anchors, err := getAnchorsFromMap(pattern)
|
||||
if err != nil {
|
||||
fmt.Printf("Validating error: %v\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
for _, value := range resourceArray {
|
||||
resource, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
fmt.Printf("Validating error: expected Map, found %T\n", resourcePart)
|
||||
return false
|
||||
}
|
||||
|
||||
if skipArrayObject(resource, anchors) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !validateMap(resource, pattern) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
default:
|
||||
for _, value := range resourceArray {
|
||||
if !checkSingleValue(value, patternArray[0]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func validateMapElement(resourcePart, patternPart interface{}) bool {
|
||||
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)
|
||||
fmt.Printf("Validating error: expected %T, found %T\n", patternPart, resourcePart)
|
||||
return false
|
||||
}
|
||||
|
||||
var err error
|
||||
for key, value := range pattern {
|
||||
err = traverseAndValidate(dictionary[key], value)
|
||||
}
|
||||
return err
|
||||
|
||||
return validateMap(dictionary, pattern)
|
||||
case []interface{}:
|
||||
array, ok := resourcePart.([]interface{})
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("Validating error: expected %T, found %T", patternPart, resourcePart)
|
||||
fmt.Printf("Validating error: expected %T, found %T\n", patternPart, resourcePart)
|
||||
return false
|
||||
}
|
||||
|
||||
var err error
|
||||
for i, value := range pattern {
|
||||
err = traverseAndValidate(array[i], value)
|
||||
}
|
||||
return err
|
||||
return validateArray(array, pattern)
|
||||
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)
|
||||
str, ok := resourcePart.(string)
|
||||
|
||||
if !ok {
|
||||
fmt.Printf("Validating error: expected %T, found %T\n", patternPart, resourcePart)
|
||||
return false
|
||||
}
|
||||
|
||||
return nil
|
||||
return checkSingleValue(str, pattern)
|
||||
default:
|
||||
fmt.Printf("Validating error: unknown type in map: %T\n", patternPart)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func getAnchorsFromMap(pattern map[string]interface{}) (map[string]interface{}, error) {
|
||||
result := make(map[string]interface{})
|
||||
|
||||
for key, value := range pattern {
|
||||
if wrappedWithParentheses(key) {
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func skipArrayObject(object, anchors map[string]interface{}) bool {
|
||||
for key, pattern := range anchors {
|
||||
key = key[1 : len(key)-1]
|
||||
|
||||
value, ok := object[key]
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
||||
if !checkSingleValue(value, pattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkSingleValue(value, pattern interface{}) bool {
|
||||
switch typedPattern := pattern.(type) {
|
||||
case string:
|
||||
switch typedValue := value.(type) {
|
||||
case string:
|
||||
return checkForWildcard(typedValue, typedPattern)
|
||||
case float64:
|
||||
return checkForOperator(typedValue, typedPattern)
|
||||
case int:
|
||||
return checkForOperator(float64(typedValue), typedPattern)
|
||||
default:
|
||||
fmt.Printf("Validating error: expected string or numerical type, found %T, pattern: %s\n", value, typedPattern)
|
||||
return false
|
||||
}
|
||||
case float64:
|
||||
num, ok := value.(float64)
|
||||
if !ok {
|
||||
fmt.Printf("Validating error: expected float, found %T\n", value)
|
||||
return false
|
||||
}
|
||||
|
||||
return typedPattern == num
|
||||
case int:
|
||||
num, ok := value.(int)
|
||||
if !ok {
|
||||
fmt.Printf("Validating error: expected int, found %T\n", value)
|
||||
return false
|
||||
}
|
||||
|
||||
return typedPattern == num
|
||||
default:
|
||||
fmt.Printf("Validating error: expected pattern (string or numerical type), found %T\n", pattern)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func checkForWildcard(value, pattern string) bool {
|
||||
return value == pattern
|
||||
return wildcard.Match(pattern, value)
|
||||
}
|
||||
|
||||
func checkForOperator(value int, pattern string) bool {
|
||||
func checkForOperator(value float64, pattern string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func wrappedWithParentheses(str string) bool {
|
||||
if len(str) < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
return (str[0] == '(' && str[len(str)-1] == ')')
|
||||
}
|
||||
|
|
234
pkg/engine/validation_test.go
Normal file
234
pkg/engine/validation_test.go
Normal file
|
@ -0,0 +1,234 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func TestWrappedWithParentheses_StringIsWrappedWithParentheses(t *testing.T) {
|
||||
str := "(something)"
|
||||
assert.Assert(t, wrappedWithParentheses(str))
|
||||
}
|
||||
|
||||
func TestWrappedWithParentheses_StringHasOnlyParentheses(t *testing.T) {
|
||||
str := "()"
|
||||
assert.Assert(t, wrappedWithParentheses(str))
|
||||
}
|
||||
|
||||
func TestWrappedWithParentheses_StringHasNoParentheses(t *testing.T) {
|
||||
str := "something"
|
||||
assert.Assert(t, !wrappedWithParentheses(str))
|
||||
}
|
||||
|
||||
func TestWrappedWithParentheses_StringHasLeftParentheses(t *testing.T) {
|
||||
str := "(something"
|
||||
assert.Assert(t, !wrappedWithParentheses(str))
|
||||
}
|
||||
|
||||
func TestWrappedWithParentheses_StringHasRightParentheses(t *testing.T) {
|
||||
str := "something)"
|
||||
assert.Assert(t, !wrappedWithParentheses(str))
|
||||
}
|
||||
|
||||
func TestWrappedWithParentheses_StringParenthesesInside(t *testing.T) {
|
||||
str := "so)m(et(hin)g"
|
||||
assert.Assert(t, !wrappedWithParentheses(str))
|
||||
}
|
||||
|
||||
func TestWrappedWithParentheses_Empty(t *testing.T) {
|
||||
str := ""
|
||||
assert.Assert(t, !wrappedWithParentheses(str))
|
||||
}
|
||||
|
||||
func TestCheckForWildcard_AsteriskTest(t *testing.T) {
|
||||
pattern := "*"
|
||||
value := "anything"
|
||||
empty := ""
|
||||
|
||||
assert.Assert(t, checkForWildcard(value, pattern))
|
||||
assert.Assert(t, checkForWildcard(empty, pattern))
|
||||
}
|
||||
|
||||
func TestCheckForWildcard_LeftAsteriskTest(t *testing.T) {
|
||||
pattern := "*right"
|
||||
value := "leftright"
|
||||
right := "right"
|
||||
|
||||
assert.Assert(t, checkForWildcard(value, pattern))
|
||||
assert.Assert(t, checkForWildcard(right, pattern))
|
||||
|
||||
value = "leftmiddle"
|
||||
middle := "middle"
|
||||
|
||||
assert.Assert(t, !checkForWildcard(value, pattern))
|
||||
assert.Assert(t, !checkForWildcard(middle, pattern))
|
||||
}
|
||||
|
||||
func TestCheckForWildcard_MiddleAsteriskTest(t *testing.T) {
|
||||
pattern := "ab*ba"
|
||||
value := "abbba"
|
||||
assert.Assert(t, checkForWildcard(value, pattern))
|
||||
|
||||
value = "abbca"
|
||||
assert.Assert(t, !checkForWildcard(value, pattern))
|
||||
}
|
||||
|
||||
func TestCheckForWildcard_QuestionMark(t *testing.T) {
|
||||
pattern := "ab?ba"
|
||||
value := "abbba"
|
||||
assert.Assert(t, checkForWildcard(value, pattern))
|
||||
|
||||
value = "abbbba"
|
||||
assert.Assert(t, !checkForWildcard(value, pattern))
|
||||
}
|
||||
|
||||
func TestCheckSingleValue_CheckInt(t *testing.T) {
|
||||
pattern := 89
|
||||
value := 89
|
||||
assert.Assert(t, checkSingleValue(value, pattern))
|
||||
|
||||
value = 202
|
||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
||||
}
|
||||
|
||||
func TestCheckSingleValue_CheckFloat(t *testing.T) {
|
||||
pattern := 89.9091
|
||||
value := 89.9091
|
||||
assert.Assert(t, checkSingleValue(value, pattern))
|
||||
|
||||
value = 89.9092
|
||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
||||
}
|
||||
|
||||
func TestCheckSingleValue_CheckOperatorMore(t *testing.T) {
|
||||
pattern := ">10"
|
||||
value := 89
|
||||
assert.Assert(t, checkSingleValue(value, pattern))
|
||||
|
||||
pattern = ">10"
|
||||
floatValue := 89.901
|
||||
assert.Assert(t, checkSingleValue(floatValue, pattern))
|
||||
}
|
||||
|
||||
func TestCheckSingleValue_CheckWildcard(t *testing.T) {
|
||||
pattern := "nirmata_*"
|
||||
value := "nirmata_awesome"
|
||||
assert.Assert(t, checkSingleValue(value, pattern))
|
||||
|
||||
pattern = "nirmata_*"
|
||||
value = "spasex_awesome"
|
||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
||||
|
||||
pattern = "g?t"
|
||||
value = "git"
|
||||
assert.Assert(t, checkSingleValue(value, pattern))
|
||||
}
|
||||
|
||||
func TestSkipArrayObject_OneAnchor(t *testing.T) {
|
||||
|
||||
rawAnchors := []byte(`{"(name)": "nirmata-*"}`)
|
||||
rawResource := []byte(`{"name": "nirmata-resource", "namespace": "kube-policy", "object": { "label": "app", "array": [ 1, 2, 3 ]}}`)
|
||||
|
||||
var resource, anchor map[string]interface{}
|
||||
|
||||
json.Unmarshal(rawAnchors, &anchor)
|
||||
json.Unmarshal(rawResource, &resource)
|
||||
|
||||
assert.Assert(t, !skipArrayObject(resource, anchor))
|
||||
}
|
||||
|
||||
func TestSkipArrayObject_OneNumberAnchorPass(t *testing.T) {
|
||||
|
||||
rawAnchors := []byte(`{"(count)": 1}`)
|
||||
rawResource := []byte(`{"name": "nirmata-resource", "count": 1, "namespace": "kube-policy", "object": { "label": "app", "array": [ 1, 2, 3 ]}}`)
|
||||
|
||||
var resource, anchor map[string]interface{}
|
||||
|
||||
json.Unmarshal(rawAnchors, &anchor)
|
||||
json.Unmarshal(rawResource, &resource)
|
||||
|
||||
assert.Assert(t, !skipArrayObject(resource, anchor))
|
||||
}
|
||||
|
||||
func TestSkipArrayObject_TwoAnchorsPass(t *testing.T) {
|
||||
rawAnchors := []byte(`{"(name)": "nirmata-*", "(namespace)": "kube-?olicy"}`)
|
||||
rawResource := []byte(`{"name": "nirmata-resource", "namespace": "kube-policy", "object": { "label": "app", "array": [ 1, 2, 3 ]}}`)
|
||||
|
||||
var resource, anchor map[string]interface{}
|
||||
|
||||
json.Unmarshal(rawAnchors, &anchor)
|
||||
json.Unmarshal(rawResource, &resource)
|
||||
|
||||
assert.Assert(t, !skipArrayObject(resource, anchor))
|
||||
}
|
||||
|
||||
func TestSkipArrayObject_TwoAnchorsSkip(t *testing.T) {
|
||||
rawAnchors := []byte(`{"(name)": "nirmata-*", "(namespace)": "some-?olicy"}`)
|
||||
rawResource := []byte(`{"name": "nirmata-resource", "namespace": "kube-policy", "object": { "label": "app", "array": [ 1, 2, 3 ]}}`)
|
||||
|
||||
var resource, anchor map[string]interface{}
|
||||
|
||||
json.Unmarshal(rawAnchors, &anchor)
|
||||
json.Unmarshal(rawResource, &resource)
|
||||
|
||||
assert.Assert(t, skipArrayObject(resource, anchor))
|
||||
}
|
||||
|
||||
func TestGetAnchorsFromMap_ThereAreAnchors(t *testing.T) {
|
||||
rawMap := []byte(`{"(name)": "nirmata-*", "notAnchor1": 123, "(namespace)": "kube-?olicy", "notAnchor2": "sample-text", "object": { "key1": "value1", "(key2)": "value2"}}`)
|
||||
|
||||
var unmarshalled map[string]interface{}
|
||||
json.Unmarshal(rawMap, &unmarshalled)
|
||||
|
||||
actualMap, err := getAnchorsFromMap(unmarshalled)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, len(actualMap), 2)
|
||||
assert.Equal(t, actualMap["(name)"].(string), "nirmata-*")
|
||||
assert.Equal(t, actualMap["(namespace)"].(string), "kube-?olicy")
|
||||
}
|
||||
|
||||
func TestGetAnchorsFromMap_ThereAreNoAnchors(t *testing.T) {
|
||||
rawMap := []byte(`{"name": "nirmata-*", "notAnchor1": 123, "namespace": "kube-?olicy", "notAnchor2": "sample-text", "object": { "key1": "value1", "(key2)": "value2"}}`)
|
||||
|
||||
var unmarshalled map[string]interface{}
|
||||
json.Unmarshal(rawMap, &unmarshalled)
|
||||
|
||||
actualMap, err := getAnchorsFromMap(unmarshalled)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, len(actualMap) == 0)
|
||||
}
|
||||
|
||||
func TestValidateMapElement_TwoElementsInArrayOnePass(t *testing.T) {
|
||||
rawPattern := []byte(`[ { "(name)": "nirmata-*", "object": [ { "(key1)": "value*", "key2": "value*" } ] } ]`)
|
||||
rawMap := []byte(`[ { "name": "nirmata-1", "object": [ { "key1": "value1", "key2": "value2" } ] }, { "name": "nirmata-1", "object": [ { "key1": "not_value", "key2": "not_value" } ] } ]`)
|
||||
|
||||
var pattern, resource interface{}
|
||||
json.Unmarshal(rawPattern, &pattern)
|
||||
json.Unmarshal(rawMap, &resource)
|
||||
|
||||
assert.Assert(t, validateMapElement(resource, pattern))
|
||||
}
|
||||
|
||||
func TestValidateMapElement_OneElementInArrayPass(t *testing.T) {
|
||||
rawPattern := []byte(`[ { "(name)": "nirmata-*", "object": [ { "(key1)": "value*", "key2": "value*" } ] } ]`)
|
||||
rawMap := []byte(`[ { "name": "nirmata-1", "object": [ { "key1": "value1", "key2": "value2" } ] } ]`)
|
||||
|
||||
var pattern, resource interface{}
|
||||
json.Unmarshal(rawPattern, &pattern)
|
||||
json.Unmarshal(rawMap, &resource)
|
||||
|
||||
assert.Assert(t, validateMapElement(resource, pattern))
|
||||
}
|
||||
|
||||
func TestValidateMapElement_OneElementInArrayNotPass(t *testing.T) {
|
||||
rawPattern := []byte(`[{"(name)": "nirmata-*", "object":[{"(key1)": "value*", "key2": "value*"}]}]`)
|
||||
rawMap := []byte(`[ { "name": "nirmata-1", "object": [ { "key1": "value5", "key2": "1value1" } ] } ]`)
|
||||
|
||||
var pattern, resource interface{}
|
||||
json.Unmarshal(rawPattern, &pattern)
|
||||
json.Unmarshal(rawMap, &resource)
|
||||
|
||||
assert.Assert(t, !validateMapElement(resource, pattern))
|
||||
}
|
|
@ -147,8 +147,8 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
|
|||
allPatches = append(allPatches, policyPatches...)
|
||||
|
||||
if len(policyPatches) > 0 {
|
||||
namespace := mutation.ParseNamespaceFromObject(request.Object.Raw)
|
||||
name := mutation.ParseNameFromObject(request.Object.Raw)
|
||||
namespace := engine.ParseNamespaceFromObject(request.Object.Raw)
|
||||
name := engine.ParseNameFromObject(request.Object.Raw)
|
||||
ws.logger.Printf("Policy %s applied to %s %s/%s", policy.Name, request.Kind.Kind, namespace, name)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue