From 2fda09aab27c4a213ab8fa613db9db4fffc70fa2 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 26 Jun 2023 16:01:05 -0700 Subject: [PATCH] Updates attribute validation messages --- internal/backend/remote-state/s3/backend.go | 26 ++++++++++++++----- .../backend/remote-state/s3/backend_test.go | 20 +++++++------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/internal/backend/remote-state/s3/backend.go b/internal/backend/remote-state/s3/backend.go index 777edc548a..6b07070647 100644 --- a/internal/backend/remote-state/s3/backend.go +++ b/internal/backend/remote-state/s3/backend.go @@ -40,6 +40,8 @@ type Backend struct { workspaceKeyPrefix string } +// ConfigSchema returns a description of the expected configuration +// structure for the receiving backend. func (b *Backend) ConfigSchema() *configschema.Block { return &configschema.Block{ Attributes: map[string]*configschema.Attribute{ @@ -211,6 +213,10 @@ func (b *Backend) ConfigSchema() *configschema.Block { } } +// PrepareConfig checks the validity of the values in the given +// configuration, and inserts any missing defaults, assuming that its +// structure has already been validated per the schema returned by +// ConfigSchema. func (b *Backend) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics if obj.IsNull() { @@ -221,8 +227,7 @@ func (b *Backend) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) diags = diags.Append(tfdiags.AttributeValue( tfdiags.Error, "Invalid bucket value", - // `The "bucket" attribute value must not be empty.`, - `"bucket": required field is not set`, + `The "bucket" attribute value must not be empty.`, cty.Path{cty.GetAttrStep{Name: "bucket"}}, )) } @@ -231,7 +236,7 @@ func (b *Backend) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) diags = diags.Append(tfdiags.AttributeValue( tfdiags.Error, "Invalid key value", - `"key": required field is not set`, + `The "key" attribute value must not be empty.`, cty.Path{cty.GetAttrStep{Name: "key"}}, )) } else if strings.HasPrefix(val.AsString(), "/") || strings.HasSuffix(val.AsString(), "/") { @@ -242,7 +247,7 @@ func (b *Backend) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) diags = diags.Append(tfdiags.AttributeValue( tfdiags.Error, "Invalid key value", - "key must not start or end with '/'", + `The "key" attribute value must not start or end with with "/".`, cty.Path{cty.GetAttrStep{Name: "key"}}, )) } @@ -252,7 +257,7 @@ func (b *Backend) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) diags = diags.Append(tfdiags.AttributeValue( tfdiags.Error, "Missing region value", - `"region": required field is not set`, + `The "region" attribute or the "AWS_REGION" or "AWS_DEFAULT_REGION" environment variables must be set.`, cty.Path{cty.GetAttrStep{Name: "region"}}, )) } @@ -267,10 +272,11 @@ func (b *Backend) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) cty.Path{}, )) } else if customerKey := os.Getenv("AWS_SSE_CUSTOMER_KEY"); customerKey != "" { - diags = diags.Append(tfdiags.Sourceless( + diags = diags.Append(tfdiags.AttributeValue( tfdiags.Error, "Invalid encryption configuration", encryptionKeyConflictEnvVarError, + cty.Path{}, )) } } @@ -280,7 +286,7 @@ func (b *Backend) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) diags = diags.Append(tfdiags.AttributeValue( tfdiags.Error, "Invalid workspace_key_prefix value", - "workspace_key_prefix must not start or end with '/'", + `The "workspace_key_prefix" attribute value must not start with "/".`, cty.Path{cty.GetAttrStep{Name: "workspace_key_prefix"}}, )) } @@ -289,6 +295,12 @@ func (b *Backend) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) return obj, diags } +// Configure uses the provided configuration to set configuration fields +// within the backend. +// +// The given configuration is assumed to have already been validated +// against the schema returned by ConfigSchema and passed validation +// via PrepareConfig. func (b *Backend) Configure(obj cty.Value) tfdiags.Diagnostics { var diags tfdiags.Diagnostics if obj.IsNull() { diff --git a/internal/backend/remote-state/s3/backend_test.go b/internal/backend/remote-state/s3/backend_test.go index adc1038a8a..95f97bf21b 100644 --- a/internal/backend/remote-state/s3/backend_test.go +++ b/internal/backend/remote-state/s3/backend_test.go @@ -503,7 +503,7 @@ func TestBackendConfig_PrepareConfigValidation(t *testing.T) { "key": cty.StringVal("test"), "region": cty.StringVal("us-west-2"), }), - expectedErr: `"bucket": required field is not set`, + expectedErr: `The "bucket" attribute value must not be empty.`, }, "empty bucket": { config: cty.ObjectVal(map[string]cty.Value{ @@ -511,7 +511,7 @@ func TestBackendConfig_PrepareConfigValidation(t *testing.T) { "key": cty.StringVal("test"), "region": cty.StringVal("us-west-2"), }), - expectedErr: `"bucket": required field is not set`, + expectedErr: `The "bucket" attribute value must not be empty.`, }, "null key": { config: cty.ObjectVal(map[string]cty.Value{ @@ -519,7 +519,7 @@ func TestBackendConfig_PrepareConfigValidation(t *testing.T) { "key": cty.NullVal(cty.String), "region": cty.StringVal("us-west-2"), }), - expectedErr: `"key": required field is not set`, + expectedErr: `The "key" attribute value must not be empty.`, }, "empty key": { config: cty.ObjectVal(map[string]cty.Value{ @@ -527,7 +527,7 @@ func TestBackendConfig_PrepareConfigValidation(t *testing.T) { "key": cty.StringVal(""), "region": cty.StringVal("us-west-2"), }), - expectedErr: `"key": required field is not set`, + expectedErr: `The "key" attribute value must not be empty.`, }, "key with leading slash": { config: cty.ObjectVal(map[string]cty.Value{ @@ -535,7 +535,7 @@ func TestBackendConfig_PrepareConfigValidation(t *testing.T) { "key": cty.StringVal("/leading-slash"), "region": cty.StringVal("us-west-2"), }), - expectedErr: `key must not start or end with '/'`, + expectedErr: `The "key" attribute value must not start or end with with "/".`, }, "key with trailing slash": { config: cty.ObjectVal(map[string]cty.Value{ @@ -543,7 +543,7 @@ func TestBackendConfig_PrepareConfigValidation(t *testing.T) { "key": cty.StringVal("trailing-slash/"), "region": cty.StringVal("us-west-2"), }), - expectedErr: `key must not start or end with '/'`, + expectedErr: `The "key" attribute value must not start or end with with "/".`, }, "null region": { config: cty.ObjectVal(map[string]cty.Value{ @@ -551,7 +551,7 @@ func TestBackendConfig_PrepareConfigValidation(t *testing.T) { "key": cty.StringVal("test"), "region": cty.NullVal(cty.String), }), - expectedErr: `"region": required field is not set`, + expectedErr: `The "region" attribute or the "AWS_REGION" or "AWS_DEFAULT_REGION" environment variables must be set.`, }, "empty region": { config: cty.ObjectVal(map[string]cty.Value{ @@ -559,7 +559,7 @@ func TestBackendConfig_PrepareConfigValidation(t *testing.T) { "key": cty.StringVal("test"), "region": cty.StringVal(""), }), - expectedErr: `"region": required field is not set`, + expectedErr: `The "region" attribute or the "AWS_REGION" or "AWS_DEFAULT_REGION" environment variables must be set.`, }, "workspace_key_prefix with leading slash": { config: cty.ObjectVal(map[string]cty.Value{ @@ -568,7 +568,7 @@ func TestBackendConfig_PrepareConfigValidation(t *testing.T) { "region": cty.StringVal("us-west-2"), "workspace_key_prefix": cty.StringVal("/env"), }), - expectedErr: `workspace_key_prefix must not start or end with '/'`, + expectedErr: `The "workspace_key_prefix" attribute value must not start with "/".`, }, "workspace_key_prefix with trailing slash": { config: cty.ObjectVal(map[string]cty.Value{ @@ -577,7 +577,7 @@ func TestBackendConfig_PrepareConfigValidation(t *testing.T) { "region": cty.StringVal("us-west-2"), "workspace_key_prefix": cty.StringVal("env/"), }), - expectedErr: `workspace_key_prefix must not start or end with '/'`, + expectedErr: `The "workspace_key_prefix" attribute value must not start with "/".`, }, "encyrption key conflict": { config: cty.ObjectVal(map[string]cty.Value{