1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

Escape variables (#2563)

* Escape variables

Signed-off-by: Kumar Mallikarjuna <kumarmallikarjuna1@gmail.com>

* Escape variables test - nested

Signed-off-by: Kumar Mallikarjuna <kumarmallikarjuna1@gmail.com>

* Fixed missing changes

Signed-off-by: Kumar Mallikarjuna <kumarmallikarjuna1@gmail.com>
This commit is contained in:
Kumar Mallikarjuna 2021-10-21 05:40:24 +05:30 committed by GitHub
parent 7d65ebbd87
commit b1c40e172d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 5 deletions

View file

@ -17,7 +17,9 @@ import (
"github.com/kyverno/kyverno/pkg/engine/operator"
)
var RegexVariables = regexp.MustCompile(`\{\{[^{}]*\}\}`)
var RegexVariables = regexp.MustCompile(`^\{\{[^{}]*\}\}|[^\\]\{\{[^{}]*\}\}`)
var RegexEscpVariables = regexp.MustCompile(`\\\{\{[^{}]*\}\}`)
// Regex for '$(...)' at the beginning of the string, and 'x$(...)' where 'x' is not '\'
var RegexReferences = regexp.MustCompile(`^\$\(.[^\ ]*\)|[^\\]\$\(.[^\ ]*\)`)
@ -25,6 +27,8 @@ var RegexReferences = regexp.MustCompile(`^\$\(.[^\ ]*\)|[^\\]\$\(.[^\ ]*\)`)
// Regex for '\$(...)'
var RegexEscpReferences = regexp.MustCompile(`\\\$\(.[^\ ]*\)`)
var regexVariableInit = regexp.MustCompile(`^\{\{[^{}]*\}\}`)
// IsVariable returns true if the element contains a 'valid' variable {{}}
func IsVariable(value string) bool {
groups := RegexVariables.FindAllStringSubmatch(value, -1)
@ -40,7 +44,19 @@ func IsReference(value string) bool {
// ReplaceAllVars replaces all variables with the value defined in the replacement function
// This is used to avoid validation errors
func ReplaceAllVars(src string, repl func(string) string) string {
return RegexVariables.ReplaceAllStringFunc(src, repl)
wrapper := func(s string) string {
initial := len(regexVariableInit.FindAllString(s, -1)) > 0
prefix := ""
if !initial {
prefix = string(s[0])
s = s[1:]
}
return prefix + repl(s)
}
return RegexVariables.ReplaceAllStringFunc(src, wrapper)
}
func newPreconditionsVariableResolver(log logr.Logger) VariableResolver {
@ -215,6 +231,12 @@ func validateBackgroundModeVars(log logr.Logger, ctx context.EvalInterface) json
}
vars := RegexVariables.FindAllString(value, -1)
for _, v := range vars {
initial := len(regexVariableInit.FindAllString(v, -1)) > 0
if !initial {
v = v[1:]
}
variable := replaceBracesAndTrimSpaces(v)
_, err := ctx.Query(variable)
@ -241,6 +263,12 @@ func validateElementInForEach(log logr.Logger) jsonUtils.Action {
}
vars := RegexVariables.FindAllString(value, -1)
for _, v := range vars {
initial := len(regexVariableInit.FindAllString(v, -1)) > 0
if !initial {
v = v[1:]
}
variable := replaceBracesAndTrimSpaces(v)
if strings.HasPrefix(variable, "element") && !strings.Contains(data.Path, "/foreach/") {
@ -341,6 +369,13 @@ func substituteVariablesIfAny(log logr.Logger, ctx context.EvalInterface, vr Var
originalPattern := value
for _, v := range vars {
initial := len(regexVariableInit.FindAllString(v, -1)) > 0
v_old := v
if !initial {
v = v[1:]
}
variable := replaceBracesAndTrimSpaces(v)
if variable == "@" {
@ -368,7 +403,13 @@ func substituteVariablesIfAny(log logr.Logger, ctx context.EvalInterface, vr Var
return substitutedVar, nil
}
if value, err = substituteVarInPattern(originalPattern, v, substitutedVar); err != nil {
prefix := ""
if !initial {
prefix = string(v_old[0])
}
if value, err = substituteVarInPattern(prefix, originalPattern, v, substitutedVar); err != nil {
return nil, fmt.Errorf("failed to resolve %v at path %s: %s", variable, data.Path, err.Error())
}
@ -379,6 +420,10 @@ func substituteVariablesIfAny(log logr.Logger, ctx context.EvalInterface, vr Var
vars = RegexVariables.FindAllString(value, -1)
}
for _, v := range RegexEscpVariables.FindAllString(value, -1) {
value = strings.Replace(value, v, v[1:], -1)
}
return value, nil
})
}
@ -404,7 +449,7 @@ func getJMESPath(rawPath string) string {
return string(regex.ReplaceAll([]byte(path), []byte("[$1].")))
}
func substituteVarInPattern(pattern, variable string, value interface{}) (string, error) {
func substituteVarInPattern(prefix, pattern, variable string, value interface{}) (string, error) {
var stringToSubstitute string
if s, ok := value.(string); ok {
@ -417,7 +462,10 @@ func substituteVarInPattern(pattern, variable string, value interface{}) (string
stringToSubstitute = string(buffer)
}
return strings.Replace(pattern, variable, stringToSubstitute, -1), nil
stringToSubstitute = prefix + stringToSubstitute
variable = prefix + variable
return strings.Replace(pattern, variable, stringToSubstitute, 1), nil
}
func replaceBracesAndTrimSpaces(v string) string {

View file

@ -1115,3 +1115,39 @@ func Test_EscpReferenceSubstitution(t *testing.T) {
assert.DeepEqual(t, expectedDocument, actualDocument)
}
func Test_ReplacingEscpNestedVariableWhenDeleting(t *testing.T) {
patternRaw := []byte(`"\\{{request.object.metadata.annotations.{{request.object.metadata.annotations.targetnew}}}}"`)
var resourceRaw = []byte(`
{
"request":{
"operation":"DELETE",
"oldObject":{
"metadata":{
"name":"current",
"namespace":"ns",
"annotations":{
"target":"nested_target",
"targetnew":"target"
}
}
}
}
}`)
var pattern interface{}
var err error
err = json.Unmarshal(patternRaw, &pattern)
if err != nil {
t.Error(err)
}
ctx := context.NewContext()
err = ctx.AddJSON(resourceRaw)
assert.NilError(t, err)
pattern, err = SubstituteAll(log.Log, ctx, pattern)
assert.NilError(t, err)
assert.Equal(t, fmt.Sprintf("%v", pattern), "{{request.object.metadata.annotations.target}}")
}