From 6a81bb7cc32f38178402ffe8db0fd480e5305234 Mon Sep 17 00:00:00 2001 From: Kumar Mallikarjuna Date: Tue, 28 Sep 2021 00:14:56 +0530 Subject: [PATCH] Escape references (#2433) * Escape references Signed-off-by: Kumar Mallikarjuna * Additional tests Signed-off-by: Kumar Mallikarjuna --- pkg/engine/variables/vars.go | 46 +++++++++++++++++++++++--- pkg/engine/variables/vars_test.go | 55 +++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/pkg/engine/variables/vars.go b/pkg/engine/variables/vars.go index b3ef7da034..587bc5e758 100644 --- a/pkg/engine/variables/vars.go +++ b/pkg/engine/variables/vars.go @@ -18,7 +18,12 @@ import ( ) var RegexVariables = regexp.MustCompile(`\{\{[^{}]*\}\}`) -var RegexReferences = regexp.MustCompile(`\$\(.[^\ ]*\)`) + +// Regex for '$(...)' at the beginning of the string, and 'x$(...)' where 'x' is not '\' +var RegexReferences = regexp.MustCompile(`^\$\(.[^\ ]*\)|[^\\]\$\(.[^\ ]*\)`) + +// Regex for '\$(...)' +var RegexEscpReferences = regexp.MustCompile(`\\\$\(.[^\ ]*\)`) // IsVariable returns true if the element contains a 'valid' variable {{}} func IsVariable(value string) bool { @@ -156,6 +161,13 @@ func substituteReferencesIfAny(log logr.Logger) jsonUtils.Action { } for _, v := range RegexReferences.FindAllString(value, -1) { + initial := v[:2] == `$(` + v_old := v + + if !initial { + v = v[1:] + } + resolvedReference, err := resolveReference(log, data.Document, v, data.Path) if err != nil { switch err.(type) { @@ -173,7 +185,15 @@ func substituteReferencesIfAny(log logr.Logger) jsonUtils.Action { log.V(3).Info("reference resolved", "reference", v, "value", resolvedReference, "path", data.Path) if val, ok := resolvedReference.(string); ok { - value = strings.Replace(value, v, val, -1) + replace_with := "" + + if !initial { + replace_with = string(v_old[0]) + } + + replace_with += val + + value = strings.Replace(value, v_old, replace_with, 1) continue } @@ -183,6 +203,10 @@ func substituteReferencesIfAny(log logr.Logger) jsonUtils.Action { } } + for _, v := range RegexEscpReferences.FindAllString(value, -1) { + value = strings.Replace(value, v, v[1:], -1) + } + return value, nil }) } @@ -329,6 +353,12 @@ func valFromReferenceToString(value interface{}, operator string) (string, error func FindAndShiftReferences(log logr.Logger, value, shift, pivot string) string { for _, reference := range RegexReferences.FindAllString(value, -1) { + initial := reference[:2] == `$(` + reference_old := reference + + if !initial { + reference = reference[1:] + } index := strings.Index(reference, pivot) if index == -1 { @@ -341,8 +371,16 @@ func FindAndShiftReferences(log logr.Logger, value, shift, pivot string) string pivot = pivot + "/" + ruleIndex } - shiftedReference := strings.Replace(reference, pivot, pivot+"/"+shift, 1) - value = strings.Replace(value, reference, shiftedReference, -1) + shiftedReference := strings.Replace(reference, pivot, pivot+"/"+shift, -1) + replace_with := "" + + if !initial { + replace_with = string(reference_old[0]) + } + + replace_with += shiftedReference + + value = strings.Replace(value, reference_old, replace_with, 1) } return value diff --git a/pkg/engine/variables/vars_test.go b/pkg/engine/variables/vars_test.go index 1ea7320311..b86b95ae31 100644 --- a/pkg/engine/variables/vars_test.go +++ b/pkg/engine/variables/vars_test.go @@ -1063,3 +1063,58 @@ func TestFindAndShiftReferences_AnyPatternPositiveCase(t *testing.T) { assert.Equal(t, expectedMessage, actualMessage) } + +func Test_EscpReferenceSubstitution(t *testing.T) { + jsonRaw := []byte(` + { + "metadata": { + "name": "temp", + "namespace": "n1", + "annotations": { + "test1": "$(../../../../spec/namespace)", + "test2": "\\$(ENV_VAR)", + "test3": "\\${ENV_VAR}", + "test4": "\\\\\\${ENV_VAR}" + } + }, + "(spec)": { + "namespace": "n1", + "name": "temp1" + } + }`) + + expectedJSON := []byte(` + { + "metadata": { + "name": "temp", + "namespace": "n1", + "annotations": { + "test1": "n1", + "test2": "$(ENV_VAR)", + "test3": "\\${ENV_VAR}", + "test4": "\\\\\\${ENV_VAR}" + } + }, + "(spec)": { + "namespace": "n1", + "name": "temp1" + } + }`) + + var document interface{} + err := json.Unmarshal(jsonRaw, &document) + assert.NilError(t, err) + + var expectedDocument interface{} + err = json.Unmarshal(expectedJSON, &expectedDocument) + assert.NilError(t, err) + + ctx := context.NewContext() + err = ctx.AddResource(jsonRaw) + assert.NilError(t, err) + + actualDocument, err := SubstituteAll(log.Log, ctx, document) + assert.NilError(t, err) + + assert.DeepEqual(t, expectedDocument, actualDocument) +}