From d74545cb0309a51cf9b5c837dc78c67042597984 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Fri, 18 Dec 2020 13:47:47 -0500 Subject: [PATCH 1/2] hclsyntax: Fix panic for marked template loops --- hclsyntax/expression_template.go | 7 ++++--- hclsyntax/expression_template_test.go | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/hclsyntax/expression_template.go b/hclsyntax/expression_template.go index ff9a6e5..dfce942 100644 --- a/hclsyntax/expression_template.go +++ b/hclsyntax/expression_template.go @@ -152,6 +152,7 @@ func (e *TemplateJoinExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti return cty.UnknownVal(cty.String), diags } + tuple, marks := tuple.Unmark() buf := &bytes.Buffer{} it := tuple.ElementIterator() for it.Next() { @@ -171,7 +172,7 @@ func (e *TemplateJoinExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti continue } if val.Type() == cty.DynamicPseudoType { - return cty.UnknownVal(cty.String), diags + return cty.UnknownVal(cty.String).WithMarks(marks), diags } strVal, err := convert.Convert(val, cty.String) if err != nil { @@ -189,13 +190,13 @@ func (e *TemplateJoinExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti continue } if !val.IsKnown() { - return cty.UnknownVal(cty.String), diags + return cty.UnknownVal(cty.String).WithMarks(marks), diags } buf.WriteString(strVal.AsString()) } - return cty.StringVal(buf.String()), diags + return cty.StringVal(buf.String()).WithMarks(marks), diags } func (e *TemplateJoinExpr) Range() hcl.Range { diff --git a/hclsyntax/expression_template_test.go b/hclsyntax/expression_template_test.go index c92157b..6219c50 100644 --- a/hclsyntax/expression_template_test.go +++ b/hclsyntax/expression_template_test.go @@ -316,6 +316,20 @@ trim`, cty.StringVal(`Authenticate with "my voice is my passport"`).WithMarks(cty.NewValueMarks("sensitive")), 0, }, + { // can loop over marked collections + `%{ for s in secrets }${s}%{ endfor }`, + &hcl.EvalContext{ + Variables: map[string]cty.Value{ + "secrets": cty.ListVal([]cty.Value{ + cty.StringVal("foo"), + cty.StringVal("bar"), + cty.StringVal("baz"), + }).Mark("sensitive"), + }, + }, + cty.StringVal("foobarbaz").Mark("sensitive"), + 0, + }, } for _, test := range tests { From f2f7dd7632bfc062e68d1d41ecce5aac3ff464a8 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Fri, 18 Dec 2020 14:36:38 -0500 Subject: [PATCH 2/2] hclsyntax: Fix another template loop panic If individual template expressions in a loop have marks, merge those marks into the final result when joining. --- hclsyntax/expression_template.go | 7 ++++++- hclsyntax/expression_template_test.go | 28 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/hclsyntax/expression_template.go b/hclsyntax/expression_template.go index dfce942..0b7e07a 100644 --- a/hclsyntax/expression_template.go +++ b/hclsyntax/expression_template.go @@ -153,6 +153,7 @@ func (e *TemplateJoinExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti } tuple, marks := tuple.Unmark() + allMarks := []cty.ValueMarks{marks} buf := &bytes.Buffer{} it := tuple.ElementIterator() for it.Next() { @@ -193,10 +194,14 @@ func (e *TemplateJoinExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti return cty.UnknownVal(cty.String).WithMarks(marks), diags } + strVal, strValMarks := strVal.Unmark() + if len(strValMarks) > 0 { + allMarks = append(allMarks, strValMarks) + } buf.WriteString(strVal.AsString()) } - return cty.StringVal(buf.String()).WithMarks(marks), diags + return cty.StringVal(buf.String()).WithMarks(allMarks...), diags } func (e *TemplateJoinExpr) Range() hcl.Range { diff --git a/hclsyntax/expression_template_test.go b/hclsyntax/expression_template_test.go index 6219c50..ef830cb 100644 --- a/hclsyntax/expression_template_test.go +++ b/hclsyntax/expression_template_test.go @@ -330,6 +330,34 @@ trim`, cty.StringVal("foobarbaz").Mark("sensitive"), 0, }, + { // marks on individual elements propagate to the result + `%{ for s in secrets }${s}%{ endfor }`, + &hcl.EvalContext{ + Variables: map[string]cty.Value{ + "secrets": cty.ListVal([]cty.Value{ + cty.StringVal("foo"), + cty.StringVal("bar").Mark("sensitive"), + cty.StringVal("baz"), + }), + }, + }, + cty.StringVal("foobarbaz").Mark("sensitive"), + 0, + }, + { // lots of marks! + `%{ for s in secrets }${s}%{ endfor }`, + &hcl.EvalContext{ + Variables: map[string]cty.Value{ + "secrets": cty.ListVal([]cty.Value{ + cty.StringVal("foo").Mark("x"), + cty.StringVal("bar").Mark("y"), + cty.StringVal("baz").Mark("z"), + }).Mark("x"), // second instance of x + }, + }, + cty.StringVal("foobarbaz").WithMarks(cty.NewValueMarks("x", "y", "z")), + 0, + }, } for _, test := range tests {