summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Atkins <mart@degeneration.co.uk>2024-05-08 16:09:28 -0700
committerMartin Atkins <mart@degeneration.co.uk>2024-05-09 11:28:37 -0700
commitbc757658ca11c5d6d17f328d5672ac447c3efcff (patch)
tree35551c0e20ef37419e22a4065392906b2e18dee0
parentbf546973d01a1ec4a306cbcc789bd86ea70e44be (diff)
hclsyntax: Don't panic if splat operand is unknown and marked
We were calling .Range() on any unknown sourceVal, without first checking whether it was marked. That method panics if called on a marked value, so we need to strip that off first. While testing this I found some return paths that weren't properly transferring the source value's marks to the output, and so this also addresses those so that all return paths preserve whatever markings are present on the source value. In particular, if a non-list/set/tuple value gets "upgraded" into a tuple then we must transfer its marks onto the tuple, because the decision about constructing that value was based on characteristics of the source value.
-rw-r--r--hclsyntax/expression.go15
-rw-r--r--hclsyntax/expression_test.go10
2 files changed, 18 insertions, 7 deletions
diff --git a/hclsyntax/expression.go b/hclsyntax/expression.go
index 8159739..577a50f 100644
--- a/hclsyntax/expression.go
+++ b/hclsyntax/expression.go
@@ -1780,7 +1780,7 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
if sourceVal.IsNull() {
if autoUpgrade {
- return cty.EmptyTupleVal, diags
+ return cty.EmptyTupleVal.WithSameMarks(sourceVal), diags
}
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
@@ -1798,7 +1798,7 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
// If we don't even know the _type_ of our source value yet then
// we'll need to defer all processing, since we can't decide our
// result type either.
- return cty.DynamicVal, diags
+ return cty.DynamicVal.WithSameMarks(sourceVal), diags
}
upgradedUnknown := false
@@ -1813,13 +1813,14 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
// list of a single attribute, but we still need to check if that
// attribute actually exists.
if !sourceVal.IsKnown() {
- sourceRng := sourceVal.Range()
+ unmarkedVal, _ := sourceVal.Unmark()
+ sourceRng := unmarkedVal.Range()
if sourceRng.CouldBeNull() {
upgradedUnknown = true
}
}
- sourceVal = cty.TupleVal([]cty.Value{sourceVal})
+ sourceVal = cty.TupleVal([]cty.Value{sourceVal}).WithSameMarks(sourceVal)
sourceTy = sourceVal.Type()
}
@@ -1900,14 +1901,14 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
e.Item.clearValue(ctx) // clean up our temporary value
if upgradedUnknown {
- return cty.DynamicVal, diags
+ return cty.DynamicVal.WithMarks(marks), diags
}
if !isKnown {
// We'll ingore the resultTy diagnostics in this case since they
// will just be the same errors we saw while iterating above.
ty, _ := resultTy()
- return cty.UnknownVal(ty), diags
+ return cty.UnknownVal(ty).WithMarks(marks), diags
}
switch {
@@ -1915,7 +1916,7 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
if len(vals) == 0 {
ty, tyDiags := resultTy()
diags = append(diags, tyDiags...)
- return cty.ListValEmpty(ty.ElementType()), diags
+ return cty.ListValEmpty(ty.ElementType()).WithMarks(marks), diags
}
return cty.ListVal(vals).WithMarks(marks), diags
default:
diff --git a/hclsyntax/expression_test.go b/hclsyntax/expression_test.go
index b18214c..b50dc13 100644
--- a/hclsyntax/expression_test.go
+++ b/hclsyntax/expression_test.go
@@ -1457,6 +1457,16 @@ upper(
cty.UnknownVal(cty.List(cty.Bool)).RefineNotNull().Mark("sensitive"),
0,
},
+ { // splat with sensitive non-collection that's unknown
+ `not_a_list.*`,
+ &hcl.EvalContext{
+ Variables: map[string]cty.Value{
+ "not_a_list": cty.UnknownVal(cty.EmptyObject).RefineNotNull().Mark("sensitive"),
+ },
+ },
+ cty.TupleVal([]cty.Value{cty.UnknownVal(cty.EmptyObject).RefineNotNull().Mark("sensitive")}).Mark("sensitive"),
+ 0,
+ },
{ // splat with sensitive collection that's unknown and not null
`maps.*.enabled`,
&hcl.EvalContext{