From 9dd28fc2e5866e38983faed9d0a2c81210a8e940 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Fri, 17 May 2024 16:10:09 -0700 Subject: [PATCH] funcs: Don't panic if templatefile path is sensitive Previously we were partially propagating any marks from the path, but not going all the way so we still ran into trouble when trying to use the string containing the file contents. Now we'll have loadTmpl also return the marks it had to read through to actually parse the template, and then we'll use those (instead of the original path marks) to mark the result. In practice the pathMarks and the tmplMarks should always match today, but this is intentionally structured to make the data flow clearer -- the marks always travel along with whatever they related to -- so we're less likely to break this accidentally under future maintenence. --- internal/lang/funcs/filesystem.go | 15 ++++++++------- internal/lang/funcs/filesystem_test.go | 12 ++++++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/internal/lang/funcs/filesystem.go b/internal/lang/funcs/filesystem.go index 4092cd5046..2257d5d91c 100644 --- a/internal/lang/funcs/filesystem.go +++ b/internal/lang/funcs/filesystem.go @@ -72,20 +72,21 @@ func MakeFileFunc(baseDir string, encBase64 bool) function.Function { // the templatefile function, since that would risk the same file being // included into itself indefinitely. func MakeTemplateFileFunc(baseDir string, funcsCb func() (funcs map[string]function.Function, fsFuncs collections.Set[string], templateFuncs collections.Set[string])) function.Function { - loadTmpl := func(fn string, marks cty.ValueMarks) (hcl.Expression, error) { + loadTmpl := func(fn string, marks cty.ValueMarks) (hcl.Expression, cty.ValueMarks, error) { // We re-use File here to ensure the same filename interpretation // as it does, along with its other safety checks. tmplVal, err := File(baseDir, cty.StringVal(fn).WithMarks(marks)) if err != nil { - return nil, err + return nil, nil, err } + tmplVal, marks = tmplVal.Unmark() expr, diags := hclsyntax.ParseTemplate([]byte(tmplVal.AsString()), fn, hcl.Pos{Line: 1, Column: 1}) if diags.HasErrors() { - return nil, diags + return nil, nil, diags } - return expr, nil + return expr, marks, nil } renderTmpl := makeRenderTemplateFunc(funcsCb, true) @@ -112,7 +113,7 @@ func MakeTemplateFileFunc(baseDir string, funcsCb func() (funcs map[string]funct // return any type. pathArg, pathMarks := args[0].Unmark() - expr, err := loadTmpl(pathArg.AsString(), pathMarks) + expr, _, err := loadTmpl(pathArg.AsString(), pathMarks) if err != nil { return cty.DynamicPseudoType, err } @@ -124,12 +125,12 @@ func MakeTemplateFileFunc(baseDir string, funcsCb func() (funcs map[string]funct }, Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { pathArg, pathMarks := args[0].Unmark() - expr, err := loadTmpl(pathArg.AsString(), pathMarks) + expr, tmplMarks, err := loadTmpl(pathArg.AsString(), pathMarks) if err != nil { return cty.DynamicVal, err } result, err := renderTmpl(expr, args[1]) - return result.WithMarks(pathMarks), err + return result.WithMarks(tmplMarks), err }, }) diff --git a/internal/lang/funcs/filesystem_test.go b/internal/lang/funcs/filesystem_test.go index cab8f27976..4b65560fa0 100644 --- a/internal/lang/funcs/filesystem_test.go +++ b/internal/lang/funcs/filesystem_test.go @@ -187,6 +187,18 @@ func TestTemplateFile(t *testing.T) { cty.True, // since this template contains only an interpolation, its true value shines through ``, }, + { + // If the template filename is sensitive then we also treat the + // rendered result as sensitive, because the rendered result + // is likely to imply which filename was used. + // (Sensitive filenames seem pretty unlikely, but if they do + // crop up then we should handle them consistently with our + // usual sensitivity rules.) + cty.StringVal("testdata/hello.txt").Mark(marks.Sensitive), + cty.EmptyObjectVal, + cty.StringVal("Hello World").Mark(marks.Sensitive), + ``, + }, } funcs := map[string]function.Function{