Skip to content

Commit 0fee440

Browse files
committed
fix: don't reveal nested attributes with sensitive schema
1 parent 980bf43 commit 0fee440

File tree

2 files changed

+152
-27
lines changed

2 files changed

+152
-27
lines changed

internal/command/format/diff.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ func (p *blockBodyDiffPrinter) writeAttrDiff(name string, attrS *configschema.At
398398
}
399399

400400
if attrS.NestedType != nil {
401-
p.writeNestedAttrDiff(name, attrS.NestedType, old, new, nameLen, indent, path, action, showJustNew)
401+
p.writeNestedAttrDiff(name, attrS, old, new, nameLen, indent, path, action, showJustNew)
402402
return false
403403
}
404404

@@ -441,9 +441,11 @@ func (p *blockBodyDiffPrinter) writeAttrDiff(name string, attrS *configschema.At
441441
// writeNestedAttrDiff is responsible for formatting Attributes with NestedTypes
442442
// in the diff.
443443
func (p *blockBodyDiffPrinter) writeNestedAttrDiff(
444-
name string, objS *configschema.Object, old, new cty.Value,
444+
name string, attrWithNestedS *configschema.Attribute, old, new cty.Value,
445445
nameLen, indent int, path cty.Path, action plans.Action, showJustNew bool) {
446446

447+
objS := attrWithNestedS.NestedType
448+
447449
p.buf.WriteString("\n")
448450
p.writeSensitivityWarning(old, new, indent, action, false)
449451
p.buf.WriteString(strings.Repeat(" ", indent))
@@ -454,11 +456,22 @@ func (p *blockBodyDiffPrinter) writeNestedAttrDiff(
454456
p.buf.WriteString(p.color.Color("[reset]"))
455457
p.buf.WriteString(strings.Repeat(" ", nameLen-len(name)))
456458

457-
if old.HasMark(marks.Sensitive) || new.HasMark(marks.Sensitive) {
458-
p.buf.WriteString(" = (sensitive value)")
459+
// Then schema of the attribute itself can be marked sensitive, or the values assigned
460+
sensitive := attrWithNestedS.Sensitive || old.HasMark(marks.Sensitive) || new.HasMark(marks.Sensitive)
461+
if sensitive {
462+
p.buf.WriteString(" = (sensitive")
463+
if attrWithNestedS.Sensitive {
464+
p.buf.WriteRune(')')
465+
} else {
466+
p.buf.WriteString(" value)")
467+
}
459468
if p.pathForcesNewResource(path) {
460469
p.buf.WriteString(p.color.Color(forcesNewResourceCaption))
461470
}
471+
472+
if new.IsNull() {
473+
p.buf.WriteString(p.color.Color("[dark_gray] -> null[reset]"))
474+
}
462475
return
463476
}
464477

internal/command/format/diff_test.go

Lines changed: 135 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2164,6 +2164,58 @@ func TestResourceChange_primitiveSet(t *testing.T) {
21642164
runTestCases(t, testCases)
21652165
}
21662166

2167+
func TestResourceChange_nested_attributes(t *testing.T) {
2168+
testCases := map[string]testCase{
2169+
"creation": {
2170+
Action: plans.Create,
2171+
Mode: addrs.ManagedResourceMode,
2172+
Before: cty.NullVal(cty.EmptyObject),
2173+
After: cty.ObjectVal(map[string]cty.Value{
2174+
"id": cty.UnknownVal(cty.String),
2175+
"nested_single": cty.ObjectVal(map[string]cty.Value{
2176+
"attr": cty.StringVal("hello"),
2177+
}),
2178+
"nested_list": cty.ListVal([]cty.Value{
2179+
cty.ObjectVal(map[string]cty.Value{
2180+
"attr": cty.StringVal("hello"),
2181+
}),
2182+
}),
2183+
}),
2184+
Schema: &configschema.Block{
2185+
Attributes: map[string]*configschema.Attribute{
2186+
"id": {Type: cty.String, Optional: true, Computed: true},
2187+
"nested_single": {NestedType: &configschema.Object{
2188+
Attributes: map[string]*configschema.Attribute{
2189+
"attr": {Type: cty.String, Optional: true},
2190+
},
2191+
Nesting: configschema.NestingSingle,
2192+
}, Optional: true},
2193+
"nested_list": {NestedType: &configschema.Object{
2194+
Attributes: map[string]*configschema.Attribute{
2195+
"attr": {Type: cty.String, Optional: true},
2196+
},
2197+
Nesting: configschema.NestingList,
2198+
}},
2199+
},
2200+
},
2201+
ExpectedOutput: ` # test_instance.example will be created
2202+
+ resource "test_instance" "example" {
2203+
+ id = (known after apply)
2204+
+ nested_list = [
2205+
+ {
2206+
+ attr = "hello"
2207+
},
2208+
]
2209+
+ nested_single = {
2210+
+ attr = "hello"
2211+
}
2212+
}
2213+
`,
2214+
},
2215+
}
2216+
runTestCases(t, testCases)
2217+
}
2218+
21672219
func TestResourceChange_map(t *testing.T) {
21682220
testCases := map[string]testCase{
21692221
"in-place update - creation": {
@@ -4829,6 +4881,9 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
48294881
"another": cty.StringVal("not secret"),
48304882
}),
48314883
}),
4884+
"nested_sensitive": cty.ObjectVal(map[string]cty.Value{
4885+
"an_attr": cty.StringVal("secret because nested_sensitive is sensitive"),
4886+
}),
48324887
}),
48334888
AfterValMarks: []cty.PathValueMarks{
48344889
{
@@ -4865,6 +4920,12 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
48654920
"map_whole": {Type: cty.Map(cty.String), Optional: true},
48664921
"map_key": {Type: cty.Map(cty.Number), Optional: true},
48674922
"list_field": {Type: cty.List(cty.String), Optional: true},
4923+
"nested_sensitive": {NestedType: &configschema.Object{
4924+
Attributes: map[string]*configschema.Attribute{
4925+
"an_attr": {Type: cty.String, Optional: true},
4926+
},
4927+
Nesting: configschema.NestingSingle,
4928+
}, Sensitive: true},
48684929
},
48694930
BlockTypes: map[string]*configschema.NestedBlock{
48704931
"nested_block_list": {
@@ -4889,18 +4950,19 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
48894950
},
48904951
ExpectedOutput: ` # test_instance.example will be created
48914952
+ resource "test_instance" "example" {
4892-
+ ami = (sensitive)
4893-
+ id = "i-02ae66f368e8518a9"
4894-
+ list_field = [
4953+
+ ami = (sensitive)
4954+
+ id = "i-02ae66f368e8518a9"
4955+
+ list_field = [
48954956
+ "hello",
48964957
+ (sensitive),
48974958
+ "!",
48984959
]
4899-
+ map_key = {
4960+
+ map_key = {
49004961
+ "breakfast" = 800
49014962
+ "dinner" = (sensitive)
49024963
}
4903-
+ map_whole = (sensitive)
4964+
+ map_whole = (sensitive)
4965+
+ nested_sensitive = (sensitive)
49044966
49054967
+ nested_block_list {
49064968
# At least one attribute in this block is (or was) sensitive,
@@ -4945,6 +5007,9 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
49455007
"an_attr": cty.StringVal("secretval"),
49465008
}),
49475009
}),
5010+
"nested_sensitive": cty.ObjectVal(map[string]cty.Value{
5011+
"an_attr": cty.StringVal("secret because nested_sensitive is sensitive"),
5012+
}),
49485013
}),
49495014
After: cty.ObjectVal(map[string]cty.Value{
49505015
"id": cty.StringVal("i-02ae66f368e8518a9"),
@@ -4974,6 +5039,9 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
49745039
"an_attr": cty.StringVal("changed"),
49755040
}),
49765041
}),
5042+
"nested_sensitive": cty.ObjectVal(map[string]cty.Value{
5043+
"an_attr": cty.StringVal("changed"),
5044+
}),
49775045
}),
49785046
BeforeValMarks: []cty.PathValueMarks{
49795047
{
@@ -5019,6 +5087,12 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
50195087
"some_number": {Type: cty.Number, Optional: true},
50205088
"map_key": {Type: cty.Map(cty.Number), Optional: true},
50215089
"map_whole": {Type: cty.Map(cty.String), Optional: true},
5090+
"nested_sensitive": {NestedType: &configschema.Object{
5091+
Attributes: map[string]*configschema.Attribute{
5092+
"an_attr": {Type: cty.String, Optional: true},
5093+
},
5094+
Nesting: configschema.NestingSingle,
5095+
}, Sensitive: true},
50225096
},
50235097
BlockTypes: map[string]*configschema.NestedBlock{
50245098
"nested_block": {
@@ -5043,29 +5117,30 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
50435117
~ resource "test_instance" "example" {
50445118
# Warning: this attribute value will no longer be marked as sensitive
50455119
# after applying this change.
5046-
~ ami = (sensitive)
5047-
id = "i-02ae66f368e8518a9"
5048-
~ list_field = [
5120+
~ ami = (sensitive)
5121+
id = "i-02ae66f368e8518a9"
5122+
~ list_field = [
50495123
# (1 unchanged element hidden)
50505124
"friends",
50515125
- (sensitive),
50525126
+ ".",
50535127
]
5054-
~ map_key = {
5128+
~ map_key = {
50555129
# Warning: this attribute value will no longer be marked as sensitive
50565130
# after applying this change.
50575131
~ "dinner" = (sensitive)
50585132
# (1 unchanged element hidden)
50595133
}
50605134
# Warning: this attribute value will no longer be marked as sensitive
50615135
# after applying this change.
5062-
~ map_whole = (sensitive)
5136+
~ map_whole = (sensitive)
5137+
~ nested_sensitive = (sensitive)
50635138
# Warning: this attribute value will no longer be marked as sensitive
50645139
# after applying this change.
5065-
~ some_number = (sensitive)
5140+
~ some_number = (sensitive)
50665141
# Warning: this attribute value will no longer be marked as sensitive
50675142
# after applying this change.
5068-
~ special = (sensitive)
5143+
~ special = (sensitive)
50695144
50705145
# Warning: this block will no longer be marked as sensitive
50715146
# after applying this change.
@@ -5103,6 +5178,9 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
51035178
"nested_block_single": cty.ObjectVal(map[string]cty.Value{
51045179
"an_attr": cty.StringVal("original"),
51055180
}),
5181+
"nested_sensitive": cty.ObjectVal(map[string]cty.Value{
5182+
"an_attr": cty.StringVal("secret because nested_sensitive is sensitive"),
5183+
}),
51065184
}),
51075185
After: cty.ObjectVal(map[string]cty.Value{
51085186
"id": cty.StringVal("i-02ae66f368e8518a9"),
@@ -5121,6 +5199,9 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
51215199
"nested_block_single": cty.ObjectVal(map[string]cty.Value{
51225200
"an_attr": cty.StringVal("changed"),
51235201
}),
5202+
"nested_sensitive": cty.ObjectVal(map[string]cty.Value{
5203+
"an_attr": cty.StringVal("changed"),
5204+
}),
51245205
}),
51255206
AfterValMarks: []cty.PathValueMarks{
51265207
{
@@ -5151,6 +5232,12 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
51515232
"list_field": {Type: cty.List(cty.String), Optional: true},
51525233
"map_key": {Type: cty.Map(cty.Number), Optional: true},
51535234
"map_whole": {Type: cty.Map(cty.String), Optional: true},
5235+
"nested_sensitive": {NestedType: &configschema.Object{
5236+
Attributes: map[string]*configschema.Attribute{
5237+
"an_attr": {Type: cty.String, Optional: true},
5238+
},
5239+
Nesting: configschema.NestingSingle,
5240+
}, Sensitive: true},
51545241
},
51555242
BlockTypes: map[string]*configschema.NestedBlock{
51565243
"nested_block_single": {
@@ -5165,21 +5252,22 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
51655252
},
51665253
ExpectedOutput: ` # test_instance.example will be updated in-place
51675254
~ resource "test_instance" "example" {
5168-
id = "i-02ae66f368e8518a9"
5169-
~ list_field = [
5255+
id = "i-02ae66f368e8518a9"
5256+
~ list_field = [
51705257
- "hello",
51715258
+ (sensitive),
51725259
"friends",
51735260
]
5174-
~ map_key = {
5261+
~ map_key = {
51755262
~ "breakfast" = 800 -> 700
51765263
# Warning: this attribute value will be marked as sensitive and will not
51775264
# display in UI output after applying this change.
51785265
~ "dinner" = (sensitive)
51795266
}
51805267
# Warning: this attribute value will be marked as sensitive and will not
51815268
# display in UI output after applying this change.
5182-
~ map_whole = (sensitive)
5269+
~ map_whole = (sensitive)
5270+
~ nested_sensitive = (sensitive)
51835271
51845272
# Warning: this block will be marked as sensitive and will not
51855273
# display in UI output after applying this change.
@@ -5520,6 +5608,9 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
55205608
"another": cty.StringVal("not secret"),
55215609
}),
55225610
}),
5611+
"nested_sensitive": cty.ObjectVal(map[string]cty.Value{
5612+
"an_attr": cty.StringVal("secret because nested_sensitive is sensitive"),
5613+
}),
55235614
}),
55245615
After: cty.NullVal(cty.EmptyObject),
55255616
BeforeValMarks: []cty.PathValueMarks{
@@ -5556,6 +5647,12 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
55565647
"list_field": {Type: cty.List(cty.String), Optional: true},
55575648
"map_key": {Type: cty.Map(cty.Number), Optional: true},
55585649
"map_whole": {Type: cty.Map(cty.String), Optional: true},
5650+
"nested_sensitive": {NestedType: &configschema.Object{
5651+
Attributes: map[string]*configschema.Attribute{
5652+
"an_attr": {Type: cty.String, Optional: true},
5653+
},
5654+
Nesting: configschema.NestingSingle,
5655+
}, Sensitive: true},
55595656
},
55605657
BlockTypes: map[string]*configschema.NestedBlock{
55615658
"nested_block_set": {
@@ -5571,17 +5668,18 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
55715668
},
55725669
ExpectedOutput: ` # test_instance.example will be destroyed
55735670
- resource "test_instance" "example" {
5574-
- ami = (sensitive) -> null
5575-
- id = "i-02ae66f368e8518a9" -> null
5576-
- list_field = [
5671+
- ami = (sensitive) -> null
5672+
- id = "i-02ae66f368e8518a9" -> null
5673+
- list_field = [
55775674
- "hello",
55785675
- (sensitive),
55795676
] -> null
5580-
- map_key = {
5677+
- map_key = {
55815678
- "breakfast" = 800
55825679
- "dinner" = (sensitive)
55835680
} -> null
5584-
- map_whole = (sensitive) -> null
5681+
- map_whole = (sensitive) -> null
5682+
- nested_sensitive = (sensitive) -> null
55855683
55865684
- nested_block_set {
55875685
# At least one attribute in this block is (or was) sensitive,
@@ -5601,6 +5699,9 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
56015699
"an_attr": cty.StringVal("secret"),
56025700
}),
56035701
}),
5702+
"nested_sensitive": cty.ObjectVal(map[string]cty.Value{
5703+
"an_attr": cty.StringVal("secret because nested_sensitive is sensitive"),
5704+
}),
56045705
}),
56055706
After: cty.ObjectVal(map[string]cty.Value{
56065707
"id": cty.StringVal("i-02ae66f368e8518a9"),
@@ -5610,6 +5711,9 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
56105711
"an_attr": cty.StringVal("changed"),
56115712
}),
56125713
}),
5714+
"nested_sensitive": cty.ObjectVal(map[string]cty.Value{
5715+
"an_attr": cty.StringVal("changed"),
5716+
}),
56135717
}),
56145718
BeforeValMarks: []cty.PathValueMarks{
56155719
{
@@ -5635,6 +5739,12 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
56355739
Attributes: map[string]*configschema.Attribute{
56365740
"id": {Type: cty.String, Optional: true, Computed: true},
56375741
"ami": {Type: cty.String, Optional: true},
5742+
"nested_sensitive": {NestedType: &configschema.Object{
5743+
Attributes: map[string]*configschema.Attribute{
5744+
"an_attr": {Type: cty.String, Optional: true},
5745+
},
5746+
Nesting: configschema.NestingSingle,
5747+
}, Sensitive: true},
56385748
},
56395749
BlockTypes: map[string]*configschema.NestedBlock{
56405750
"nested_block_set": {
@@ -5650,11 +5760,13 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
56505760
RequiredReplace: cty.NewPathSet(
56515761
cty.GetAttrPath("ami"),
56525762
cty.GetAttrPath("nested_block_set"),
5763+
cty.GetAttrPath("nested_sensitive"),
56535764
),
56545765
ExpectedOutput: ` # test_instance.example must be replaced
56555766
-/+ resource "test_instance" "example" {
5656-
~ ami = (sensitive) # forces replacement
5657-
id = "i-02ae66f368e8518a9"
5767+
~ ami = (sensitive) # forces replacement
5768+
id = "i-02ae66f368e8518a9"
5769+
~ nested_sensitive = (sensitive) # forces replacement
56585770
56595771
~ nested_block_set { # forces replacement
56605772
# At least one attribute in this block is (or was) sensitive,

0 commit comments

Comments
 (0)