Consider sensitivity when evaluating module outputs

This change "marks" values related to outputs that
have Sensitive set to true.
This commit is contained in:
Pam Selle 2020-10-06 12:53:49 -04:00
parent cc007a27b7
commit b9eeba0da2
2 changed files with 115 additions and 0 deletions

View File

@ -426,6 +426,10 @@ func (d *evaluationStateData) GetModule(addr addrs.ModuleCall, rng tfdiags.Sourc
}
instance[cfg.Name] = outputState
if cfg.Sensitive {
instance[cfg.Name] = outputState.Mark("sensitive")
}
}
// any pending changes override the state state values
@ -451,6 +455,10 @@ func (d *evaluationStateData) GetModule(addr addrs.ModuleCall, rng tfdiags.Sourc
}
instance[cfg.Name] = change.After
if change.Sensitive {
instance[cfg.Name] = change.After.Mark("sensitive")
}
}
}

View File

@ -9,6 +9,8 @@ import (
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/plans"
"github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/tfdiags"
)
@ -121,3 +123,108 @@ func TestEvaluatorGetInputVariable(t *testing.T) {
t.Errorf("wrong result %#v; want %#v", got, want)
}
}
func TestEvaluatorGetModule(t *testing.T) {
// Create a new evaluator with an existing state
stateSync := states.BuildState(func(ss *states.SyncState) {
ss.SetOutputValue(
addrs.OutputValue{Name: "out"}.Absolute(addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "mod"}}),
cty.StringVal("bar"),
true,
)
}).SyncWrapper()
evaluator := evaluatorForModule(stateSync, plans.NewChanges().SyncWrapper())
data := &evaluationStateData{
Evaluator: evaluator,
}
scope := evaluator.Scope(data, nil)
want := cty.ObjectVal(map[string]cty.Value{"out": cty.StringVal("bar").Mark("sensitive")})
got, diags := scope.Data.GetModule(addrs.ModuleCall{
Name: "mod",
}, tfdiags.SourceRange{})
if len(diags) != 0 {
t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
}
if !got.RawEquals(want) {
t.Errorf("wrong result %#v; want %#v", got, want)
}
// Changes should override the state value
changesSync := plans.NewChanges().SyncWrapper()
change := &plans.OutputChange{
Addr: addrs.OutputValue{Name: "out"}.Absolute(addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "mod"}}),
Sensitive: true,
Change: plans.Change{
After: cty.StringVal("baz"),
},
}
cs, _ := change.Encode()
changesSync.AppendOutputChange(cs)
evaluator = evaluatorForModule(stateSync, changesSync)
data = &evaluationStateData{
Evaluator: evaluator,
}
scope = evaluator.Scope(data, nil)
want = cty.ObjectVal(map[string]cty.Value{"out": cty.StringVal("baz").Mark("sensitive")})
got, diags = scope.Data.GetModule(addrs.ModuleCall{
Name: "mod",
}, tfdiags.SourceRange{})
if len(diags) != 0 {
t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
}
if !got.RawEquals(want) {
t.Errorf("wrong result %#v; want %#v", got, want)
}
// Test changes with empty state
evaluator = evaluatorForModule(states.NewState().SyncWrapper(), changesSync)
data = &evaluationStateData{
Evaluator: evaluator,
}
scope = evaluator.Scope(data, nil)
want = cty.ObjectVal(map[string]cty.Value{"out": cty.StringVal("baz").Mark("sensitive")})
got, diags = scope.Data.GetModule(addrs.ModuleCall{
Name: "mod",
}, tfdiags.SourceRange{})
if len(diags) != 0 {
t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
}
if !got.RawEquals(want) {
t.Errorf("wrong result %#v; want %#v", got, want)
}
}
func evaluatorForModule(stateSync *states.SyncState, changesSync *plans.ChangesSync) *Evaluator {
return &Evaluator{
Meta: &ContextMeta{
Env: "foo",
},
Config: &configs.Config{
Module: &configs.Module{
ModuleCalls: map[string]*configs.ModuleCall{
"mod": {
Name: "mod",
},
},
},
Children: map[string]*configs.Config{
"mod": {
Path: addrs.Module{"module.mod"},
Module: &configs.Module{
Outputs: map[string]*configs.Output{
"out": {
Name: "out",
Sensitive: true,
},
},
},
},
},
},
State: stateSync,
Changes: changesSync,
}
}