diff --git a/terraform/evaluate.go b/terraform/evaluate.go index 4bf19fefc..6dde19700 100644 --- a/terraform/evaluate.go +++ b/terraform/evaluate.go @@ -979,12 +979,17 @@ func getValMarks(schema *configschema.Block, val cty.Value, path cty.Path) []cty if !blockS.Block.ContainsSensitive() { continue } + + blockV := val.GetAttr(name) + if blockV.IsNull() || !blockV.IsKnown() { + continue + } + // Create a copy of the path, with this step added, to add to our PathValueMarks slice blockPath := make(cty.Path, len(path), len(path)+1) copy(blockPath, path) blockPath = append(path, cty.GetAttrStep{Name: name}) - blockV := val.GetAttr(name) switch blockS.Nesting { case configschema.NestingSingle, configschema.NestingGroup: pvm = append(pvm, getValMarks(&blockS.Block, blockV, blockPath)...) diff --git a/terraform/evaluate_test.go b/terraform/evaluate_test.go index 7a96767f1..427b2291a 100644 --- a/terraform/evaluate_test.go +++ b/terraform/evaluate_test.go @@ -1,6 +1,7 @@ package terraform import ( + "fmt" "sync" "testing" @@ -550,3 +551,95 @@ func evaluatorForModule(stateSync *states.SyncState, changesSync *plans.ChangesS Changes: changesSync, } } + +func TestMarkProviderSensitive(t *testing.T) { + schema := &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "unsensitive": { + Type: cty.String, + Optional: true, + }, + "sensitive": { + Type: cty.String, + Sensitive: true, + }, + }, + + BlockTypes: map[string]*configschema.NestedBlock{ + "list": &configschema.NestedBlock{ + Nesting: configschema.NestingList, + Block: configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "unsensitive": { + Type: cty.String, + Optional: true, + }, + "sensitive": { + Type: cty.String, + Sensitive: true, + }, + }, + }, + }, + }, + } + + for _, tc := range []struct { + given cty.Value + expect cty.Value + }{ + { + cty.UnknownVal(schema.ImpliedType()), + cty.UnknownVal(schema.ImpliedType()), + }, + { + cty.ObjectVal(map[string]cty.Value{ + "sensitive": cty.UnknownVal(cty.String), + "unsensitive": cty.UnknownVal(cty.String), + "list": cty.UnknownVal(schema.BlockTypes["list"].ImpliedType()), + }), + cty.ObjectVal(map[string]cty.Value{ + "sensitive": cty.UnknownVal(cty.String).Mark("sensitive"), + "unsensitive": cty.UnknownVal(cty.String), + "list": cty.UnknownVal(schema.BlockTypes["list"].ImpliedType()), + }), + }, + { + cty.ObjectVal(map[string]cty.Value{ + "sensitive": cty.NullVal(cty.String), + "unsensitive": cty.UnknownVal(cty.String), + "list": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "sensitive": cty.UnknownVal(cty.String), + "unsensitive": cty.UnknownVal(cty.String), + }), + cty.ObjectVal(map[string]cty.Value{ + "sensitive": cty.NullVal(cty.String), + "unsensitive": cty.NullVal(cty.String), + }), + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "sensitive": cty.NullVal(cty.String).Mark("sensitive"), + "unsensitive": cty.UnknownVal(cty.String), + "list": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "sensitive": cty.UnknownVal(cty.String).Mark("sensitive"), + "unsensitive": cty.UnknownVal(cty.String), + }), + cty.ObjectVal(map[string]cty.Value{ + "sensitive": cty.NullVal(cty.String).Mark("sensitive"), + "unsensitive": cty.NullVal(cty.String), + }), + }), + }), + }, + } { + t.Run(fmt.Sprintf("%#v", tc.given), func(t *testing.T) { + got := markProviderSensitiveAttributes(schema, tc.given) + if !got.RawEquals(tc.expect) { + t.Fatalf("\nexpected: %#v\ngot: %#v\n", tc.expect, got) + } + }) + } +}