mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-10 01:46:55 +00:00
* fix: allow kyverno test variables directly in test 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> * strict Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
215 lines
7.2 KiB
Go
215 lines
7.2 KiB
Go
package common
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/go-git/go-billy/v5"
|
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/test/api"
|
|
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
|
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
|
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/values"
|
|
"github.com/kyverno/kyverno/pkg/autogen"
|
|
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
|
|
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
|
)
|
|
|
|
// HasVariables - check for variables in the policy
|
|
func HasVariables(policy kyvernov1.PolicyInterface) [][]string {
|
|
policyRaw, _ := json.Marshal(policy)
|
|
matches := regex.RegexVariables.FindAllStringSubmatch(string(policyRaw), -1)
|
|
return matches
|
|
}
|
|
|
|
func GetVariable(
|
|
variablesString []string,
|
|
vals *api.Values,
|
|
valuesFile string,
|
|
fs billy.Filesystem,
|
|
isGit bool,
|
|
policyResourcePath string,
|
|
) (map[string]string, map[string]string, map[string]map[string]api.Resource, map[string]map[string]string, []api.Subresource, error) {
|
|
if vals == nil && valuesFile != "" {
|
|
v, err := values.Load(fs, filepath.Join(policyResourcePath, valuesFile))
|
|
if err != nil {
|
|
fmt.Printf("Unable to load variable file: %s. error: %s \n", valuesFile, err)
|
|
return nil, nil, nil, nil, nil, sanitizederror.NewWithError("unable to read yaml", err)
|
|
}
|
|
vals = v
|
|
}
|
|
|
|
variables, globalValMap, valuesMapResource, valuesMapRule, namespaceSelectorMap, subresources := getVariable(variablesString, vals)
|
|
|
|
if globalValMap != nil {
|
|
if _, ok := globalValMap["request.operation"]; !ok {
|
|
globalValMap["request.operation"] = "CREATE"
|
|
log.V(3).Info("Defaulting request.operation to CREATE")
|
|
}
|
|
}
|
|
|
|
storePolicies := make([]store.Policy, 0)
|
|
for policyName, ruleMap := range valuesMapRule {
|
|
storeRules := make([]store.Rule, 0)
|
|
for _, rule := range ruleMap {
|
|
storeRules = append(storeRules, store.Rule{
|
|
Name: rule.Name,
|
|
Values: rule.Values,
|
|
ForEachValues: rule.ForeachValues,
|
|
})
|
|
}
|
|
storePolicies = append(storePolicies, store.Policy{
|
|
Name: policyName,
|
|
Rules: storeRules,
|
|
})
|
|
}
|
|
|
|
store.SetPolicies(storePolicies...)
|
|
|
|
return variables, globalValMap, valuesMapResource, namespaceSelectorMap, subresources, nil
|
|
}
|
|
|
|
func getVariable(
|
|
variablesString []string,
|
|
vals *api.Values,
|
|
) (map[string]string, map[string]string, map[string]map[string]api.Resource, map[string]map[string]api.Rule, map[string]map[string]string, []api.Subresource) {
|
|
valuesMapResource := make(map[string]map[string]api.Resource)
|
|
valuesMapRule := make(map[string]map[string]api.Rule)
|
|
namespaceSelectorMap := make(map[string]map[string]string)
|
|
variables := make(map[string]string)
|
|
subresources := make([]api.Subresource, 0)
|
|
globalValMap := make(map[string]string)
|
|
reqObjVars := ""
|
|
for _, kvpair := range variablesString {
|
|
kvs := strings.Split(strings.Trim(kvpair, " "), "=")
|
|
if strings.Contains(kvs[0], "request.object") {
|
|
if !strings.Contains(reqObjVars, kvs[0]) {
|
|
reqObjVars = reqObjVars + "," + kvs[0]
|
|
}
|
|
continue
|
|
}
|
|
variables[strings.Trim(kvs[0], " ")] = strings.Trim(kvs[1], " ")
|
|
}
|
|
|
|
if vals != nil {
|
|
if vals.GlobalValues == nil {
|
|
vals.GlobalValues = make(map[string]string)
|
|
vals.GlobalValues["request.operation"] = "CREATE"
|
|
log.V(3).Info("Defaulting request.operation to CREATE")
|
|
} else {
|
|
if val, ok := vals.GlobalValues["request.operation"]; ok {
|
|
if val == "" {
|
|
vals.GlobalValues["request.operation"] = "CREATE"
|
|
log.V(3).Info("Globally request.operation value provided by the user is empty, defaulting it to CREATE", "request.opearation: ", vals.GlobalValues)
|
|
}
|
|
}
|
|
}
|
|
|
|
globalValMap = vals.GlobalValues
|
|
|
|
for _, p := range vals.Policies {
|
|
resourceMap := make(map[string]api.Resource)
|
|
for _, r := range p.Resources {
|
|
if val, ok := r.Values["request.operation"]; ok {
|
|
if val == "" {
|
|
r.Values["request.operation"] = "CREATE"
|
|
log.V(3).Info("No request.operation found, defaulting it to CREATE", "policy", p.Name)
|
|
}
|
|
}
|
|
for variableInFile := range r.Values {
|
|
if strings.Contains(variableInFile, "request.object") {
|
|
if !strings.Contains(reqObjVars, variableInFile) {
|
|
reqObjVars = reqObjVars + "," + variableInFile
|
|
}
|
|
delete(r.Values, variableInFile)
|
|
continue
|
|
}
|
|
}
|
|
resourceMap[r.Name] = r
|
|
}
|
|
valuesMapResource[p.Name] = resourceMap
|
|
|
|
if p.Rules != nil {
|
|
ruleMap := make(map[string]api.Rule)
|
|
for _, r := range p.Rules {
|
|
ruleMap[r.Name] = r
|
|
}
|
|
valuesMapRule[p.Name] = ruleMap
|
|
}
|
|
}
|
|
|
|
for _, n := range vals.NamespaceSelectors {
|
|
namespaceSelectorMap[n.Name] = n.Labels
|
|
}
|
|
|
|
subresources = vals.Subresources
|
|
}
|
|
if reqObjVars != "" {
|
|
fmt.Printf("\nNOTICE: request.object.* variables are automatically parsed from the supplied resource. Ignoring value of variables `%v`.\n", reqObjVars)
|
|
}
|
|
return variables, globalValMap, valuesMapResource, valuesMapRule, namespaceSelectorMap, subresources
|
|
}
|
|
|
|
func SetInStoreContext(mutatedPolicies []kyvernov1.PolicyInterface, variables map[string]string) map[string]string {
|
|
storePolicies := make([]store.Policy, 0)
|
|
for _, policy := range mutatedPolicies {
|
|
storeRules := make([]store.Rule, 0)
|
|
for _, rule := range autogen.ComputeRules(policy) {
|
|
contextVal := make(map[string]interface{})
|
|
if len(rule.Context) != 0 {
|
|
for _, contextVar := range rule.Context {
|
|
for k, v := range variables {
|
|
if strings.HasPrefix(k, contextVar.Name) {
|
|
contextVal[k] = v
|
|
delete(variables, k)
|
|
}
|
|
}
|
|
}
|
|
storeRules = append(storeRules, store.Rule{
|
|
Name: rule.Name,
|
|
Values: contextVal,
|
|
})
|
|
}
|
|
}
|
|
storePolicies = append(storePolicies, store.Policy{
|
|
Name: policy.GetName(),
|
|
Rules: storeRules,
|
|
})
|
|
}
|
|
|
|
store.SetPolicies(storePolicies...)
|
|
|
|
return variables
|
|
}
|
|
|
|
func CheckVariableForPolicy(valuesMap map[string]map[string]api.Resource, globalValMap map[string]string, policyName string, resourceName string, resourceKind string, variables map[string]string, kindOnwhichPolicyIsApplied map[string]struct{}, variable string) (map[string]interface{}, error) {
|
|
// get values from file for this policy resource combination
|
|
thisPolicyResourceValues := make(map[string]interface{})
|
|
if len(valuesMap[policyName]) != 0 && !datautils.DeepEqual(valuesMap[policyName][resourceName], api.Resource{}) {
|
|
thisPolicyResourceValues = valuesMap[policyName][resourceName].Values
|
|
}
|
|
|
|
for k, v := range variables {
|
|
thisPolicyResourceValues[k] = v
|
|
}
|
|
|
|
if thisPolicyResourceValues == nil && len(globalValMap) > 0 {
|
|
thisPolicyResourceValues = make(map[string]interface{})
|
|
}
|
|
|
|
for k, v := range globalValMap {
|
|
if _, ok := thisPolicyResourceValues[k]; !ok {
|
|
thisPolicyResourceValues[k] = v
|
|
}
|
|
}
|
|
|
|
// skipping the variable check for non matching kind
|
|
if _, ok := kindOnwhichPolicyIsApplied[resourceKind]; ok {
|
|
if len(variable) > 0 && len(thisPolicyResourceValues) == 0 && store.HasPolicies() {
|
|
return thisPolicyResourceValues, sanitizederror.NewWithError(fmt.Sprintf("policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag", policyName, resourceName), nil)
|
|
}
|
|
}
|
|
return thisPolicyResourceValues, nil
|
|
}
|