diff --git a/config.go b/config.go index 36e53e6..e093cfa 100644 --- a/config.go +++ b/config.go @@ -147,6 +147,9 @@ type ConfigVariable struct { // The defined text description of the variable. Description string `json:"description,omitempty"` + + // Whether the variable is marked as sensitive + Sensitive bool `json:"sensitive,omitempty"` } // ConfigProvisioner describes a provisioner declared in a resource diff --git a/plan.go b/plan.go index 2a8ebd2..7e44c5c 100644 --- a/plan.go +++ b/plan.go @@ -150,6 +150,14 @@ type Change struct { // If the value cannot be found in this map, then its value should // be available within After, so long as the operation supports it. AfterUnknown interface{} `json:"after_unknown,omitempty"` + + // BeforeSensitive and AfterSensitive are object values with similar + // structure to Before and After, but with all sensitive leaf values + // replaced with true, and all non-sensitive leaf values omitted. These + // objects should be combined with Before and After to prevent accidental + // display of sensitive values in user interfaces. + BeforeSensitive interface{} `json:"before_sensitive,omitempty"` + AfterSensitive interface{} `json:"after_sensitive,omitempty"` } // PlanVariable is a top-level variable in the Terraform plan. diff --git a/plan_test.go b/plan_test.go index 80133ae..003e966 100644 --- a/plan_test.go +++ b/plan_test.go @@ -4,6 +4,8 @@ import ( "encoding/json" "os" "testing" + + "github.com/google/go-cmp/cmp" ) func TestPlanValidate(t *testing.T) { @@ -22,3 +24,41 @@ func TestPlanValidate(t *testing.T) { t.Fatal(err) } } + +func TestPlan_015(t *testing.T) { + f, err := os.Open("testdata/basic/plan-0.15.json") + if err != nil { + t.Fatal(err) + } + defer f.Close() + + var plan *Plan + if err := json.NewDecoder(f).Decode(&plan); err != nil { + t.Fatal(err) + } + + if err := plan.Validate(); err != nil { + t.Fatal(err) + } + + expectedChange := &Change{ + Actions: Actions{"create"}, + After: map[string]interface{}{"ami": "boop"}, + AfterUnknown: map[string]interface{}{"id": true}, + BeforeSensitive: false, + AfterSensitive: map[string]interface{}{"ami": true}, + } + if diff := cmp.Diff(expectedChange, plan.ResourceChanges[0].Change); diff != "" { + t.Fatalf("unexpected change: %s", diff) + } + + expectedVariable := map[string]*ConfigVariable{ + "test_var": { + Default: "boop", + Sensitive: true, + }, + } + if diff := cmp.Diff(expectedVariable, plan.Config.RootModule.Variables); diff != "" { + t.Fatalf("unexpected variables: %s", diff) + } +} diff --git a/testdata/basic/plan-0.15.json b/testdata/basic/plan-0.15.json new file mode 100644 index 0000000..5110538 --- /dev/null +++ b/testdata/basic/plan-0.15.json @@ -0,0 +1,117 @@ +{ + "format_version": "0.1", + "variables": { + "test_var": { + "value": "boop" + } + }, + "planned_values": { + "outputs": { + "test": { + "sensitive": true, + "value": "boop" + } + }, + "root_module": { + "resources": [ + { + "address": "test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "boop" + } + } + ] + } + }, + "resource_changes": [ + { + "address": "test_instance.test", + "mode": "managed", + "type": "test_instance", + "provider_name": "registry.terraform.io/hashicorp/test", + "name": "test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "boop" + }, + "after_unknown": { + "id": true + }, + "after_sensitive": { + "ami": true + }, + "before_sensitive": false + } + } + ], + "output_changes": { + "test": { + "actions": [ + "create" + ], + "before": null, + "after": "boop", + "after_unknown": false, + "before_sensitive": true, + "after_sensitive": true + } + }, + "prior_state": { + "format_version": "0.1", + "values": { + "outputs": { + "test": { + "sensitive": true, + "value": "boop" + } + }, + "root_module": {} + } + }, + "configuration": { + "root_module": { + "outputs": { + "test": { + "expression": { + "references": [ + "test_instance.test" + ] + }, + "sensitive": true + } + }, + "resources": [ + { + "address": "test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_config_key": "test", + "schema_version": 0, + "expressions": { + "ami": { + "references": [ + "var.test_var" + ] + } + } + } + ], + "variables": { + "test_var": { + "default": "boop", + "sensitive": true + } + } + } + } +}