From 849cfe5aba3d99f28762f60e5e101147b677b17e Mon Sep 17 00:00:00 2001 From: Eugene Yarshevich Date: Sun, 23 Jul 2023 18:51:58 +0300 Subject: [PATCH] Fix: Do not substitute strings without brackets Signed-off-by: Eugene Yarshevich --- internal/compose/templates.go | 36 ++++++++++++++++++++---------- internal/compose/templates_test.go | 1 + 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/internal/compose/templates.go b/internal/compose/templates.go index 7f222bd..66e1173 100644 --- a/internal/compose/templates.go +++ b/internal/compose/templates.go @@ -10,7 +10,7 @@ package compose import ( "fmt" "log" - "os" + "regexp" "strings" "github.com/mitchellh/mapstructure" @@ -18,6 +18,10 @@ import ( score "github.com/score-spec/score-go/types" ) +var ( + placeholderRegEx = regexp.MustCompile(`\$(\$|{([a-zA-Z0-9.\-_\[\]"'#]+)})`) +) + // templatesContext ia an utility type that provides a context for '${...}' templates substitution type templatesContext struct { meta map[string]interface{} @@ -49,22 +53,30 @@ func buildContext(metadata score.WorkloadMeta, resources score.ResourcesSpecs) ( // Substitute replaces all matching '${...}' templates in a source string func (ctx *templatesContext) Substitute(src string) string { - return os.Expand(src, ctx.mapVar) + return placeholderRegEx.ReplaceAllStringFunc(src, func(str string) string { + // WORKAROUND: ReplaceAllStringFunc(..) does not provide match details + // https://github.com/golang/go/issues/5690 + var matches = placeholderRegEx.FindStringSubmatch(str) + + // SANITY CHECK + if len(matches) != 3 { + log.Printf("Error: could not find a proper match in previously captured string fragment") + return src + } + + // EDGE CASE: Captures "$$" sequences and empty templates "${}" + if matches[2] == "" { + return matches[1] + } + + return ctx.mapVar(matches[2]) + }) } // MapVar replaces objects and properties references with corresponding values // Returns an empty string if the reference can't be resolved func (ctx *templatesContext) mapVar(ref string) string { - if ref == "" { - return "" - } - - // NOTE: os.Expand(..) would invoke a callback function with "$" as an argument for escaped sequences. - // "$${abc}" is treated as "$$" pattern and "{abc}" static text. - // The first segment (pattern) would trigger a callback function call. - // By returning "$" value we would ensure that escaped sequences would remain in the source text. - // For example "$${abc}" would result in "${abc}" after os.Expand(..) call. - if ref == "$" { + if ref == "" || ref == "$" { return ref } diff --git a/internal/compose/templates_test.go b/internal/compose/templates_test.go index 84ab2c0..03a0caf 100644 --- a/internal/compose/templates_test.go +++ b/internal/compose/templates_test.go @@ -71,6 +71,7 @@ func TestSubstitute(t *testing.T) { assert.Equal(t, "", ctx.Substitute("")) assert.Equal(t, "abc", ctx.Substitute("abc")) + assert.Equal(t, "$abc", ctx.Substitute("$abc")) assert.Equal(t, "abc $ abc", ctx.Substitute("abc $$ abc")) assert.Equal(t, "${abc}", ctx.Substitute("$${abc}"))