lang/funcs: templatefile requires valid variable names

Previously the templatefile function would permit any arbitrary string as
a variable name, but due to the HCL template syntax it would be impossible
to refer to one that isn't a valid HCL identifier without causing an
HCL syntax error.

The HCL syntax errors are correct, but don't really point to the root
cause of the problem. Instead, we'll pre-verify that the variable names
are valid before we even try to render the template, and given a
specialized error message that refers to the vars argument expression as
the problematic part, which will hopefully make the resolution path
clearer for a user encountering this situation.

The syntax error still remains for situations where all of the variable
names are correct but e.g. the user made a typo referring to one, which
makes sense because in that case the problem _is_ inside the template.
This commit is contained in:
Martin Atkins 2020-02-21 16:35:27 -08:00
parent ec9f950b3f
commit 67d95b97ce
3 changed files with 25 additions and 1 deletions

View File

@ -100,6 +100,20 @@ func MakeTemplateFileFunc(baseDir string, funcsCb func() map[string]function.Fun
Variables: varsVal.AsValueMap(),
}
// We require all of the variables to be valid HCL identifiers, because
// otherwise there would be no way to refer to them in the template
// anyway. Rejecting this here gives better feedback to the user
// than a syntax error somewhere in the template itself.
for n := range ctx.Variables {
if !hclsyntax.ValidIdentifier(n) {
// This error message intentionally doesn't describe _all_ of
// the different permutations that are technically valid as an
// HCL identifier, but rather focuses on what we might
// consider to be an "idiomatic" variable name.
return cty.DynamicVal, function.NewArgErrorf(1, "invalid template variable name %q: must start with a letter, followed by zero or more letters, digits, and underscores", n)
}
}
// We'll pre-check references in the template here so we can give a
// more specialized error message than HCL would by default, so it's
// clearer that this problem is coming from a templatefile call.

View File

@ -86,6 +86,14 @@ func TestTemplateFile(t *testing.T) {
cty.StringVal("Hello, Jodie!"),
``,
},
{
cty.StringVal("testdata/hello.tmpl"),
cty.MapVal(map[string]cty.Value{
"name!": cty.StringVal("Jodie"),
}),
cty.NilVal,
`invalid template variable name "name!": must start with a letter, followed by zero or more letters, digits, and underscores`,
},
{
cty.StringVal("testdata/hello.tmpl"),
cty.ObjectVal(map[string]cty.Value{

View File

@ -29,7 +29,9 @@ into a separate file for readability.
The "vars" argument must be a map. Within the template file, each of the keys
in the map is available as a variable for interpolation. The template may
also use any other function available in the Terraform language, except that
recursive calls to `templatefile` are not permitted.
recursive calls to `templatefile` are not permitted. Variable names must
each start with a letter, followed by zero or more letters, digits, or
underscores.
Strings in the Terraform language are sequences of Unicode characters, so
this function will interpret the file contents as UTF-8 encoded text and