1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

fix: kyverno test doesn't fail when mutated YAML != patchedResource YAML (#8183)

* fix: kyverno test doesn't fail when mutated YAML != patchedResource YAML

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fixes

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* makefile

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

---------

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-08-30 21:37:15 +02:00 committed by GitHub
parent fb166d4f0e
commit 31bed97806
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -6,6 +6,7 @@ import (
"regexp"
"strings"
jsonpatch "github.com/evanphx/json-patch/v5"
"github.com/go-git/go-billy/v5"
"github.com/kyverno/kyverno/api/kyverno"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
@ -599,6 +600,37 @@ func isNamespacedPolicy(policyNames string) (bool, error) {
return regexp.MatchString("^[a-z]*/[a-z]*", policyNames)
}
func tidyObject(obj interface{}) interface{} {
switch typedPatternElement := obj.(type) {
case map[string]interface{}:
tidy := map[string]interface{}{}
for k, v := range typedPatternElement {
v = tidyObject(v)
if v != nil {
tidy[k] = v
}
}
if len(tidy) == 0 {
return nil
}
return tidy
case []interface{}:
var tidy []interface{}
for _, v := range typedPatternElement {
v = tidyObject(v)
if v != nil {
tidy = append(tidy, v)
}
}
if len(tidy) == 0 {
return nil
}
return tidy
default:
return obj
}
}
// getAndCompareResource --> Get the patchedResource or generatedResource from the path provided by user
// And compare this resource with engine generated resource.
func getAndCompareResource(path string, engineResource unstructured.Unstructured, isGit bool, policyResourcePath string, fs billy.Filesystem, isGenerate bool) string {
@ -607,18 +639,43 @@ func getAndCompareResource(path string, engineResource unstructured.Unstructured
if isGenerate {
resourceType = "generatedResource"
}
userResource, err := common.GetResourceFromPath(fs, path, isGit, policyResourcePath, resourceType)
if err != nil {
fmt.Printf("Error: failed to load resources\nCause: %s\n", err)
fmt.Printf("Error: failed to load resources (%s)", err)
return ""
}
matched, err := generate.ValidateResourceWithPattern(log.Log, engineResource.UnstructuredContent(), userResource.UnstructuredContent())
if err != nil {
log.Log.V(3).Info(resourceType+" mismatch", "error", err.Error())
status = "fail"
} else if matched == "" {
status = "pass"
if isGenerate {
matched, err := generate.ValidateResourceWithPattern(log.Log, engineResource.UnstructuredContent(), userResource.UnstructuredContent())
if err != nil {
log.Log.V(3).Info("generatedResource mismatch", "error", err.Error())
status = "fail"
} else if matched == "" {
status = "pass"
}
} else {
userResource = unstructured.Unstructured{Object: tidyObject(userResource.UnstructuredContent()).(map[string]interface{})}
expected, err := userResource.MarshalJSON()
if err != nil {
fmt.Printf("Error: failed to convert patched resource to json (%s)\n", err)
return status
}
engineResource = unstructured.Unstructured{Object: tidyObject(engineResource.UnstructuredContent()).(map[string]interface{})}
actual, err := engineResource.MarshalJSON()
if err != nil {
fmt.Printf("Error: failed to convert engine resource to json (%s)\n", err)
return status
}
patch, err := jsonpatch.CreateMergePatch(actual, expected)
if err != nil {
fmt.Printf("Error: failed to calculate diff between patched and engine resources (%s)\n", err)
return status
}
if len(patch) > 2 {
log.Log.V(3).Info("patchedResource mismatch", "actual", string(actual), "expected", string(expected), "patch", string(patch))
status = "fail"
} else {
status = "pass"
}
}
return status
}