Merge pull request #26590 from hashicorp/pselle/sensitivity-providers
Mark attributes providers mark as sensitive
This commit is contained in:
commit
cdebf2820d
|
@ -11870,7 +11870,23 @@ variable "sensitive_map" {
|
|||
|
||||
resource "test_resource" "foo" {
|
||||
value = var.sensitive_map.x
|
||||
}`,
|
||||
sensitive_value = "should get marked"
|
||||
}
|
||||
|
||||
resource "test_resource" "bar" {
|
||||
value = test_resource.foo.sensitive_value
|
||||
random = test_resource.foo.id # not sensitive
|
||||
|
||||
nesting_single {
|
||||
value = "abc"
|
||||
sensitive_value = "xyz"
|
||||
}
|
||||
}
|
||||
|
||||
resource "test_resource" "baz" {
|
||||
value = test_resource.bar.nesting_single.sensitive_value
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
||||
p := testProvider("test")
|
||||
|
@ -11903,10 +11919,20 @@ resource "test_resource" "foo" {
|
|||
}
|
||||
|
||||
addr := mustResourceInstanceAddr("test_resource.foo")
|
||||
|
||||
fooChangeSrc := plan.Changes.ResourceInstance(addr)
|
||||
verifySensitiveValue(fooChangeSrc.AfterValMarks)
|
||||
|
||||
// Sensitive attributes (defined by the provider) are marked
|
||||
// as sensitive when referenced from another resource
|
||||
// "bar" references sensitive resources in "foo"
|
||||
barAddr := mustResourceInstanceAddr("test_resource.bar")
|
||||
barChangeSrc := plan.Changes.ResourceInstance(barAddr)
|
||||
verifySensitiveValue(barChangeSrc.AfterValMarks)
|
||||
|
||||
bazAddr := mustResourceInstanceAddr("test_resource.baz")
|
||||
bazChangeSrc := plan.Changes.ResourceInstance(bazAddr)
|
||||
verifySensitiveValue(bazChangeSrc.AfterValMarks)
|
||||
|
||||
state, diags := ctx.Apply()
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("apply errors: %s", diags.Err())
|
||||
|
@ -11914,6 +11940,12 @@ resource "test_resource" "foo" {
|
|||
|
||||
fooState := state.ResourceInstance(addr)
|
||||
verifySensitiveValue(fooState.Current.AttrSensitivePaths)
|
||||
|
||||
barState := state.ResourceInstance(barAddr)
|
||||
verifySensitiveValue(barState.Current.AttrSensitivePaths)
|
||||
|
||||
bazState := state.ResourceInstance(bazAddr)
|
||||
verifySensitiveValue(bazState.Current.AttrSensitivePaths)
|
||||
}
|
||||
|
||||
func TestContext2Apply_variableSensitivityChange(t *testing.T) {
|
||||
|
|
|
@ -425,6 +425,11 @@ func testProviderSchema(name string) *ProviderSchema {
|
|||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
"sensitive_value": {
|
||||
Type: cty.String,
|
||||
Sensitive: true,
|
||||
Optional: true,
|
||||
},
|
||||
"random": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
|
@ -440,6 +445,15 @@ func testProviderSchema(name string) *ProviderSchema {
|
|||
},
|
||||
Nesting: configschema.NestingSet,
|
||||
},
|
||||
"nesting_single": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"value": {Type: cty.String, Optional: true},
|
||||
"sensitive_value": {Type: cty.String, Optional: true, Sensitive: true},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingSingle,
|
||||
},
|
||||
},
|
||||
},
|
||||
name + "_ami_list": {
|
||||
|
|
|
@ -727,7 +727,7 @@ func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.Sourc
|
|||
}
|
||||
|
||||
// Planned resources are temporarily stored in state with empty values,
|
||||
// and need to be replaced bu the planned value here.
|
||||
// and need to be replaced by the planned value here.
|
||||
if is.Current.Status == states.ObjectPlanned {
|
||||
if change == nil {
|
||||
// If the object is in planned status then we should not get
|
||||
|
@ -752,6 +752,10 @@ func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.Sourc
|
|||
continue
|
||||
}
|
||||
|
||||
// If our schema contains sensitive values, mark those as sensitive
|
||||
if schema.ContainsSensitive() {
|
||||
val = markProviderSensitiveAttributes(schema, val)
|
||||
}
|
||||
instances[key] = val
|
||||
continue
|
||||
}
|
||||
|
@ -768,7 +772,13 @@ func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.Sourc
|
|||
})
|
||||
continue
|
||||
}
|
||||
instances[key] = ios.Value
|
||||
|
||||
val := ios.Value
|
||||
// If our schema contains sensitive values, mark those as sensitive
|
||||
if schema.ContainsSensitive() {
|
||||
val = markProviderSensitiveAttributes(schema, val)
|
||||
}
|
||||
instances[key] = val
|
||||
}
|
||||
|
||||
var ret cty.Value
|
||||
|
@ -935,3 +945,51 @@ func moduleDisplayAddr(addr addrs.ModuleInstance) string {
|
|||
return addr.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 {
|
||||
var pvm []cty.PathValueMarks
|
||||
for name, attrS := range schema.Attributes {
|
||||
if attrS.Sensitive {
|
||||
// Create a copy of the path, with this step added, to add to our PathValueMarks slice
|
||||
attrPath := make(cty.Path, len(path), len(path)+1)
|
||||
copy(attrPath, path)
|
||||
attrPath = append(path, cty.GetAttrStep{Name: name})
|
||||
pvm = append(pvm, cty.PathValueMarks{
|
||||
Path: attrPath,
|
||||
Marks: cty.NewValueMarks("sensitive"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for name, blockS := range schema.BlockTypes {
|
||||
// If our block doesn't contain any sensitive attributes, skip inspecting it
|
||||
if !blockS.Block.ContainsSensitive() {
|
||||
continue
|
||||
}
|
||||
// Create a copy of the path, with this step added, to add to our PathValueMarks slice
|
||||
blockPath := make(cty.Path, len(path), len(path)+1)
|
||||
copy(blockPath, path)
|
||||
blockPath = append(path, cty.GetAttrStep{Name: name})
|
||||
|
||||
blockV := val.GetAttr(name)
|
||||
switch blockS.Nesting {
|
||||
case configschema.NestingSingle, configschema.NestingGroup:
|
||||
pvm = append(pvm, getValMarks(&blockS.Block, blockV, blockPath)...)
|
||||
case configschema.NestingList, configschema.NestingMap, configschema.NestingSet:
|
||||
for it := blockV.ElementIterator(); it.Next(); {
|
||||
idx, blockEV := it.Element()
|
||||
morePaths := getValMarks(&blockS.Block, blockEV, append(blockPath, cty.IndexStep{Key: idx}))
|
||||
pvm = append(pvm, morePaths...)
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported nesting mode %s", blockS.Nesting))
|
||||
}
|
||||
}
|
||||
return pvm
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
|
@ -124,6 +125,178 @@ func TestEvaluatorGetInputVariable(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEvaluatorGetResource(t *testing.T) {
|
||||
stateSync := states.BuildState(func(ss *states.SyncState) {
|
||||
ss.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_resource",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
Status: states.ObjectReady,
|
||||
AttrsJSON: []byte(`{"id":"foo", "nesting_list": [{"sensitive_value":"abc"}], "nesting_map": {"foo":{"foo":"x"}}, "nesting_set": [{"baz":"abc"}], "nesting_single": {"boop":"abc"}, "nesting_nesting": {"nesting_list":[{"sensitive_value":"abc"}]}, "value":"hello"}`),
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
}).SyncWrapper()
|
||||
|
||||
rc := &configs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_resource",
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"id": cty.StringVal("foo"),
|
||||
}),
|
||||
Provider: addrs.Provider{
|
||||
Hostname: addrs.DefaultRegistryHost,
|
||||
Namespace: "hashicorp",
|
||||
Type: "test",
|
||||
},
|
||||
}
|
||||
|
||||
evaluator := &Evaluator{
|
||||
Meta: &ContextMeta{
|
||||
Env: "foo",
|
||||
},
|
||||
Changes: plans.NewChanges().SyncWrapper(),
|
||||
Config: &configs.Config{
|
||||
Module: &configs.Module{
|
||||
ManagedResources: map[string]*configs.Resource{
|
||||
"test_resource.foo": rc,
|
||||
},
|
||||
},
|
||||
},
|
||||
State: stateSync,
|
||||
Schemas: &Schemas{
|
||||
Providers: map[addrs.Provider]*ProviderSchema{
|
||||
addrs.NewDefaultProvider("test"): {
|
||||
Provider: &configschema.Block{},
|
||||
ResourceTypes: map[string]*configschema.Block{
|
||||
"test_resource": {
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {
|
||||
Type: cty.String,
|
||||
Computed: true,
|
||||
},
|
||||
"value": {
|
||||
Type: cty.String,
|
||||
Computed: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
},
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"nesting_list": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"value": {Type: cty.String, Optional: true},
|
||||
"sensitive_value": {Type: cty.String, Optional: true, Sensitive: true},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingList,
|
||||
},
|
||||
"nesting_map": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"foo": {Type: cty.String, Optional: true, Sensitive: true},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingMap,
|
||||
},
|
||||
"nesting_set": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"baz": {Type: cty.String, Optional: true, Sensitive: true},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingSet,
|
||||
},
|
||||
"nesting_single": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"boop": {Type: cty.String, Optional: true, Sensitive: true},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingSingle,
|
||||
},
|
||||
"nesting_nesting": {
|
||||
Block: configschema.Block{
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"nesting_list": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"value": {Type: cty.String, Optional: true},
|
||||
"sensitive_value": {Type: cty.String, Optional: true, Sensitive: true},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingList,
|
||||
},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingSingle,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
data := &evaluationStateData{
|
||||
Evaluator: evaluator,
|
||||
}
|
||||
scope := evaluator.Scope(data, nil)
|
||||
|
||||
want := cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("foo"),
|
||||
"nesting_list": cty.ListVal([]cty.Value{
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"sensitive_value": cty.StringVal("abc").Mark("sensitive"),
|
||||
"value": cty.NullVal(cty.String),
|
||||
}),
|
||||
}),
|
||||
"nesting_map": cty.MapVal(map[string]cty.Value{
|
||||
"foo": cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("x").Mark("sensitive")}),
|
||||
}),
|
||||
"nesting_nesting": cty.ObjectVal(map[string]cty.Value{
|
||||
"nesting_list": cty.ListVal([]cty.Value{
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"sensitive_value": cty.StringVal("abc").Mark("sensitive"),
|
||||
"value": cty.NullVal(cty.String),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
"nesting_set": cty.SetVal([]cty.Value{
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"baz": cty.StringVal("abc").Mark("sensitive"),
|
||||
}),
|
||||
}),
|
||||
"nesting_single": cty.ObjectVal(map[string]cty.Value{
|
||||
"boop": cty.StringVal("abc").Mark("sensitive"),
|
||||
}),
|
||||
"value": cty.StringVal("hello").Mark("sensitive"),
|
||||
})
|
||||
|
||||
addr := addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_resource",
|
||||
Name: "foo",
|
||||
}
|
||||
got, diags := scope.Data.GetResource(addr, tfdiags.SourceRange{})
|
||||
|
||||
if len(diags) != 0 {
|
||||
t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
|
||||
}
|
||||
|
||||
if !got.RawEquals(want) {
|
||||
t.Errorf("wrong result:\ngot: %#v\nwant: %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluatorGetModule(t *testing.T) {
|
||||
// Create a new evaluator with an existing state
|
||||
stateSync := states.BuildState(func(ss *states.SyncState) {
|
||||
|
|
Loading…
Reference in New Issue