From 9d0decad45d3bd76a010590458ed51017c854b97 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Fri, 14 May 2021 14:02:24 -0400 Subject: [PATCH] function/stdlib: flatten allows objects containing unknown types Using HasDynamicTypes to see if the Flatten argument's type will be unknown is a little too conservative, and will also catch dynamic values within maps and objects. Check each value as we're iterating to find any dynamic values. --- cty/function/stdlib/collection.go | 12 +++--- cty/function/stdlib/collection_test.go | 52 +++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/cty/function/stdlib/collection.go b/cty/function/stdlib/collection.go index dbfd46d0..1f599c85 100644 --- a/cty/function/stdlib/collection.go +++ b/cty/function/stdlib/collection.go @@ -530,16 +530,18 @@ func flattener(flattenList cty.Value) ([]cty.Value, []cty.ValueMarks, bool) { // predict the length of our result yet either. return nil, markses, false } - // Any dynamic types could result in more collection that need to be - // flattened, so the type cannot be known. - if flattenList.Type().HasDynamicTypes() { - return nil, markses, false - } out := make([]cty.Value, 0) isKnown := true for it := flattenList.ElementIterator(); it.Next(); { _, val := it.Element() + + // Any dynamic types could result in more collections that need to be + // flattened, so the type cannot be known. + if val.Type().Equals(cty.DynamicPseudoType) { + isKnown = false + } + if val.Type().IsListType() || val.Type().IsSetType() || val.Type().IsTupleType() { if !val.IsKnown() { isKnown = false diff --git a/cty/function/stdlib/collection_test.go b/cty/function/stdlib/collection_test.go index be155526..4d9a2163 100644 --- a/cty/function/stdlib/collection_test.go +++ b/cty/function/stdlib/collection_test.go @@ -1953,7 +1953,57 @@ func TestFlatten(t *testing.T) { }).Mark("marked"), }), }), - cty.DynamicVal, + cty.DynamicVal.Mark("marked"), + "", + }, + { + cty.TupleVal([]cty.Value{ + cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "blop": cty.ListVal([]cty.Value{ + cty.DynamicVal, + }), + }), + }), + cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "bloop": cty.DynamicVal, + }), + }), + }), + cty.TupleVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "blop": cty.ListVal([]cty.Value{ + cty.DynamicVal, + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "bloop": cty.DynamicVal, + }), + }), + "", + }, + { + cty.ListVal([]cty.Value{ + cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "bloop": cty.DynamicVal, + }), + }), + cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "bloop": cty.DynamicVal, + }), + }), + }), + cty.TupleVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "bloop": cty.DynamicVal, + }), + cty.ObjectVal(map[string]cty.Value{ + "bloop": cty.DynamicVal, + }), + }), "", }, {