Merge pull request #28381 from hashicorp/alisdair/fix-double-mark-sensitive-attrs

core: Fix double-marked sensitive attributes
This commit is contained in:
Alisdair McDiarmid 2021-04-15 10:13:29 -04:00 committed by GitHub
commit ec001d3e18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 10 deletions

View File

@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/providers" "github.com/hashicorp/terraform/providers"
"github.com/hashicorp/terraform/states" "github.com/hashicorp/terraform/states"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
@ -367,3 +368,80 @@ resource "aws_instance" "bin" {
} }
} }
func TestContext2Apply_additionalSensitiveFromState(t *testing.T) {
// Ensure we're not trying to double-mark values decoded from state
m := testModuleInline(t, map[string]string{
"main.tf": `
variable "secret" {
sensitive = true
default = ["secret"]
}
resource "test_resource" "a" {
sensitive_attr = var.secret
}
resource "test_resource" "b" {
value = test_resource.a.id
}
`,
})
p := new(MockProvider)
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"test_resource": {
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
"value": {
Type: cty.String,
Optional: true,
},
"sensitive_attr": {
Type: cty.List(cty.String),
Optional: true,
Sensitive: true,
},
},
},
},
})
state := states.BuildState(func(s *states.SyncState) {
s.SetResourceInstanceCurrent(
mustResourceInstanceAddr(`test_resource.a`),
&states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"id":"a","sensitive_attr":["secret"]}`),
AttrSensitivePaths: []cty.PathValueMarks{
{
Path: cty.GetAttrPath("sensitive_attr"),
Marks: cty.NewValueMarks("sensitive"),
},
},
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)
})
ctx := testContext2(t, &ContextOpts{
Config: m,
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
State: state,
})
_, diags := ctx.Plan()
if diags.HasErrors() {
t.Fatal(diags.ErrWithWarnings())
}
_, diags = ctx.Apply()
if diags.HasErrors() {
t.Fatal(diags.ErrWithWarnings())
}
}

View File

@ -782,9 +782,15 @@ func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.Sourc
val := ios.Value val := ios.Value
// If our schema contains sensitive values, mark those as sensitive // If our schema contains sensitive values, mark those as sensitive.
// Since decoding the instance object can also apply sensitivity marks,
// we must remove and combine those before remarking to avoid a double-
// mark error.
if schema.ContainsSensitive() { if schema.ContainsSensitive() {
val = markProviderSensitiveAttributes(schema, val) var marks []cty.PathValueMarks
val, marks = val.UnmarkDeepWithPaths()
marks = append(marks, getValMarks(schema, val, nil)...)
val = val.MarkWithPaths(marks)
} }
instances[key] = val instances[key] = val
} }
@ -954,12 +960,6 @@ func moduleDisplayAddr(addr addrs.ModuleInstance) string {
} }
} }
// markProviderSensitiveAttributes returns an updated value
// where attributes that are Sensitive are marked
func markProviderSensitiveAttributes(schema *configschema.Block, val cty.Value) cty.Value {
return val.MarkWithPaths(getValMarks(schema, val, nil))
}
func getValMarks(schema *configschema.Block, val cty.Value, path cty.Path) []cty.PathValueMarks { func getValMarks(schema *configschema.Block, val cty.Value, path cty.Path) []cty.PathValueMarks {
var pvm []cty.PathValueMarks var pvm []cty.PathValueMarks
for name, attrS := range schema.Attributes { for name, attrS := range schema.Attributes {

View File

@ -563,7 +563,7 @@ func evaluatorForModule(stateSync *states.SyncState, changesSync *plans.ChangesS
} }
} }
func TestMarkProviderSensitive(t *testing.T) { func TestGetValMarks(t *testing.T) {
schema := &configschema.Block{ schema := &configschema.Block{
Attributes: map[string]*configschema.Attribute{ Attributes: map[string]*configschema.Attribute{
"unsensitive": { "unsensitive": {
@ -647,7 +647,7 @@ func TestMarkProviderSensitive(t *testing.T) {
}, },
} { } {
t.Run(fmt.Sprintf("%#v", tc.given), func(t *testing.T) { t.Run(fmt.Sprintf("%#v", tc.given), func(t *testing.T) {
got := markProviderSensitiveAttributes(schema, tc.given) got := tc.given.MarkWithPaths(getValMarks(schema, tc.given, nil))
if !got.RawEquals(tc.expect) { if !got.RawEquals(tc.expect) {
t.Fatalf("\nexpected: %#v\ngot: %#v\n", tc.expect, got) t.Fatalf("\nexpected: %#v\ngot: %#v\n", tc.expect, got)
} }