Merge pull request #26373 from hashicorp/pselle/sensitive-vals-list

Support list diffs with sensitivity
This commit is contained in:
Pam Selle 2020-09-25 13:46:37 -04:00 committed by GitHub
commit 40ea3f4cb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 162 additions and 28 deletions

View File

@ -3631,28 +3631,44 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
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-123"), "ami": cty.StringVal("ami-123"),
"list_field": cty.ListVal([]cty.Value{
cty.StringVal("hello"),
cty.StringVal("friends"),
cty.StringVal("!"),
}),
}), }),
AfterValMarks: []cty.PathValueMarks{ AfterValMarks: []cty.PathValueMarks{
{ {
Path: cty.Path{cty.GetAttrStep{Name: "ami"}}, Path: cty.Path{cty.GetAttrStep{Name: "ami"}},
Marks: cty.NewValueMarks("sensitive"), Marks: cty.NewValueMarks("sensitive"),
}}, },
{
Path: cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(1)}},
Marks: cty.NewValueMarks("sensitive"),
},
},
RequiredReplace: cty.NewPathSet(), RequiredReplace: cty.NewPathSet(),
Tainted: false, Tainted: false,
Schema: &configschema.Block{ Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{ Attributes: map[string]*configschema.Attribute{
"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},
"list_field": {Type: cty.List(cty.String), Optional: true},
}, },
}, },
ExpectedOutput: ` # test_instance.example will be created ExpectedOutput: ` # test_instance.example will be created
+ resource "test_instance" "example" { + resource "test_instance" "example" {
+ ami = (sensitive) + ami = (sensitive)
+ id = "i-02ae66f368e8518a9" + id = "i-02ae66f368e8518a9"
+ list_field = [
+ "hello",
+ (sensitive),
+ "!",
]
} }
`, `,
}, },
"in-place update - before sensitive, primitive types": { "in-place update - before sensitive": {
Action: plans.Update, Action: plans.Update,
Mode: addrs.ManagedResourceMode, Mode: addrs.ManagedResourceMode,
Before: cty.ObjectVal(map[string]cty.Value{ Before: cty.ObjectVal(map[string]cty.Value{
@ -3660,12 +3676,22 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
"ami": cty.StringVal("ami-BEFORE"), "ami": cty.StringVal("ami-BEFORE"),
"special": cty.BoolVal(true), "special": cty.BoolVal(true),
"some_number": cty.NumberIntVal(1), "some_number": cty.NumberIntVal(1),
"list_field": cty.ListVal([]cty.Value{
cty.StringVal("hello"),
cty.StringVal("friends"),
cty.StringVal("!"),
}),
}), }),
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"),
"special": cty.BoolVal(false), "special": cty.BoolVal(false),
"some_number": cty.NumberIntVal(2), "some_number": cty.NumberIntVal(2),
"list_field": cty.ListVal([]cty.Value{
cty.StringVal("hello"),
cty.StringVal("friends"),
cty.StringVal("."),
}),
}), }),
BeforeValMarks: []cty.PathValueMarks{ BeforeValMarks: []cty.PathValueMarks{
{ {
@ -3680,6 +3706,10 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
Path: cty.Path{cty.GetAttrStep{Name: "some_number"}}, Path: cty.Path{cty.GetAttrStep{Name: "some_number"}},
Marks: cty.NewValueMarks("sensitive"), Marks: cty.NewValueMarks("sensitive"),
}, },
{
Path: cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(2)}},
Marks: cty.NewValueMarks("sensitive"),
},
}, },
RequiredReplace: cty.NewPathSet(), RequiredReplace: cty.NewPathSet(),
Tainted: false, Tainted: false,
@ -3687,6 +3717,7 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
Attributes: map[string]*configschema.Attribute{ Attributes: map[string]*configschema.Attribute{
"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},
"list_field": {Type: cty.List(cty.String), Optional: true},
"special": {Type: cty.Bool, Optional: true}, "special": {Type: cty.Bool, Optional: true},
"some_number": {Type: cty.Number, Optional: true}, "some_number": {Type: cty.Number, Optional: true},
}, },
@ -3697,6 +3728,12 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
# after applying this change # after applying this change
~ ami = (sensitive) ~ ami = (sensitive)
id = "i-02ae66f368e8518a9" id = "i-02ae66f368e8518a9"
~ list_field = [
# (1 unchanged element hidden)
"friends",
- (sensitive),
+ ".",
]
# Warning: this attribute value will no longer be marked as sensitive # Warning: this attribute value will no longer be marked as sensitive
# after applying this change # after applying this change
~ some_number = (sensitive) ~ some_number = (sensitive)
@ -3706,41 +3743,63 @@ func TestResourceChange_sensitiveVariable(t *testing.T) {
} }
`, `,
}, },
"in-place update - after sensitive, map type": { "in-place update - after sensitive": {
Action: plans.Update, Action: plans.Update,
Mode: addrs.ManagedResourceMode, Mode: addrs.ManagedResourceMode,
Before: cty.ObjectVal(map[string]cty.Value{ Before: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("i-02ae66f368e8518a9"), "id": cty.StringVal("i-02ae66f368e8518a9"),
"tags": cty.MapVal(map[string]cty.Value{ "tags": cty.MapVal(map[string]cty.Value{
"name": cty.StringVal("anna"), "name": cty.StringVal("anna a"),
"address": cty.StringVal("123 Main St"),
}),
"list_field": cty.ListVal([]cty.Value{
cty.StringVal("hello"),
cty.StringVal("friends"),
}), }),
}), }),
After: cty.ObjectVal(map[string]cty.Value{ After: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("i-02ae66f368e8518a9"), "id": cty.StringVal("i-02ae66f368e8518a9"),
"tags": cty.MapVal(map[string]cty.Value{ "tags": cty.MapVal(map[string]cty.Value{
"name": cty.StringVal("bob"), "name": cty.StringVal("anna b"),
"address": cty.StringVal("123 Main Ave"),
}),
"list_field": cty.ListVal([]cty.Value{
cty.StringVal("goodbye"),
cty.StringVal("friends"),
}), }),
}), }),
AfterValMarks: []cty.PathValueMarks{ AfterValMarks: []cty.PathValueMarks{
{ {
Path: cty.Path{cty.GetAttrStep{Name: "tags"}, cty.IndexStep{Key: cty.StringVal("name")}}, Path: cty.Path{cty.GetAttrStep{Name: "tags"}, cty.IndexStep{Key: cty.StringVal("address")}},
Marks: cty.NewValueMarks("sensitive"), Marks: cty.NewValueMarks("sensitive"),
}}, },
{
Path: cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(0)}},
Marks: cty.NewValueMarks("sensitive"),
},
},
RequiredReplace: cty.NewPathSet(), RequiredReplace: cty.NewPathSet(),
Tainted: false, Tainted: false,
Schema: &configschema.Block{ Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{ Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Optional: true, Computed: true}, "id": {Type: cty.String, Optional: true, Computed: true},
"tags": {Type: cty.Map(cty.String), Optional: true}, "tags": {Type: cty.Map(cty.String), Optional: true},
"list_field": {Type: cty.List(cty.String), Optional: true},
}, },
}, },
ExpectedOutput: ` # test_instance.example will be updated in-place ExpectedOutput: ` # test_instance.example will be updated in-place
~ resource "test_instance" "example" { ~ resource "test_instance" "example" {
id = "i-02ae66f368e8518a9" id = "i-02ae66f368e8518a9"
~ tags = { ~ list_field = [
- "hello",
+ (sensitive),
"friends",
]
~ tags = {
# Warning: this attribute value will be marked as sensitive and will # Warning: this attribute value will be marked as sensitive and will
# not display in UI output after applying this change # not display in UI output after applying this change
~ "name" = (sensitive) ~ "address" = (sensitive)
~ "name" = "anna a" -> "anna b"
} }
} }
`, `,
@ -3751,33 +3810,57 @@ 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"),
"list_field": cty.ListVal([]cty.Value{
cty.StringVal("hello"),
cty.StringVal("friends"),
}),
}), }),
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"),
"list_field": cty.ListVal([]cty.Value{
cty.StringVal("goodbye"),
cty.StringVal("friends"),
}),
}), }),
BeforeValMarks: []cty.PathValueMarks{ BeforeValMarks: []cty.PathValueMarks{
{ {
Path: cty.Path{cty.GetAttrStep{Name: "ami"}}, Path: cty.Path{cty.GetAttrStep{Name: "ami"}},
Marks: cty.NewValueMarks("sensitive"), Marks: cty.NewValueMarks("sensitive"),
}}, },
{
Path: cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(0)}},
Marks: cty.NewValueMarks("sensitive"),
},
},
AfterValMarks: []cty.PathValueMarks{ AfterValMarks: []cty.PathValueMarks{
{ {
Path: cty.Path{cty.GetAttrStep{Name: "ami"}}, Path: cty.Path{cty.GetAttrStep{Name: "ami"}},
Marks: cty.NewValueMarks("sensitive"), Marks: cty.NewValueMarks("sensitive"),
}}, },
{
Path: cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(0)}},
Marks: cty.NewValueMarks("sensitive"),
},
},
RequiredReplace: cty.NewPathSet(), RequiredReplace: cty.NewPathSet(),
Tainted: false, Tainted: false,
Schema: &configschema.Block{ Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{ Attributes: map[string]*configschema.Attribute{
"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},
"list_field": {Type: cty.List(cty.String), Optional: true},
}, },
}, },
ExpectedOutput: ` # test_instance.example will be updated in-place ExpectedOutput: ` # test_instance.example will be updated in-place
~ resource "test_instance" "example" { ~ resource "test_instance" "example" {
~ ami = (sensitive) ~ ami = (sensitive)
id = "i-02ae66f368e8518a9" id = "i-02ae66f368e8518a9"
~ list_field = [
- (sensitive),
+ (sensitive),
"friends",
]
} }
`, `,
}, },
@ -3787,25 +3870,39 @@ 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"),
"list_field": cty.ListVal([]cty.Value{
cty.StringVal("hello"),
cty.StringVal("friends"),
}),
}), }),
After: cty.NullVal(cty.EmptyObject), After: cty.NullVal(cty.EmptyObject),
BeforeValMarks: []cty.PathValueMarks{ BeforeValMarks: []cty.PathValueMarks{
{ {
Path: cty.Path{cty.GetAttrStep{Name: "ami"}}, Path: cty.Path{cty.GetAttrStep{Name: "ami"}},
Marks: cty.NewValueMarks("sensitive"), Marks: cty.NewValueMarks("sensitive"),
}}, },
{
Path: cty.Path{cty.GetAttrStep{Name: "list_field"}, cty.IndexStep{Key: cty.NumberIntVal(1)}},
Marks: cty.NewValueMarks("sensitive"),
},
},
RequiredReplace: cty.NewPathSet(), RequiredReplace: cty.NewPathSet(),
Tainted: false, Tainted: false,
Schema: &configschema.Block{ Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{ Attributes: map[string]*configschema.Attribute{
"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},
"list_field": {Type: cty.List(cty.String), Optional: true},
}, },
}, },
ExpectedOutput: ` # test_instance.example will be destroyed ExpectedOutput: ` # test_instance.example will be destroyed
- resource "test_instance" "example" { - resource "test_instance" "example" {
- ami = (sensitive) -> null - ami = (sensitive) -> null
- id = "i-02ae66f368e8518a9" -> null - id = "i-02ae66f368e8518a9" -> null
- list_field = [
- "hello",
- (sensitive),
] -> null
} }
`, `,
}, },

View File

@ -26,7 +26,12 @@ func LongestCommonSubsequence(xs, ys []cty.Value) []cty.Value {
for y := 0; y < len(ys); y++ { for y := 0; y < len(ys); y++ {
for x := 0; x < len(xs); x++ { for x := 0; x < len(xs); x++ {
eqV := xs[x].Equals(ys[y]) unmarkedX, xMarks := xs[x].UnmarkDeep()
unmarkedY, yMarks := ys[y].UnmarkDeep()
eqV := unmarkedX.Equals(unmarkedY)
if len(xMarks) != len(yMarks) {
eqV = cty.False
}
eq := false eq := false
if eqV.IsKnown() && eqV.True() { if eqV.IsKnown() && eqV.True() {
eq = true eq = true

View File

@ -70,6 +70,38 @@ func TestLongestCommonSubsequence(t *testing.T) {
[]cty.Value{cty.UnknownVal(cty.Number)}, []cty.Value{cty.UnknownVal(cty.Number)},
[]cty.Value{}, []cty.Value{},
}, },
// marked values
{
[]cty.Value{cty.NumberIntVal(1).Mark("foo"), cty.NumberIntVal(2).Mark("foo"), cty.NumberIntVal(3)},
[]cty.Value{cty.NumberIntVal(1).Mark("foo"), cty.NumberIntVal(2).Mark("foo")},
[]cty.Value{cty.NumberIntVal(1).Mark("foo"), cty.NumberIntVal(2).Mark("foo")},
},
{
[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2).Mark("foo"), cty.NumberIntVal(3)},
[]cty.Value{cty.NumberIntVal(2), cty.NumberIntVal(3)},
[]cty.Value{cty.NumberIntVal(3)},
},
{
[]cty.Value{cty.NumberIntVal(1), cty.NumberIntVal(2).Mark("foo")},
[]cty.Value{cty.NumberIntVal(2)},
[]cty.Value{},
},
{
[]cty.Value{
cty.MapVal(map[string]cty.Value{"a": cty.StringVal("x").Mark("sensitive")}),
cty.MapVal(map[string]cty.Value{"b": cty.StringVal("y")}),
},
[]cty.Value{
cty.MapVal(map[string]cty.Value{"a": cty.StringVal("x").Mark("sensitive")}),
cty.MapVal(map[string]cty.Value{"b": cty.StringVal("y")}),
cty.MapVal(map[string]cty.Value{"c": cty.StringVal("z")}),
},
[]cty.Value{
cty.MapVal(map[string]cty.Value{"a": cty.StringVal("x").Mark("sensitive")}),
cty.MapVal(map[string]cty.Value{"b": cty.StringVal("y")}),
},
},
} }
for _, test := range tests { for _, test := range tests {