diff --git a/command/format/diff.go b/command/format/diff.go index 920229f0e0..126d5ddbb7 100644 --- a/command/format/diff.go +++ b/command/format/diff.go @@ -381,7 +381,7 @@ func (p *blockBodyDiffPrinter) writeNestedBlockDiffs(name string, blockS *config // Display a special diff because it is irrelevant // to list all obfuscated attributes as (sensitive) if old.IsMarked() || new.IsMarked() { - p.writeSensitiveNestedBlockDiff(name, old, new, indent, blankBefore) + p.writeSensitiveNestedBlockDiff(name, old, new, indent, blankBefore, path) return 0 } @@ -589,7 +589,7 @@ func (p *blockBodyDiffPrinter) writeNestedBlockDiffs(name string, blockS *config return skippedBlocks } -func (p *blockBodyDiffPrinter) writeSensitiveNestedBlockDiff(name string, old, new cty.Value, indent int, blankBefore bool) { +func (p *blockBodyDiffPrinter) writeSensitiveNestedBlockDiff(name string, old, new cty.Value, indent int, blankBefore bool, path cty.Path) { unmarkedOld, _ := old.Unmark() unmarkedNew, _ := new.Unmark() eqV := unmarkedNew.Equals(unmarkedOld) @@ -618,6 +618,9 @@ func (p *blockBodyDiffPrinter) writeSensitiveNestedBlockDiff(name string, old, n p.buf.WriteString(strings.Repeat(" ", indent)) p.writeActionSymbol(action) fmt.Fprintf(p.buf, "%s {", name) + if action != plans.NoOp && p.pathForcesNewResource(path) { + p.buf.WriteString(p.color.Color(forcesNewResourceCaption)) + } p.buf.WriteRune('\n') p.buf.WriteString(strings.Repeat(" ", indent+4)) p.buf.WriteString("# At least one attribute in this block is (or was) sensitive,\n") @@ -827,6 +830,9 @@ func (p *blockBodyDiffPrinter) writeValueDiff(old, new cty.Value, indent int, pa if old.IsKnown() && new.IsKnown() && !old.IsNull() && !new.IsNull() && typesEqual { if old.IsMarked() || new.IsMarked() { p.buf.WriteString("(sensitive)") + if p.pathForcesNewResource(path) { + p.buf.WriteString(p.color.Color(forcesNewResourceCaption)) + } return } diff --git a/command/format/diff_test.go b/command/format/diff_test.go index 55c53e8e1b..b3ba9af76e 100644 --- a/command/format/diff_test.go +++ b/command/format/diff_test.go @@ -4251,6 +4251,80 @@ func TestResourceChange_sensitiveVariable(t *testing.T) { # so its contents will not be displayed. } } +`, + }, + "update with sensitive value forcing replacement": { + Action: plans.DeleteThenCreate, + Mode: addrs.ManagedResourceMode, + Before: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("i-02ae66f368e8518a9"), + "ami": cty.StringVal("ami-BEFORE"), + "nested_block_set": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "an_attr": cty.StringVal("secret"), + }), + }), + }), + After: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("i-02ae66f368e8518a9"), + "ami": cty.StringVal("ami-AFTER"), + "nested_block_set": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "an_attr": cty.StringVal("changed"), + }), + }), + }), + BeforeValMarks: []cty.PathValueMarks{ + { + Path: cty.GetAttrPath("ami"), + Marks: cty.NewValueMarks("sensitive"), + }, + { + Path: cty.GetAttrPath("nested_block_set"), + Marks: cty.NewValueMarks("sensitive"), + }, + }, + AfterValMarks: []cty.PathValueMarks{ + { + Path: cty.GetAttrPath("ami"), + Marks: cty.NewValueMarks("sensitive"), + }, + { + Path: cty.GetAttrPath("nested_block_set"), + Marks: cty.NewValueMarks("sensitive"), + }, + }, + Schema: &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "id": {Type: cty.String, Optional: true, Computed: true}, + "ami": {Type: cty.String, Optional: true}, + }, + BlockTypes: map[string]*configschema.NestedBlock{ + "nested_block_set": { + Block: configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "an_attr": {Type: cty.String, Required: true}, + }, + }, + Nesting: configschema.NestingSet, + }, + }, + }, + RequiredReplace: cty.NewPathSet( + cty.GetAttrPath("ami"), + cty.GetAttrPath("nested_block_set"), + ), + Tainted: false, + ExpectedOutput: ` # test_instance.example must be replaced +-/+ resource "test_instance" "example" { + ~ ami = (sensitive) # forces replacement + id = "i-02ae66f368e8518a9" + + ~ nested_block_set { # forces replacement + # At least one attribute in this block is (or was) sensitive, + # so its contents will not be displayed. + } + } `, }, }