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

refactor: move common utils (#3553)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-04-05 15:02:43 +02:00 committed by GitHub
parent 3bc0e062f9
commit 29d7010e25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 121 additions and 131 deletions

View file

@ -9,25 +9,22 @@ import (
"fmt"
"strings"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/sigstore/cosign/cmd/cosign/cli/rekor"
"github.com/sigstore/cosign/cmd/cosign/cli/fulcio"
"github.com/sigstore/cosign/pkg/oci/remote"
"github.com/go-logr/logr"
"github.com/google/go-containerregistry/pkg/name"
gcrremote "github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/in-toto/in-toto-golang/in_toto"
wildcard "github.com/kyverno/go-wildcard"
"github.com/kyverno/kyverno/pkg/engine/common"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/registryclient"
"github.com/kyverno/kyverno/pkg/utils"
"github.com/pkg/errors"
"github.com/sigstore/cosign/cmd/cosign/cli/fulcio"
"github.com/sigstore/cosign/cmd/cosign/cli/options"
"github.com/sigstore/cosign/cmd/cosign/cli/rekor"
"github.com/sigstore/cosign/pkg/cosign"
"github.com/sigstore/cosign/pkg/cosign/attestation"
"github.com/sigstore/cosign/pkg/oci"
"github.com/sigstore/cosign/pkg/oci/remote"
sigs "github.com/sigstore/cosign/pkg/signature"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/signature"
@ -269,7 +266,7 @@ func decodeStatement(payloadBase64 string) (map[string]interface{}, error) {
// - in_toto.PredicateLinkV1
// - in_toto.PredicateSPDX
// any other custom predicate
return common.ToMap(statement)
return utils.ToMap(statement)
}
return decodeCosignCustomProvenanceV01(statement)
@ -297,7 +294,7 @@ func decodeCosignCustomProvenanceV01(statement in_toto.Statement) (map[string]in
statement.Predicate = predicate
}
return common.ToMap(statement)
return utils.ToMap(statement)
}
func stringToJSONMap(i interface{}) (map[string]interface{}, error) {

View file

@ -1,7 +1,6 @@
package common
import (
"encoding/json"
"fmt"
"reflect"
@ -10,53 +9,6 @@ import (
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
)
// CopyMap creates a full copy of the target map
func CopyMap(m map[string]interface{}) map[string]interface{} {
mapCopy := make(map[string]interface{})
for k, v := range m {
mapCopy[k] = v
}
return mapCopy
}
// CopySlice creates a full copy of the target slice
func CopySlice(s []interface{}) []interface{} {
sliceCopy := make([]interface{}, len(s))
copy(sliceCopy, s)
return sliceCopy
}
// CopySliceOfMaps creates a full copy of the target slice
func CopySliceOfMaps(s []map[string]interface{}) []interface{} {
sliceCopy := make([]interface{}, len(s))
for i, v := range s {
sliceCopy[i] = CopyMap(v)
}
return sliceCopy
}
func ToMap(data interface{}) (map[string]interface{}, error) {
if m, ok := data.(map[string]interface{}); ok {
return m, nil
}
b, err := json.Marshal(data)
if err != nil {
return nil, err
}
mapData := make(map[string]interface{})
err = json.Unmarshal(b, &mapData)
if err != nil {
return nil, err
}
return mapData, nil
}
func GetRawKeyIfWrappedWithAttributes(str string) string {
if len(str) < 2 {
return str

View file

@ -1,37 +0,0 @@
package common
import (
"testing"
"gotest.tools/assert"
)
func Test_OriginalMapMustNotBeChanged(t *testing.T) {
// no variables
originalMap := map[string]interface{}{
"rsc": 3711,
"r": 2138,
"gri": 1908,
"adg": 912,
}
mapCopy := CopyMap(originalMap)
mapCopy["r"] = 1
assert.Equal(t, originalMap["r"], 2138)
}
func Test_OriginalSliceMustNotBeChanged(t *testing.T) {
// no variables
originalSlice := []interface{}{
3711,
2138,
1908,
912,
}
sliceCopy := CopySlice(originalSlice)
sliceCopy[0] = 1
assert.Equal(t, originalSlice[0], 3711)
}

View file

@ -4,7 +4,7 @@ import (
"fmt"
"strconv"
"github.com/kyverno/kyverno/pkg/engine/common"
"github.com/kyverno/kyverno/pkg/utils"
)
// ActionData represents data available for action on current element
@ -69,13 +69,13 @@ func (t *Traversal) traverseJSON(element interface{}, path string) (interface{},
// traverse further
switch typed := element.(type) {
case map[string]interface{}:
return t.traverseObject(common.CopyMap(typed), path)
return t.traverseObject(utils.CopyMap(typed), path)
case []interface{}:
return t.traverseList(common.CopySlice(typed), path)
return t.traverseList(utils.CopySlice(typed), path)
case []map[string]interface{}:
return t.traverseList(common.CopySliceOfMaps(typed), path)
return t.traverseList(utils.CopySliceOfMaps(typed), path)
case Key:
return typed.Key, nil

View file

@ -8,11 +8,11 @@ import (
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine/common"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/mutate/patch"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/utils"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@ -92,7 +92,7 @@ func ForEach(name string, foreach *kyverno.ForEachMutation, ctx *context.Context
}
func substituteAllInForEach(fe *kyverno.ForEachMutation, ctx *context.Context, logger logr.Logger) (*kyverno.ForEachMutation, error) {
jsonObj, err := common.ToMap(fe)
jsonObj, err := utils.ToMap(fe)
if err != nil {
return nil, err
}

View file

@ -16,9 +16,10 @@ import (
"github.com/go-logr/logr"
gojmespath "github.com/jmespath/go-jmespath"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/utils"
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/engine/validate"
"github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/utils"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
)
@ -179,7 +180,7 @@ func newValidator(log logr.Logger, ctx *PolicyContext, rule *kyverno.Rule) *vali
func newForeachValidator(foreach *kyverno.ForEachValidation, rule *kyverno.Rule, ctx *PolicyContext, log logr.Logger) *validator {
ruleCopy := rule.DeepCopy()
anyAllConditions, err := common.ToMap(foreach.AnyAllConditions)
anyAllConditions, err := utils.ToMap(foreach.AnyAllConditions)
if err != nil {
log.Error(err, "failed to convert ruleCopy.Validation.ForEachValidation.AnyAllConditions")
}
@ -198,16 +199,16 @@ func newForeachValidator(foreach *kyverno.ForEachValidation, rule *kyverno.Rule,
func (v *validator) validate() *response.RuleResponse {
if err := v.loadContext(); err != nil {
return ruleError(v.rule, utils.Validation, "failed to load context", err)
return ruleError(v.rule, engineutils.Validation, "failed to load context", err)
}
preconditionsPassed, err := checkPreconditions(v.log, v.ctx, v.anyAllConditions)
if err != nil {
return ruleError(v.rule, utils.Validation, "failed to evaluate preconditions", err)
return ruleError(v.rule, engineutils.Validation, "failed to evaluate preconditions", err)
}
if !preconditionsPassed && v.ctx.Policy.GetSpec().ValidationFailureAction != kyverno.Audit {
return ruleResponse(v.rule, utils.Validation, "preconditions not met", response.RuleStatusSkip)
return ruleResponse(v.rule, engineutils.Validation, "preconditions not met", response.RuleStatusSkip)
}
if v.deny != nil {
@ -216,14 +217,14 @@ func (v *validator) validate() *response.RuleResponse {
if v.pattern != nil || v.anyPattern != nil {
if err = v.substitutePatterns(); err != nil {
return ruleError(v.rule, utils.Validation, "variable substitution failed", err)
return ruleError(v.rule, engineutils.Validation, "variable substitution failed", err)
}
ruleResponse := v.validateResourceWithRule()
if isUpdateRequest(v.ctx) {
priorResp, err := validateOldObject(v.log, v.ctx, v.rule)
if err != nil {
return ruleError(v.rule, utils.Validation, "failed to validate old object", err)
return ruleError(v.rule, engineutils.Validation, "failed to validate old object", err)
}
if isSameRuleResponse(ruleResponse, priorResp) {
@ -241,14 +242,14 @@ func (v *validator) validate() *response.RuleResponse {
func (v *validator) validateForEach() *response.RuleResponse {
if err := v.loadContext(); err != nil {
return ruleError(v.rule, utils.Validation, "failed to load context", err)
return ruleError(v.rule, engineutils.Validation, "failed to load context", err)
}
preconditionsPassed, err := checkPreconditions(v.log, v.ctx, v.anyAllConditions)
if err != nil {
return ruleError(v.rule, utils.Validation, "failed to evaluate preconditions", err)
return ruleError(v.rule, engineutils.Validation, "failed to evaluate preconditions", err)
} else if !preconditionsPassed && v.ctx.Policy.GetSpec().ValidationFailureAction != kyverno.Audit {
return ruleResponse(v.rule, utils.Validation, "preconditions not met", response.RuleStatusSkip)
return ruleResponse(v.rule, engineutils.Validation, "preconditions not met", response.RuleStatusSkip)
}
foreachList := v.rule.Validation.ForEachValidation
@ -278,10 +279,10 @@ func (v *validator) validateForEach() *response.RuleResponse {
}
if applyCount == 0 {
return ruleResponse(v.rule, utils.Validation, "rule skipped", response.RuleStatusSkip)
return ruleResponse(v.rule, engineutils.Validation, "rule skipped", response.RuleStatusSkip)
}
return ruleResponse(v.rule, utils.Validation, "rule passed", response.RuleStatusPass)
return ruleResponse(v.rule, engineutils.Validation, "rule passed", response.RuleStatusPass)
}
func (v *validator) validateElements(foreach *kyverno.ForEachValidation, elements []interface{}, elementScope bool) (*response.RuleResponse, int) {
@ -295,7 +296,7 @@ func (v *validator) validateElements(foreach *kyverno.ForEachValidation, element
ctx := v.ctx.Copy()
if err := addElementToContext(ctx, e, i, elementScope); err != nil {
v.log.Error(err, "failed to add element to context")
return ruleError(v.rule, utils.Validation, "failed to process foreach", err), applyCount
return ruleError(v.rule, engineutils.Validation, "failed to process foreach", err), applyCount
}
foreachValidator := newForeachValidator(foreach, v.rule, ctx, v.log)
@ -308,17 +309,17 @@ func (v *validator) validateElements(foreach *kyverno.ForEachValidation, element
continue
} else if r.Status != response.RuleStatusPass {
msg := fmt.Sprintf("validation failure: %v", r.Message)
return ruleResponse(v.rule, utils.Validation, msg, r.Status), applyCount
return ruleResponse(v.rule, engineutils.Validation, msg, r.Status), applyCount
}
applyCount++
}
return ruleResponse(v.rule, utils.Validation, "", response.RuleStatusPass), applyCount
return ruleResponse(v.rule, engineutils.Validation, "", response.RuleStatusPass), applyCount
}
func addElementToContext(ctx *PolicyContext, e interface{}, elementIndex int, elementScope bool) error {
data, err := common.ToMap(e)
data, err := utils.ToMap(e)
if err != nil {
return err
}
@ -359,24 +360,24 @@ func (v *validator) validateDeny() *response.RuleResponse {
anyAllCond := v.deny.GetAnyAllConditions()
anyAllCond, err := variables.SubstituteAll(v.log, v.ctx.JSONContext, anyAllCond)
if err != nil {
return ruleError(v.rule, utils.Validation, "failed to substitute variables in deny conditions", err)
return ruleError(v.rule, engineutils.Validation, "failed to substitute variables in deny conditions", err)
}
if err = v.substituteDeny(); err != nil {
return ruleError(v.rule, utils.Validation, "failed to substitute variables in rule", err)
return ruleError(v.rule, engineutils.Validation, "failed to substitute variables in rule", err)
}
denyConditions, err := common.TransformConditions(anyAllCond)
if err != nil {
return ruleError(v.rule, utils.Validation, "invalid deny conditions", err)
return ruleError(v.rule, engineutils.Validation, "invalid deny conditions", err)
}
deny := variables.EvaluateConditions(v.log, v.ctx.JSONContext, denyConditions)
if deny {
return ruleResponse(v.rule, utils.Validation, v.getDenyMessage(deny), response.RuleStatusFail)
return ruleResponse(v.rule, engineutils.Validation, v.getDenyMessage(deny), response.RuleStatusFail)
}
return ruleResponse(v.rule, utils.Validation, v.getDenyMessage(deny), response.RuleStatusPass)
return ruleResponse(v.rule, engineutils.Validation, v.getDenyMessage(deny), response.RuleStatusPass)
}
func (v *validator) getDenyMessage(deny bool) string {
@ -480,22 +481,22 @@ func (v *validator) validatePatterns(resource unstructured.Unstructured) *respon
v.log.V(3).Info("validation error", "path", pe.Path, "error", err.Error())
if pe.Skip {
return ruleResponse(v.rule, utils.Validation, pe.Error(), response.RuleStatusSkip)
return ruleResponse(v.rule, engineutils.Validation, pe.Error(), response.RuleStatusSkip)
}
if pe.Path == "" {
return ruleResponse(v.rule, utils.Validation, v.buildErrorMessage(err, ""), response.RuleStatusError)
return ruleResponse(v.rule, engineutils.Validation, v.buildErrorMessage(err, ""), response.RuleStatusError)
}
return ruleResponse(v.rule, utils.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusFail)
return ruleResponse(v.rule, engineutils.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusFail)
}
return ruleResponse(v.rule, utils.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusError)
return ruleResponse(v.rule, engineutils.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusError)
}
v.log.V(4).Info("successfully processed rule")
msg := fmt.Sprintf("validation rule '%s' passed.", v.rule.Name)
return ruleResponse(v.rule, utils.Validation, msg, response.RuleStatusPass)
return ruleResponse(v.rule, engineutils.Validation, msg, response.RuleStatusPass)
}
if v.anyPattern != nil {
@ -505,14 +506,14 @@ func (v *validator) validatePatterns(resource unstructured.Unstructured) *respon
anyPatterns, err := deserializeAnyPattern(v.anyPattern)
if err != nil {
msg := fmt.Sprintf("failed to deserialize anyPattern, expected type array: %v", err)
return ruleResponse(v.rule, utils.Validation, msg, response.RuleStatusError)
return ruleResponse(v.rule, engineutils.Validation, msg, response.RuleStatusError)
}
for idx, pattern := range anyPatterns {
err := validate.MatchPattern(v.log, resource.Object, pattern)
if err == nil {
msg := fmt.Sprintf("validation rule '%s' anyPattern[%d] passed.", v.rule.Name, idx)
return ruleResponse(v.rule, utils.Validation, msg, response.RuleStatusPass)
return ruleResponse(v.rule, engineutils.Validation, msg, response.RuleStatusPass)
}
if pe, ok := err.(*validate.PatternError); ok {
@ -536,11 +537,11 @@ func (v *validator) validatePatterns(resource unstructured.Unstructured) *respon
v.log.V(4).Info(fmt.Sprintf("Validation rule '%s' failed. %s", v.rule.Name, errorStr))
msg := buildAnyPatternErrorMessage(v.rule, errorStr)
return ruleResponse(v.rule, utils.Validation, msg, response.RuleStatusFail)
return ruleResponse(v.rule, engineutils.Validation, msg, response.RuleStatusFail)
}
}
return ruleResponse(v.rule, utils.Validation, v.rule.Validation.Message, response.RuleStatusPass)
return ruleResponse(v.rule, engineutils.Validation, v.rule.Validation.Message, response.RuleStatusPass)
}
func deserializeAnyPattern(anyPattern apiextensions.JSON) ([]interface{}, error) {

View file

@ -25,6 +25,53 @@ import (
var regexVersion = regexp.MustCompile(`v(\d+).(\d+).(\d+)\.*`)
// CopyMap creates a full copy of the target map
func CopyMap(m map[string]interface{}) map[string]interface{} {
mapCopy := make(map[string]interface{})
for k, v := range m {
mapCopy[k] = v
}
return mapCopy
}
// CopySlice creates a full copy of the target slice
func CopySlice(s []interface{}) []interface{} {
sliceCopy := make([]interface{}, len(s))
copy(sliceCopy, s)
return sliceCopy
}
// CopySliceOfMaps creates a full copy of the target slice
func CopySliceOfMaps(s []map[string]interface{}) []interface{} {
sliceCopy := make([]interface{}, len(s))
for i, v := range s {
sliceCopy[i] = CopyMap(v)
}
return sliceCopy
}
func ToMap(data interface{}) (map[string]interface{}, error) {
if m, ok := data.(map[string]interface{}); ok {
return m, nil
}
b, err := json.Marshal(data)
if err != nil {
return nil, err
}
mapData := make(map[string]interface{})
err = json.Unmarshal(b, &mapData)
if err != nil {
return nil, err
}
return mapData, nil
}
// Contains checks if a string is contained in a list of string
func contains(list []string, element string, fn func(string, string) bool) bool {
for _, e := range list {

View file

@ -6,6 +6,36 @@ import (
"gotest.tools/assert"
)
func Test_OriginalMapMustNotBeChanged(t *testing.T) {
// no variables
originalMap := map[string]interface{}{
"rsc": 3711,
"r": 2138,
"gri": 1908,
"adg": 912,
}
mapCopy := CopyMap(originalMap)
mapCopy["r"] = 1
assert.Equal(t, originalMap["r"], 2138)
}
func Test_OriginalSliceMustNotBeChanged(t *testing.T) {
// no variables
originalSlice := []interface{}{
3711,
2138,
1908,
912,
}
sliceCopy := CopySlice(originalSlice)
sliceCopy[0] = 1
assert.Equal(t, originalSlice[0], 3711)
}
func Test_allEmpty(t *testing.T) {
var list []string
var element string