From 4c7cd549cd085e2a8320356a4837fea9bce7320a Mon Sep 17 00:00:00 2001 From: James Bardin Date: Fri, 4 Aug 2017 18:26:19 -0400 Subject: [PATCH] don't allow leading slashes in s3 remote state key S3 accepts objects with a leading slash and strips them off. This works fine except in our workspace hierarchy, which then can no longer find suffixes matching the full key name. --- backend/remote-state/s3/backend.go | 10 ++++++++++ backend/remote-state/s3/backend_test.go | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/backend/remote-state/s3/backend.go b/backend/remote-state/s3/backend.go index 1a1e10bab..41cf037a9 100644 --- a/backend/remote-state/s3/backend.go +++ b/backend/remote-state/s3/backend.go @@ -2,6 +2,8 @@ package s3 import ( "context" + "fmt" + "strings" "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/aws/aws-sdk-go/service/s3" @@ -25,6 +27,14 @@ func New() backend.Backend { Type: schema.TypeString, Required: true, Description: "The path to the state file inside the bucket", + ValidateFunc: func(v interface{}, s string) ([]string, []error) { + // s3 will strip leading slashes from an object, so while this will + // technically be accepted by s3, it will break our workspace hierarchy. + if strings.HasPrefix(v.(string), "/") { + return nil, []error{fmt.Errorf("key must not start with '/'")} + } + return nil, nil + }, }, "region": { diff --git a/backend/remote-state/s3/backend_test.go b/backend/remote-state/s3/backend_test.go index c5a1f5009..83af43e45 100644 --- a/backend/remote-state/s3/backend_test.go +++ b/backend/remote-state/s3/backend_test.go @@ -11,6 +11,7 @@ import ( "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/aws/aws-sdk-go/service/s3" "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/state/remote" "github.com/hashicorp/terraform/terraform" ) @@ -65,6 +66,28 @@ func TestBackendConfig(t *testing.T) { } } +func TestBackendConfig_invalidKey(t *testing.T) { + testACC(t) + cfg := map[string]interface{}{ + "region": "us-west-1", + "bucket": "tf-test", + "key": "/leading-slash", + "encrypt": true, + "dynamodb_table": "dynamoTable", + } + + rawCfg, err := config.NewRawConfig(cfg) + if err != nil { + t.Fatal(err) + } + resCfg := terraform.NewResourceConfig(rawCfg) + + _, errs := New().Validate(resCfg) + if len(errs) != 1 { + t.Fatal("expected config validation error") + } +} + func TestBackend(t *testing.T) { testACC(t)