command: Fix missing force new for sensitive blocks

If an entire block is marked sensitive (possibly because it is of type
NestedSet) and results in replacement of the resource, we should render
the standard "forces replacement" text after the opening line of the
block.
This commit is contained in:
Alisdair McDiarmid 2020-10-07 10:50:54 -04:00
parent 79a3e33c4d
commit 62e6f56a50
2 changed files with 44 additions and 7 deletions

View File

@ -381,7 +381,7 @@ func (p *blockBodyDiffPrinter) writeNestedBlockDiffs(name string, blockS *config
// Display a special diff because it is irrelevant // Display a special diff because it is irrelevant
// to list all obfuscated attributes as (sensitive) // to list all obfuscated attributes as (sensitive)
if old.IsMarked() || new.IsMarked() { if old.IsMarked() || new.IsMarked() {
p.writeSensitiveNestedBlockDiff(name, old, new, indent, blankBefore) p.writeSensitiveNestedBlockDiff(name, old, new, indent, blankBefore, path)
return 0 return 0
} }
@ -589,7 +589,7 @@ func (p *blockBodyDiffPrinter) writeNestedBlockDiffs(name string, blockS *config
return skippedBlocks 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() unmarkedOld, _ := old.Unmark()
unmarkedNew, _ := new.Unmark() unmarkedNew, _ := new.Unmark()
eqV := unmarkedNew.Equals(unmarkedOld) eqV := unmarkedNew.Equals(unmarkedOld)
@ -618,6 +618,9 @@ func (p *blockBodyDiffPrinter) writeSensitiveNestedBlockDiff(name string, old, n
p.buf.WriteString(strings.Repeat(" ", indent)) p.buf.WriteString(strings.Repeat(" ", indent))
p.writeActionSymbol(action) p.writeActionSymbol(action)
fmt.Fprintf(p.buf, "%s {", name) 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.WriteRune('\n')
p.buf.WriteString(strings.Repeat(" ", indent+4)) p.buf.WriteString(strings.Repeat(" ", indent+4))
p.buf.WriteString("# At least one attribute in this block is (or was) sensitive,\n") p.buf.WriteString("# At least one attribute in this block is (or was) sensitive,\n")

View File

@ -4259,20 +4259,38 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
Before: cty.ObjectVal(map[string]cty.Value{ Before: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("i-02ae66f368e8518a9"), "id": cty.StringVal("i-02ae66f368e8518a9"),
"ami": cty.StringVal("ami-BEFORE"), "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{ After: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("i-02ae66f368e8518a9"), "id": cty.StringVal("i-02ae66f368e8518a9"),
"ami": cty.StringVal("ami-AFTER"), "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{ BeforeValMarks: []cty.PathValueMarks{
{ {
Path: cty.Path{cty.GetAttrStep{Name: "ami"}}, Path: cty.GetAttrPath("ami"),
Marks: cty.NewValueMarks("sensitive"),
},
{
Path: cty.GetAttrPath("nested_block_set"),
Marks: cty.NewValueMarks("sensitive"), Marks: cty.NewValueMarks("sensitive"),
}, },
}, },
AfterValMarks: []cty.PathValueMarks{ AfterValMarks: []cty.PathValueMarks{
{ {
Path: cty.Path{cty.GetAttrStep{Name: "ami"}}, Path: cty.GetAttrPath("ami"),
Marks: cty.NewValueMarks("sensitive"),
},
{
Path: cty.GetAttrPath("nested_block_set"),
Marks: cty.NewValueMarks("sensitive"), Marks: cty.NewValueMarks("sensitive"),
}, },
}, },
@ -4281,15 +4299,31 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
"id": {Type: cty.String, Optional: true, Computed: true}, "id": {Type: cty.String, Optional: true, Computed: true},
"ami": {Type: cty.String, Optional: 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},
}, },
RequiredReplace: cty.NewPathSet(cty.Path{ },
cty.GetAttrStep{Name: "ami"}, Nesting: configschema.NestingSet,
}), },
},
},
RequiredReplace: cty.NewPathSet(
cty.GetAttrPath("ami"),
cty.GetAttrPath("nested_block_set"),
),
Tainted: false, Tainted: false,
ExpectedOutput: ` # test_instance.example must be replaced ExpectedOutput: ` # test_instance.example must be replaced
-/+ resource "test_instance" "example" { -/+ resource "test_instance" "example" {
~ ami = (sensitive) # forces replacement ~ ami = (sensitive) # forces replacement
id = "i-02ae66f368e8518a9" 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.
}
} }
`, `,
}, },