From e6daf3dbf1faeae8a8728d5f2d2fdd1ccaf86ef5 Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 29 Jan 2021 14:28:09 -0500 Subject: [PATCH] Unmark before ElementIterator in couldHaveUnknownBlockPlaceholder This is needed for cases where a variable may be fetched and become a member of a set, and thus the whole set is marked, which means ElementIterator will panic on unmarked values --- plans/objchange/compatible.go | 4 +++ plans/objchange/compatible_test.go | 43 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/plans/objchange/compatible.go b/plans/objchange/compatible.go index 6d92fca4d..efb4023d2 100644 --- a/plans/objchange/compatible.go +++ b/plans/objchange/compatible.go @@ -357,6 +357,10 @@ func couldHaveUnknownBlockPlaceholder(v cty.Value, blockS *configschema.NestedBl return false // treated as if the list were empty, so we would see zero iterations below } + // Unmark before we call ElementIterator in case this iterable is marked sensitive. + // This can arise in the case where a member of a Set is sensitive, and thus the + // whole Set is marked sensitive + v, _ := v.Unmark() // For all other nesting modes, our value should be something iterable. for it := v.ElementIterator(); it.Next(); { _, ev := it.Element() diff --git a/plans/objchange/compatible_test.go b/plans/objchange/compatible_test.go index 9a6924441..ac3793674 100644 --- a/plans/objchange/compatible_test.go +++ b/plans/objchange/compatible_test.go @@ -194,6 +194,49 @@ func TestAssertObjectCompatible(t *testing.T) { `.name: inconsistent values for sensitive attribute`, }, }, + { + // This tests the codepath that leads to couldHaveUnknownBlockPlaceholder, + // where a set may be sensitive and need to be unmarked before it + // is iterated upon + &configschema.Block{ + BlockTypes: map[string]*configschema.NestedBlock{ + "configuration": { + Nesting: configschema.NestingList, + Block: configschema.Block{ + BlockTypes: map[string]*configschema.NestedBlock{ + "sensitive_fields": { + Nesting: configschema.NestingSet, + Block: schemaWithFoo, + }, + }, + }, + }, + }, + }, + cty.ObjectVal(map[string]cty.Value{ + "configuration": cty.TupleVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "sensitive_fields": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("secret"), + }), + }).Mark("sensitive"), + }), + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "configuration": cty.TupleVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "sensitive_fields": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("secret"), + }), + }).Mark("sensitive"), + }), + }), + }), + nil, + }, { &configschema.Block{ Attributes: map[string]*configschema.Attribute{