mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-25 01:00:16 -05:00
lang/funcs: transpose fix panics with null elements
Previously the "transpose" function would panic if any of the given lists were null or if any of the strings inside the given lists were null. Null values _are_ invalid in those positions because we can't project null values into the keys of the resulting map, but we should return explicit error messages in those cases rather than causing a cty panic. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
@@ -16,6 +16,8 @@ import (
|
||||
"github.com/zclconf/go-cty/cty/function"
|
||||
"github.com/zclconf/go-cty/cty/function/stdlib"
|
||||
"github.com/zclconf/go-cty/cty/gocty"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
)
|
||||
|
||||
var LengthFunc = function.New(&function.Spec{
|
||||
@@ -578,13 +580,22 @@ var TransposeFunc = function.New(&function.Spec{
|
||||
outputMap := make(map[string]cty.Value)
|
||||
tmpMap := make(map[string][]string)
|
||||
|
||||
path := make(cty.Path, 0, 2) // we'll append a maximum of two path steps in the loop below
|
||||
for it := inputMap.ElementIterator(); it.Next(); {
|
||||
inKey, inVal := it.Element()
|
||||
keyPath := path.Index(inKey)
|
||||
if inVal.IsNull() {
|
||||
return cty.DynamicVal, function.NewArgErrorf(0, "cannot use null list for %s", tfdiags.FormatCtyPath(keyPath))
|
||||
}
|
||||
for iter := inVal.ElementIterator(); iter.Next(); {
|
||||
_, val := iter.Element()
|
||||
idx, val := iter.Element()
|
||||
idxPath := keyPath.Index(idx)
|
||||
if !val.Type().Equals(cty.String) {
|
||||
return cty.MapValEmpty(cty.List(cty.String)), errors.New("input must be a map of lists of strings")
|
||||
}
|
||||
if val.IsNull() {
|
||||
return cty.DynamicVal, function.NewArgErrorf(0, "cannot use null string for %s", tfdiags.FormatCtyPath(idxPath))
|
||||
}
|
||||
|
||||
outKey := val.AsString()
|
||||
if _, ok := tmpMap[outKey]; !ok {
|
||||
|
||||
@@ -1822,6 +1822,23 @@ func TestTranspose(t *testing.T) {
|
||||
}).WithMarks(cty.NewValueMarks("beep", "boop", "bloop")),
|
||||
false,
|
||||
},
|
||||
{ // Null value must be rejected because map keys cannot be null
|
||||
cty.MapVal(map[string]cty.Value{
|
||||
"key1": cty.ListVal([]cty.Value{
|
||||
cty.StringVal("a"),
|
||||
cty.NullVal(cty.String),
|
||||
}),
|
||||
}),
|
||||
cty.NilVal,
|
||||
true,
|
||||
},
|
||||
{ // Null list must be rejected, too
|
||||
cty.MapVal(map[string]cty.Value{
|
||||
"key1": cty.NullVal(cty.List(cty.String)),
|
||||
}),
|
||||
cty.NilVal,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
Reference in New Issue
Block a user