Avoid disclosing values in errors on marked vals

AssertObjectCompatible is a special case that will
expose Go string values of values unless otherwise
stopped. This adds that check.
This commit is contained in:
Pam Selle 2020-10-12 15:37:44 -04:00
parent af20a769be
commit da4ddd0160
2 changed files with 62 additions and 14 deletions

View File

@ -51,18 +51,17 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu
actualV := actual.GetAttr(name)
path := append(path, cty.GetAttrStep{Name: name})
// If our value is marked, unmark it here before
// checking value assertions
unmarkedActualV := actualV
if actualV.ContainsMarked() {
unmarkedActualV, _ = actualV.UnmarkDeep()
}
unmarkedPlannedV := plannedV
if plannedV.ContainsMarked() {
unmarkedPlannedV, _ = actualV.UnmarkDeep()
}
// Unmark values here before checking value assertions,
// but save the marks so we can see if we should supress
// exposing a value through errors
unmarkedActualV, marksA := actualV.UnmarkDeep()
unmarkedPlannedV, marksP := plannedV.UnmarkDeep()
_, isMarkedActual := marksA["sensitive"]
_, isMarkedPlanned := marksP["sensitive"]
moreErrs := assertValueCompatible(unmarkedPlannedV, unmarkedActualV, path)
if attrS.Sensitive {
if attrS.Sensitive || isMarkedActual || isMarkedPlanned {
if len(moreErrs) > 0 {
// Use a vague placeholder message instead, to avoid disclosing
// sensitive information.
@ -73,9 +72,8 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu
}
}
for name, blockS := range schema.BlockTypes {
// Unmark values before testing compatibility
plannedV, _ := planned.GetAttr(name).UnmarkDeep()
actualV, _ := actual.GetAttr(name).UnmarkDeep()
plannedV, _ := planned.GetAttr(name).Unmark()
actualV, _ := actual.GetAttr(name).Unmark()
// As a special case, if there were any blocks whose leaf attributes
// are all unknown then we assume (possibly incorrectly) that the

View File

@ -144,6 +144,56 @@ func TestAssertObjectCompatible(t *testing.T) {
`.name: inconsistent values for sensitive attribute`,
},
},
{
&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
"name": {
Type: cty.String,
Required: true,
},
},
},
cty.ObjectVal(map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"name": cty.StringVal("wotsit").Mark("sensitive"),
}),
cty.ObjectVal(map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"name": cty.StringVal("thingy"),
}),
[]string{
`.name: inconsistent values for sensitive attribute`,
},
},
{
&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
"name": {
Type: cty.String,
Required: true,
},
},
},
cty.ObjectVal(map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"name": cty.StringVal("wotsit"),
}),
cty.ObjectVal(map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"name": cty.StringVal("thingy").Mark("sensitive"),
}),
[]string{
`.name: inconsistent values for sensitive attribute`,
},
},
{
&configschema.Block{
Attributes: map[string]*configschema.Attribute{