Skip to content

Commit

Permalink
ADD RULE aws_s3_bucket_name_length
Browse files Browse the repository at this point in the history
  • Loading branch information
davimmt committed Sep 25, 2023
1 parent 9120f8a commit 1ff7feb
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 0 deletions.
31 changes: 31 additions & 0 deletions docs/rules/aws_s3_bucket_name_length.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# aws_s3_bucket_name_length

Ensures all S3 bucket names contains a valid number of characters.

## Example

```hcl
resource "aws_s3_bucket" "too_long" {
bucket = "a-really-ultra-hiper-super-long-foo-bar-baz-bucket-name.domain.test"
}
```

```sh
$ tflint
1 issue(s) found:

Error: Bucket name "a-really-ultra-hiper-super-long-foo-bar-baz-bucket-name.domain.test" length must be within 3 - 63 character range (aws_s3_bucket_name_length)

on main.tf line 2:
2: bucket = "a-really-ultra-hiper-super-long-foo-bar-baz-bucket-name.domain.test"
```

## Why

Amazon S3 bucket names have [restrictive naming rules](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html).

* This rule is specifically for how many characters long a bucket name must have.

## How To Fix

Ensure the bucket name matches the minimum and maximum characters length count.
84 changes: 84 additions & 0 deletions rules/aws_s3_bucket_name_length.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package rules

import (
"fmt"

"github.com/terraform-linters/tflint-plugin-sdk/hclext"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/terraform-linters/tflint-ruleset-aws/project"
)

// AwsS3BucketNameLengthRule checks that an S3 bucket name contains a valid number of characteres
type AwsS3BucketNameLengthRule struct {
tflint.DefaultRule

resourceType string
attributeName string
}

// NewAwsS3BucketNameLengthRule returns new rule with default attributes
func NewAwsS3BucketNameLengthRule() *AwsS3BucketNameLengthRule {
return &AwsS3BucketNameLengthRule{
resourceType: "aws_s3_bucket",
attributeName: "bucket",
}
}

// Name returns the rule name
func (r *AwsS3BucketNameLengthRule) Name() string {
return "aws_s3_bucket_name_length"
}

// Enabled returns whether the rule is enabled by default
func (r *AwsS3BucketNameLengthRule) Enabled() bool {
return true
}

// Severity returns the rule severity
func (r *AwsS3BucketNameLengthRule) Severity() tflint.Severity {
return tflint.ERROR
}

// Link returns the rule reference link
func (r *AwsS3BucketNameLengthRule) Link() string {
return project.ReferenceLink(r.Name())
}

// Check if s3 bucket name is within the characteres length accepted range
func (r *AwsS3BucketNameLengthRule) Check(runner tflint.Runner) error {

resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{
Attributes: []hclext.AttributeSchema{
{Name: r.attributeName},
},
}, nil)
if err != nil {
return err
}

bucketNameMinLength := 3
bucketNameMaxLength := 63

for _, resource := range resources.Blocks {
attribute, exists := resource.Body.Attributes[r.attributeName]
if !exists {
continue
}

err := runner.EvaluateExpr(attribute.Expr, func (name string) error {
if len(name) < bucketNameMinLength || len(name) > bucketNameMaxLength {
runner.EmitIssue(
r,
fmt.Sprintf("Bucket name %q must be between %d and %d characters", name, bucketNameMinLength, bucketNameMaxLength),
attribute.Expr.Range(),
)
}
return nil
}, nil)
if err != nil {
return err
}
}

return nil
}
48 changes: 48 additions & 0 deletions rules/aws_s3_bucket_name_length_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package rules

import (
"testing"

hcl "github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/helper"
)

func Test_AwsS3BucketNameLength(t *testing.T) {
cases := []struct {
Name string
Content string
Expected helper.Issues
}{
{
Name: "basic",
Content: `
resource "aws_s3_bucket" "too_long" {
bucket = "a-really-ultra-hiper-super-long-foo-bar-baz-bucket-name.domain.test"
}
`,
Expected: helper.Issues{
{
Rule: NewAwsS3BucketNameLengthRule(),
Message: `Bucket name "a-really-ultra-hiper-super-long-foo-bar-baz-bucket-name.domain.test" length must be within 3 - 63 character range`,
Range: hcl.Range{
Filename: "resource.tf",
Start: hcl.Pos{Line: 3, Column: 12},
End: hcl.Pos{Line: 3, Column: 81},
},
},
},
},
}

rule := NewAwsS3BucketNameLengthRule()

for _, tc := range cases {
runner := helper.TestRunner(t, map[string]string{"resource.tf": tc.Content})

if err := rule.Check(runner); err != nil {
t.Fatalf("Unexpected error occurred: %s", err)
}

helper.AssertIssues(t, tc.Expected, runner.Issues)
}
}
1 change: 1 addition & 0 deletions rules/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var manualRules = []tflint.Rule{
NewAwsElasticBeanstalkEnvironmentInvalidNameFormatRule(),
NewAwsSecurityGroupInvalidProtocolRule(),
NewAwsSecurityGroupRuleInvalidProtocolRule(),
NewAwsS3BucketNameLengthRule(),
}

// Rules is a list of all rules
Expand Down

0 comments on commit 1ff7feb

Please sign in to comment.