Skip to content

Commit

Permalink
Merge pull request #35223 from hashicorp/t-s3-object-key-extra-clean
Browse files Browse the repository at this point in the history
Remove leading `./` from S3 object key name -- AWS SDK for Go v1 compatibility
  • Loading branch information
ewbankkit authored Jan 11, 2024
2 parents fb291b3 + 699b04f commit a7fdef9
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 1 deletion.
19 changes: 19 additions & 0 deletions .changelog/35223.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
```release-note:bug
resource/aws_s3_object: Remove any leading `./` from `key` to maintain AWS SDK for Go v1 (pre-v5.17.0) compatibility
```

```release-note:bug
data-source/aws_s3_object: Remove any leading `./` from `key` to maintain AWS SDK for Go v1 (pre-v5.17.0) compatibility
```

```release-note:bug
data-source/aws_s3_bucket_object: Remove any leading `./` from `key` to maintain AWS SDK for Go v1 (pre-v5.17.0) compatibility
```

```release-note:bug
resource/aws_s3_object_copy: Remove any leading `./` from `key` to maintain AWS SDK for Go v1 (pre-v5.17.0) compatibility
```

```release-note:bug
resource/aws_s3_bucket_object: Remove any leading `./` from `key` to maintain AWS SDK for Go v1 (pre-v5.17.0) compatibility
```
2 changes: 2 additions & 0 deletions internal/service/s3/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,8 @@ func flattenObjectDate(t *time.Time) string {
// See https://docs.aws.amazon.com/sdk-for-go/api/service/s3/#hdr-Automatic_URI_cleaning.
// See https://github.com/aws/aws-sdk-go/blob/cf903c8c543034654bb8f53b5f9d6454fdb2117f/private/protocol/rest/build.go#L247-L258.
func sdkv1CompatibleCleanKey(key string) string {
// Remove leading './'.
key = strings.TrimPrefix(key, "./")
// We are effectively ignoring all leading '/'s and treating multiple '/'s as a single '/'.
key = strings.TrimLeft(key, "/")
key = regexache.MustCompile(`/+`).ReplaceAllString(key, "/")
Expand Down
148 changes: 147 additions & 1 deletion internal/service/s3/object_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,89 @@ func TestAccS3ObjectDataSource_singleSlashAsKey(t *testing.T) {
})
}

func TestAccS3ObjectDataSource_leadingDotSlash(t *testing.T) {
ctx := acctest.Context(t)
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_s3_object.test"
dataSourceName1 := "data.aws_s3_object.test1"
dataSourceName2 := "data.aws_s3_object.test2"

resourceOnlyConf, conf := testAccObjectDataSourceConfig_leadingDotSlash(rName)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
PreventPostDestroyRefresh: true,
Steps: []resource.TestStep{
{ // nosemgrep:ci.test-config-funcs-correct-form
Config: resourceOnlyConf,
},
{ // nosemgrep:ci.test-config-funcs-correct-form
Config: conf,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName1, "body", "yes"),
resource.TestCheckResourceAttr(dataSourceName1, "content_length", "3"),
resource.TestCheckResourceAttrPair(dataSourceName1, "content_type", resourceName, "content_type"),
resource.TestCheckResourceAttrPair(dataSourceName1, "etag", resourceName, "etag"),
resource.TestMatchResourceAttr(dataSourceName1, "last_modified", regexache.MustCompile(rfc1123RegexPattern)),

resource.TestCheckResourceAttr(dataSourceName2, "body", "yes"),
resource.TestCheckResourceAttr(dataSourceName2, "content_length", "3"),
resource.TestCheckResourceAttrPair(dataSourceName2, "content_type", resourceName, "content_type"),
resource.TestCheckResourceAttrPair(dataSourceName2, "etag", resourceName, "etag"),
resource.TestMatchResourceAttr(dataSourceName2, "last_modified", regexache.MustCompile(rfc1123RegexPattern)),
),
},
},
})
}

func TestAccS3ObjectDataSource_leadingMultipleSlashes(t *testing.T) {
ctx := acctest.Context(t)
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_s3_object.test"
dataSourceName1 := "data.aws_s3_object.test1"
dataSourceName2 := "data.aws_s3_object.test2"
dataSourceName3 := "data.aws_s3_object.test3"

resourceOnlyConf, conf := testAccObjectDataSourceConfig_leadingMultipleSlashes(rName)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
PreventPostDestroyRefresh: true,
Steps: []resource.TestStep{
{ // nosemgrep:ci.test-config-funcs-correct-form
Config: resourceOnlyConf,
},
{ // nosemgrep:ci.test-config-funcs-correct-form
Config: conf,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName1, "body", "yes"),
resource.TestCheckResourceAttr(dataSourceName1, "content_length", "3"),
resource.TestCheckResourceAttrPair(dataSourceName1, "content_type", resourceName, "content_type"),
resource.TestCheckResourceAttrPair(dataSourceName1, "etag", resourceName, "etag"),
resource.TestMatchResourceAttr(dataSourceName1, "last_modified", regexache.MustCompile(rfc1123RegexPattern)),

resource.TestCheckResourceAttr(dataSourceName2, "body", "yes"),
resource.TestCheckResourceAttr(dataSourceName2, "content_length", "3"),
resource.TestCheckResourceAttrPair(dataSourceName2, "content_type", resourceName, "content_type"),
resource.TestCheckResourceAttrPair(dataSourceName2, "etag", resourceName, "etag"),
resource.TestMatchResourceAttr(dataSourceName2, "last_modified", regexache.MustCompile(rfc1123RegexPattern)),

resource.TestCheckResourceAttr(dataSourceName3, "body", "yes"),
resource.TestCheckResourceAttr(dataSourceName3, "content_length", "3"),
resource.TestCheckResourceAttrPair(dataSourceName3, "content_type", resourceName, "content_type"),
resource.TestCheckResourceAttrPair(dataSourceName3, "etag", resourceName, "etag"),
resource.TestMatchResourceAttr(dataSourceName3, "last_modified", regexache.MustCompile(rfc1123RegexPattern)),
),
},
},
})
}

func TestAccS3ObjectDataSource_checksumMode(t *testing.T) {
ctx := acctest.Context(t)
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
Expand Down Expand Up @@ -728,7 +811,7 @@ resource "aws_s3_bucket" "test" {
resource "aws_s3_object" "test" {
bucket = aws_s3_bucket.test.bucket
key = "//%[1]s-key"
key = "/%[1]s-key"
content = "yes"
content_type = "text/plain"
}
Expand Down Expand Up @@ -809,6 +892,69 @@ data "aws_s3_object" "test" {
`, rName)
}

func testAccObjectDataSourceConfig_leadingDotSlash(rName string) (string, string) {
resources := fmt.Sprintf(`
resource "aws_s3_bucket" "test" {
bucket = %[1]q
}
resource "aws_s3_object" "test" {
bucket = aws_s3_bucket.test.bucket
key = "./%[1]s-key"
content = "yes"
content_type = "text/plain"
}
`, rName)

both := acctest.ConfigCompose(resources, fmt.Sprintf(`
data "aws_s3_object" "test1" {
bucket = aws_s3_bucket.test.bucket
key = "%[1]s-key"
}
data "aws_s3_object" "test2" {
bucket = aws_s3_bucket.test.bucket
key = "/%[1]s-key"
}
`, rName))

return resources, both
}

func testAccObjectDataSourceConfig_leadingMultipleSlashes(rName string) (string, string) {
resources := fmt.Sprintf(`
resource "aws_s3_bucket" "test" {
bucket = %[1]q
}
resource "aws_s3_object" "test" {
bucket = aws_s3_bucket.test.bucket
key = "///%[1]s-key"
content = "yes"
content_type = "text/plain"
}
`, rName)

both := acctest.ConfigCompose(resources, fmt.Sprintf(`
data "aws_s3_object" "test1" {
bucket = aws_s3_bucket.test.bucket
key = "%[1]s-key"
}
data "aws_s3_object" "test2" {
bucket = aws_s3_bucket.test.bucket
key = "/%[1]s-key"
}
data "aws_s3_object" "test3" {
bucket = aws_s3_bucket.test.bucket
key = "//%[1]s-key"
}
`, rName))

return resources, both
}

func testAccObjectDataSourceConfig_checksumMode(rName string) string {
return fmt.Sprintf(`
resource "aws_s3_bucket" "test" {
Expand Down

0 comments on commit a7fdef9

Please sign in to comment.