mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Add -show-sensitive
flag to tofu plan, apply, state-show and output commands (#1554)
Signed-off-by: siddharthasonker95 <158144589+siddharthasonker95@users.noreply.github.com>
This commit is contained in:
parent
5079292cb2
commit
579d74c409
CHANGELOG.md
internal/command
apply.goapply_test.go
arguments
jsonformat
output.gooutput_test.goplan.goplan_test.goshow.goshow_test.gostate_show.gostate_show_test.gotestdata/plan-sensitive-output
views
@ -5,6 +5,7 @@ UPGRADE NOTES:
|
||||
NEW FEATURES:
|
||||
|
||||
ENHANCEMENTS:
|
||||
* Added `-show-sensitive` flag to tofu plan, apply, state-show and output commands to display sensitive data in output. ([#1554](https://github.com/opentofu/opentofu/pull/1554))
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
|
@ -49,6 +49,8 @@ func (c *ApplyCommand) Run(rawArgs []string) int {
|
||||
args, diags = arguments.ParseApply(rawArgs)
|
||||
}
|
||||
|
||||
c.View.SetShowSensitive(args.ShowSensitive)
|
||||
|
||||
// Instantiate the view, even if there are flag errors, so that we render
|
||||
// diagnostics according to the desired view
|
||||
view := views.NewApply(args.ViewType, c.Destroy, c.View)
|
||||
@ -378,6 +380,8 @@ Options:
|
||||
"-state". This can be used to preserve the old
|
||||
state.
|
||||
|
||||
-show-sensitive If specified, sensitive values will be displayed.
|
||||
|
||||
If you don't provide a saved plan file then this command will also accept
|
||||
all of the plan-customization options accepted by the tofu plan command.
|
||||
For more information on those options, run:
|
||||
|
@ -2167,6 +2167,43 @@ func TestApply_warnings(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestApply_showSensitiveArg(t *testing.T) {
|
||||
td := t.TempDir()
|
||||
testCopyDir(t, testFixturePath("apply-sensitive-output"), td)
|
||||
defer testChdir(t, td)()
|
||||
|
||||
p := testProvider()
|
||||
view, done := testView(t)
|
||||
c := &ApplyCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
statePath := testTempFile(t)
|
||||
|
||||
args := []string{
|
||||
"-state", statePath,
|
||||
"-auto-approve",
|
||||
"-show-sensitive",
|
||||
}
|
||||
|
||||
code := c.Run(args)
|
||||
output := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("bad: \n%s", output.Stderr())
|
||||
}
|
||||
|
||||
stdout := output.Stdout()
|
||||
if !strings.Contains(stdout, "notsensitive = \"Hello world\"") {
|
||||
t.Fatalf("bad: output should contain 'notsensitive' output\n%s", stdout)
|
||||
}
|
||||
if !strings.Contains(stdout, "sensitive = \"Hello world\"") {
|
||||
t.Fatalf("bad: output should contain 'sensitive' output\n%s", stdout)
|
||||
}
|
||||
}
|
||||
|
||||
// applyFixtureSchema returns a schema suitable for processing the
|
||||
// configuration in testdata/apply . This schema should be
|
||||
// assigned to a mock provider named "test".
|
||||
|
@ -31,6 +31,9 @@ type Apply struct {
|
||||
|
||||
// ViewType specifies which output format to use
|
||||
ViewType ViewType
|
||||
|
||||
// ShowSensitive is used to display the value of variables marked as sensitive.
|
||||
ShowSensitive bool
|
||||
}
|
||||
|
||||
// ParseApply processes CLI arguments, returning an Apply value and errors.
|
||||
@ -47,6 +50,7 @@ func ParseApply(args []string) (*Apply, tfdiags.Diagnostics) {
|
||||
cmdFlags := extendedFlagSet("apply", apply.State, apply.Operation, apply.Vars)
|
||||
cmdFlags.BoolVar(&apply.AutoApprove, "auto-approve", false, "auto-approve")
|
||||
cmdFlags.BoolVar(&apply.InputEnabled, "input", true, "input")
|
||||
cmdFlags.BoolVar(&apply.ShowSensitive, "show-sensitive", false, "displays sensitive values")
|
||||
|
||||
var json bool
|
||||
cmdFlags.BoolVar(&json, "json", false, "json")
|
||||
|
@ -23,6 +23,9 @@ type Output struct {
|
||||
ViewType ViewType
|
||||
|
||||
Vars *Vars
|
||||
|
||||
// ShowSensitive is used to display the value of variables marked as sensitive.
|
||||
ShowSensitive bool
|
||||
}
|
||||
|
||||
// ParseOutput processes CLI arguments, returning an Output value and errors.
|
||||
@ -40,6 +43,7 @@ func ParseOutput(args []string) (*Output, tfdiags.Diagnostics) {
|
||||
cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
|
||||
cmdFlags.BoolVar(&rawOutput, "raw", false, "raw")
|
||||
cmdFlags.StringVar(&statePath, "state", "", "path")
|
||||
cmdFlags.BoolVar(&output.ShowSensitive, "show-sensitive", false, "displays sensitive values")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
|
@ -34,6 +34,9 @@ type Plan struct {
|
||||
|
||||
// ViewType specifies which output format to use
|
||||
ViewType ViewType
|
||||
|
||||
// ShowSensitive is used to display the value of variables marked as sensitive.
|
||||
ShowSensitive bool
|
||||
}
|
||||
|
||||
// ParsePlan processes CLI arguments, returning a Plan value and errors.
|
||||
@ -52,6 +55,7 @@ func ParsePlan(args []string) (*Plan, tfdiags.Diagnostics) {
|
||||
cmdFlags.BoolVar(&plan.InputEnabled, "input", true, "input")
|
||||
cmdFlags.StringVar(&plan.OutPath, "out", "", "out")
|
||||
cmdFlags.StringVar(&plan.GenerateConfigPath, "generate-config-out", "", "generate-config-out")
|
||||
cmdFlags.BoolVar(&plan.ShowSensitive, "show-sensitive", false, "displays sensitive values")
|
||||
|
||||
var json bool
|
||||
cmdFlags.BoolVar(&json, "json", false, "json")
|
||||
|
@ -19,6 +19,9 @@ type Show struct {
|
||||
ViewType ViewType
|
||||
|
||||
Vars *Vars
|
||||
|
||||
// ShowSensitive is used to display the value of variables marked as sensitive.
|
||||
ShowSensitive bool
|
||||
}
|
||||
|
||||
// ParseShow processes CLI arguments, returning a Show value and errors.
|
||||
@ -34,6 +37,7 @@ func ParseShow(args []string) (*Show, tfdiags.Diagnostics) {
|
||||
var jsonOutput bool
|
||||
cmdFlags := extendedFlagSet("show", nil, nil, show.Vars)
|
||||
cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
|
||||
cmdFlags.BoolVar(&show.ShowSensitive, "show-sensitive", false, "displays sensitive values")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
|
@ -19,6 +19,9 @@ type View struct {
|
||||
// Concise is used to reduce the level of noise in the output and display
|
||||
// only the important details.
|
||||
Concise bool
|
||||
|
||||
// ShowSensitive is used to display the value of variables marked as sensitive.
|
||||
ShowSensitive bool
|
||||
}
|
||||
|
||||
// ParseView processes CLI arguments, returning a View value and a
|
||||
|
@ -96,13 +96,17 @@ type RenderHumanOpts struct {
|
||||
// HideDiffActionSymbols tells the renderer not to show the '+'/'-' symbols
|
||||
// and to skip the places where the symbols would result in an offset.
|
||||
HideDiffActionSymbols bool
|
||||
|
||||
// ShowSensitive is used to display the value of variables marked as sensitive.
|
||||
ShowSensitive bool
|
||||
}
|
||||
|
||||
// NewRenderHumanOpts creates a new RenderHumanOpts struct with the required
|
||||
// fields set.
|
||||
func NewRenderHumanOpts(colorize *colorstring.Colorize) RenderHumanOpts {
|
||||
func NewRenderHumanOpts(colorize *colorstring.Colorize, showSensitive bool) RenderHumanOpts {
|
||||
return RenderHumanOpts{
|
||||
Colorize: colorize,
|
||||
Colorize: colorize,
|
||||
ShowSensitive: showSensitive,
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,5 +125,6 @@ func (opts RenderHumanOpts) Clone() RenderHumanOpts {
|
||||
// children should override their internal Replace logic, instead of
|
||||
// an ancestor making the switch and affecting the entire tree.
|
||||
OverrideForcesReplacement: false,
|
||||
ShowSensitive: opts.ShowSensitive,
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,11 @@ type sensitiveRenderer struct {
|
||||
}
|
||||
|
||||
func (renderer sensitiveRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
|
||||
// If the -show-sensitive argument is set, then invoke RenderHuman with the inner computed.Diff to display sensitive values.
|
||||
if opts.ShowSensitive {
|
||||
return renderer.inner.RenderHuman(indent, opts)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("(sensitive value)%s%s", nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts))
|
||||
}
|
||||
|
||||
|
@ -274,7 +274,7 @@ func renderHumanDiffOutputs(renderer Renderer, outputs map[string]computed.Diff)
|
||||
for _, key := range keys {
|
||||
output := outputs[key]
|
||||
if output.Action != plans.NoOp {
|
||||
rendered = append(rendered, fmt.Sprintf("%s %-*s = %s", renderer.Colorize.Color(format.DiffActionSymbol(output.Action)), escapedKeyMaxLen, escapedKeys[key], output.RenderHuman(0, computed.NewRenderHumanOpts(renderer.Colorize))))
|
||||
rendered = append(rendered, fmt.Sprintf("%s %-*s = %s", renderer.Colorize.Color(format.DiffActionSymbol(output.Action)), escapedKeyMaxLen, escapedKeys[key], output.RenderHuman(0, computed.NewRenderHumanOpts(renderer.Colorize, renderer.ShowSensitive))))
|
||||
}
|
||||
}
|
||||
return strings.Join(rendered, "\n")
|
||||
@ -356,7 +356,7 @@ func renderHumanDiff(renderer Renderer, diff diff, cause string) (string, bool)
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(renderer.Colorize.Color(resourceChangeComment(diff.change, action, cause)))
|
||||
|
||||
opts := computed.NewRenderHumanOpts(renderer.Colorize)
|
||||
opts := computed.NewRenderHumanOpts(renderer.Colorize, renderer.ShowSensitive)
|
||||
|
||||
if action == plans.Forget {
|
||||
opts.HideDiffActionSymbols = true
|
||||
|
@ -82,6 +82,7 @@ type Renderer struct {
|
||||
Colorize *colorstring.Colorize
|
||||
|
||||
RunningInAutomation bool
|
||||
ShowSensitive bool
|
||||
}
|
||||
|
||||
func (renderer Renderer) RenderHumanPlan(plan Plan, mode plans.Mode, opts ...plans.Quality) {
|
||||
@ -106,7 +107,7 @@ func (renderer Renderer) RenderHumanState(state State) {
|
||||
return
|
||||
}
|
||||
|
||||
opts := computed.NewRenderHumanOpts(renderer.Colorize)
|
||||
opts := computed.NewRenderHumanOpts(renderer.Colorize, renderer.ShowSensitive)
|
||||
opts.ShowUnchangedChildren = true
|
||||
opts.HideDiffActionSymbols = true
|
||||
|
||||
@ -143,7 +144,7 @@ func (renderer Renderer) RenderLog(log *JSONLog) error {
|
||||
return err
|
||||
}
|
||||
|
||||
opts := computed.NewRenderHumanOpts(renderer.Colorize)
|
||||
opts := computed.NewRenderHumanOpts(renderer.Colorize, renderer.ShowSensitive)
|
||||
opts.ShowUnchangedChildren = true
|
||||
|
||||
outputDiff := differ.ComputeDiffForType(change, ctype)
|
||||
|
@ -35,6 +35,8 @@ func (c *OutputCommand) Run(rawArgs []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
c.View.SetShowSensitive(args.ShowSensitive)
|
||||
|
||||
view := views.NewOutput(args.ViewType, c.View)
|
||||
|
||||
// Inject variables from args into meta for static evaluation
|
||||
@ -149,6 +151,8 @@ Options:
|
||||
string directly, rather than a human-oriented
|
||||
representation of the value.
|
||||
|
||||
-show-sensitive If specified, sensitive values will be displayed.
|
||||
|
||||
-var 'foo=bar' Set a value for one of the input variables in the root
|
||||
module of the configuration. Use this option more than
|
||||
once to set more than one variable.
|
||||
|
@ -325,3 +325,73 @@ func TestOutput_stateDefault(t *testing.T) {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutput_showSensitiveArg(t *testing.T) {
|
||||
originalState := stateWithSensitiveValueForOutput()
|
||||
|
||||
statePath := testStateFile(t, originalState)
|
||||
|
||||
view, done := testView(t)
|
||||
c := &OutputCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-state", statePath,
|
||||
"-show-sensitive",
|
||||
}
|
||||
code := c.Run(args)
|
||||
output := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("bad: \n%s", output.Stderr())
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(output.Stdout())
|
||||
if actual != "foo = \"bar\"" {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutput_withoutShowSensitiveArg(t *testing.T) {
|
||||
originalState := stateWithSensitiveValueForOutput()
|
||||
|
||||
statePath := testStateFile(t, originalState)
|
||||
|
||||
view, done := testView(t)
|
||||
c := &OutputCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-state", statePath,
|
||||
}
|
||||
code := c.Run(args)
|
||||
output := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("bad: \n%s", output.Stderr())
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(output.Stdout())
|
||||
if actual != "foo = <sensitive>" {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
// stateWithSensitiveValueForOutput return a state with an output value
|
||||
// marked as sensitive.
|
||||
func stateWithSensitiveValueForOutput() *states.State {
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetOutputValue(
|
||||
addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
|
||||
cty.StringVal("bar"),
|
||||
true,
|
||||
)
|
||||
})
|
||||
return state
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ func (c *PlanCommand) Run(rawArgs []string) int {
|
||||
// Parse and validate flags
|
||||
args, diags := arguments.ParsePlan(rawArgs)
|
||||
|
||||
c.View.SetShowSensitive(args.ShowSensitive)
|
||||
|
||||
// Instantiate the view, even if there are flag errors, so that we render
|
||||
// diagnostics according to the desired view
|
||||
view := views.NewPlan(args.ViewType, c.View)
|
||||
@ -288,6 +290,8 @@ Other Options:
|
||||
-state=statefile A legacy option used for the local backend only.
|
||||
See the local backend's documentation for more
|
||||
information.
|
||||
|
||||
-show-sensitive If specified, sensitive values will be displayed.
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
@ -1655,6 +1655,60 @@ func planFixtureSchema() *providers.GetProviderSchemaResponse {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlan_showSensitiveArg(t *testing.T) {
|
||||
td := t.TempDir()
|
||||
testCopyDir(t, testFixturePath("plan-sensitive-output"), td)
|
||||
defer testChdir(t, td)()
|
||||
|
||||
p := planFixtureProvider()
|
||||
view, done := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-show-sensitive",
|
||||
}
|
||||
code := c.Run(args)
|
||||
output := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("bad status code: \n%s", output.Stderr())
|
||||
}
|
||||
|
||||
if got, want := output.Stdout(), "sensitive = \"Hello world\""; !strings.Contains(got, want) {
|
||||
t.Fatalf("got incorrect output, want %q, got:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlan_withoutShowSensitiveArg(t *testing.T) {
|
||||
td := t.TempDir()
|
||||
testCopyDir(t, testFixturePath("plan-sensitive-output"), td)
|
||||
defer testChdir(t, td)()
|
||||
|
||||
p := planFixtureProvider()
|
||||
view, done := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{}
|
||||
code := c.Run(args)
|
||||
output := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("bad status code: \n%s", output.Stderr())
|
||||
}
|
||||
|
||||
if got, want := output.Stdout(), "sensitive = (sensitive value)"; !strings.Contains(got, want) {
|
||||
t.Fatalf("got incorrect output, want %q, got:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
// planFixtureProvider returns a mock provider that is configured for basic
|
||||
// operation with the configuration in testdata/plan. This mock has
|
||||
// GetSchemaResponse and PlanResourceChangeFn populated, with the plan
|
||||
|
@ -69,6 +69,7 @@ func (c *ShowCommand) Run(rawArgs []string) int {
|
||||
return 1
|
||||
}
|
||||
c.viewType = args.ViewType
|
||||
c.View.SetShowSensitive(args.ShowSensitive)
|
||||
|
||||
// Set up view
|
||||
view := views.NewShow(args.ViewType, c.View)
|
||||
@ -114,9 +115,12 @@ Usage: tofu [global options] show [options] [path]
|
||||
Options:
|
||||
|
||||
-no-color If specified, output won't contain any color.
|
||||
|
||||
-json If specified, output the OpenTofu plan or state in
|
||||
a machine-readable form.
|
||||
|
||||
-show-sensitive If specified, sensitive values will be displayed.
|
||||
|
||||
-var 'foo=bar' Set a value for one of the input variables in the root
|
||||
module of the configuration. Use this option more than
|
||||
once to set more than one variable.
|
||||
|
@ -1000,6 +1000,74 @@ func TestShow_corruptStatefile(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestShow_showSensitiveArg(t *testing.T) {
|
||||
originalState := stateWithSensitiveValueForShow()
|
||||
|
||||
testStateFileDefault(t, originalState)
|
||||
|
||||
view, done := testView(t)
|
||||
c := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-show-sensitive",
|
||||
}
|
||||
code := c.Run(args)
|
||||
output := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("bad: \n%s", output.Stderr())
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(output.Stdout())
|
||||
expected := "Outputs:\n\nfoo = \"bar\""
|
||||
if actual != expected {
|
||||
t.Fatalf("got incorrect output: %#v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShow_withoutShowSensitiveArg(t *testing.T) {
|
||||
originalState := stateWithSensitiveValueForShow()
|
||||
|
||||
testStateFileDefault(t, originalState)
|
||||
|
||||
view, done := testView(t)
|
||||
c := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
code := c.Run([]string{})
|
||||
output := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("bad: \n%s", output.Stderr())
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(output.Stdout())
|
||||
expected := "Outputs:\n\nfoo = (sensitive value)"
|
||||
if actual != expected {
|
||||
t.Fatalf("got incorrect output: %#v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
// stateWithSensitiveValueForShow return a state with an output value
|
||||
// marked as sensitive.
|
||||
func stateWithSensitiveValueForShow() *states.State {
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetOutputValue(
|
||||
addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
|
||||
cty.StringVal("bar"),
|
||||
true,
|
||||
)
|
||||
})
|
||||
return state
|
||||
}
|
||||
|
||||
// showFixtureSchema returns a schema suitable for processing the configuration
|
||||
// in testdata/show. This schema should be assigned to a mock provider
|
||||
// named "test".
|
||||
|
@ -35,6 +35,10 @@ func (c *StateShowCommand) Run(args []string) int {
|
||||
cmdFlags := c.Meta.defaultFlagSet("state show")
|
||||
c.Meta.varFlagSet(cmdFlags)
|
||||
cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
|
||||
|
||||
showSensitive := false
|
||||
cmdFlags.BoolVar(&showSensitive, "show-sensitive", false, "displays sensitive values")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
c.Streams.Eprintf("Error parsing command-line flags: %s\n", err.Error())
|
||||
return 1
|
||||
@ -187,6 +191,7 @@ func (c *StateShowCommand) Run(args []string) int {
|
||||
Streams: c.Streams,
|
||||
Colorize: c.Colorize(),
|
||||
RunningInAutomation: c.RunningInAutomation,
|
||||
ShowSensitive: showSensitive,
|
||||
}
|
||||
|
||||
renderer.RenderHumanState(jstate)
|
||||
@ -209,6 +214,8 @@ Options:
|
||||
up OpenTofu-managed resources. By default it will
|
||||
use the state "terraform.tfstate" if it exists.
|
||||
|
||||
-show-sensitive If specified, sensitive values will be displayed.
|
||||
|
||||
-var 'foo=bar' Set a value for one of the input variables in the root
|
||||
module of the configuration. Use this option more than
|
||||
once to set more than one variable.
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/opentofu/opentofu/internal/addrs"
|
||||
"github.com/opentofu/opentofu/internal/configs/configschema"
|
||||
"github.com/opentofu/opentofu/internal/providers"
|
||||
@ -270,6 +271,123 @@ func TestStateShow_configured_provider(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateShow_withoutShowSensitiveArg(t *testing.T) {
|
||||
state := stateWithSensitiveValueForStateShow()
|
||||
statePath := testStateFile(t, state)
|
||||
|
||||
p := testProvider()
|
||||
p.GetProviderSchemaResponse = providerWithSensitiveValueForStateShow()
|
||||
|
||||
streams, done := terminal.StreamsForTesting(t)
|
||||
c := &StateShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Streams: streams,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-state", statePath,
|
||||
"test_instance.foo",
|
||||
}
|
||||
code := c.Run(args)
|
||||
output := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("bad: \n%s", output.Stderr())
|
||||
}
|
||||
|
||||
expected := `# test_instance.foo:
|
||||
resource "test_instance" "foo" {
|
||||
bar = "value"
|
||||
foo = "value"
|
||||
id = (sensitive value)
|
||||
}`
|
||||
actual := strings.TrimSpace(output.Stdout())
|
||||
if diff := cmp.Diff(actual, expected); len(diff) > 0 {
|
||||
t.Fatalf("got incorrect output\n %v", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateShow_showSensitiveArg(t *testing.T) {
|
||||
state := stateWithSensitiveValueForStateShow()
|
||||
statePath := testStateFile(t, state)
|
||||
|
||||
p := testProvider()
|
||||
p.GetProviderSchemaResponse = providerWithSensitiveValueForStateShow()
|
||||
|
||||
streams, done := terminal.StreamsForTesting(t)
|
||||
c := &StateShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Streams: streams,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-show-sensitive",
|
||||
"-state", statePath,
|
||||
"test_instance.foo",
|
||||
}
|
||||
code := c.Run(args)
|
||||
output := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("bad: \n%s", output.Stderr())
|
||||
}
|
||||
|
||||
expected := `# test_instance.foo:
|
||||
resource "test_instance" "foo" {
|
||||
bar = "value"
|
||||
foo = "value"
|
||||
id = "bar"
|
||||
}`
|
||||
actual := strings.TrimSpace(output.Stdout())
|
||||
if diff := cmp.Diff(actual, expected); len(diff) > 0 {
|
||||
t.Fatalf("got incorrect output\n %v", diff)
|
||||
}
|
||||
}
|
||||
|
||||
// stateWithSensitiveValueForStateShow returns a state with a resource
|
||||
// instance.
|
||||
func stateWithSensitiveValueForStateShow() *states.State {
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
// providerWithSensitiveValueForStateShow returns a provider schema response
|
||||
// with the "id" attribute flagged as sensitive.
|
||||
func providerWithSensitiveValueForStateShow() *providers.GetProviderSchemaResponse {
|
||||
return &providers.GetProviderSchemaResponse{
|
||||
ResourceTypes: map[string]providers.Schema{
|
||||
"test_instance": {
|
||||
Block: &configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {Type: cty.String, Optional: true, Computed: true, Sensitive: true},
|
||||
"foo": {Type: cty.String, Optional: true},
|
||||
"bar": {Type: cty.String, Optional: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const testStateShowOutput = `
|
||||
# test_instance.foo:
|
||||
resource "test_instance" "foo" {
|
||||
|
12
internal/command/testdata/plan-sensitive-output/main.tf
vendored
Normal file
12
internal/command/testdata/plan-sensitive-output/main.tf
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
variable "input" {
|
||||
default = "Hello world"
|
||||
}
|
||||
|
||||
output "notsensitive" {
|
||||
value = "${var.input}"
|
||||
}
|
||||
|
||||
output "sensitive" {
|
||||
sensitive = true
|
||||
value = "${var.input}"
|
||||
}
|
@ -105,6 +105,7 @@ func (v *OperationHuman) Plan(plan *plans.Plan, schemas *tofu.Schemas) {
|
||||
Colorize: v.view.colorize,
|
||||
Streams: v.view.streams,
|
||||
RunningInAutomation: v.inAutomation,
|
||||
ShowSensitive: v.view.showSensitive,
|
||||
}
|
||||
|
||||
jplan := jsonformat.Plan{
|
||||
|
@ -84,13 +84,13 @@ func (v *OutputHuman) Output(name string, outputs map[string]*states.OutputValue
|
||||
sort.Strings(ks)
|
||||
|
||||
for _, k := range ks {
|
||||
v := outputs[k]
|
||||
if v.Sensitive {
|
||||
vs := outputs[k]
|
||||
if vs.Sensitive && !v.view.showSensitive {
|
||||
outputBuf.WriteString(fmt.Sprintf("%s = <sensitive>\n", k))
|
||||
continue
|
||||
}
|
||||
|
||||
result := repl.FormatValue(v.Value, 0)
|
||||
result := repl.FormatValue(vs.Value, 0)
|
||||
outputBuf.WriteString(fmt.Sprintf("%s = %s\n", k, result))
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ func (v *ShowHuman) Display(config *configs.Config, plan *plans.Plan, planJSON *
|
||||
Colorize: v.view.colorize,
|
||||
Streams: v.view.streams,
|
||||
RunningInAutomation: v.view.runningInAutomation,
|
||||
ShowSensitive: v.view.showSensitive,
|
||||
}
|
||||
|
||||
// Prefer to display a pre-built JSON plan, if we got one; then, fall back
|
||||
|
@ -33,6 +33,9 @@ type View struct {
|
||||
// only the important details.
|
||||
concise bool
|
||||
|
||||
// showSensitive is used to display the value of variables marked as sensitive.
|
||||
showSensitive bool
|
||||
|
||||
// This unfortunate wart is required to enable rendering of diagnostics which
|
||||
// have associated source code in the configuration. This function pointer
|
||||
// will be dereferenced as late as possible when rendering diagnostics in
|
||||
@ -170,3 +173,7 @@ func (v *View) errorColumns() int {
|
||||
func (v *View) outputHorizRule() {
|
||||
v.streams.Println(format.HorizontalRule(v.colorize, v.outputColumns()))
|
||||
}
|
||||
|
||||
func (v *View) SetShowSensitive(showSensitive bool) {
|
||||
v.showSensitive = showSensitive
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user