Skip to content

Commit

Permalink
aws_elastic_beanstalk_environment_invalid_name_format (#315)
Browse files Browse the repository at this point in the history
* add aws_elastic_beanstalk_environment_name_invalid_format rule & tests

* increase readability of error message

* add documentation

* add rule reference link

* standardise rule name

* add missing link in rules readme

* break lines in readme code blocks

* update example resource config

* update readme description

* update readme

* import project for rule reference link

* revert changes to rules readme

* Revert "revert changes to rules readme"

This reverts commit 36d962a.

* Fix docs/rules/README.md.tmpl

Co-authored-by: samhpickering <samhpickering@googlemail.com>
Co-authored-by: wata_mac <watassbass@gmail.com>
  • Loading branch information
3 people authored Mar 27, 2022
1 parent fc2b8fe commit 69c3f2b
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/rules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ These rules warn of possible errors that can occur at `terraform apply`. Rules m
|[aws_db_instance_invalid_type](aws_db_instance_invalid_type.md)|Disallow using invalid instance class|||
|aws_db_instance_invalid_vpc_security_group|Disallow using invalid VPC security groups|||
|aws_dynamodb_table_invalid_stream_view_type|Disallow using invalid stream view types for DynamoDB|||
|[aws_elastic_beanstalk_environment_invalid_name_format](aws_elastic_beanstalk_environment_invalid_name_format.md)|Disallow invalid environment name|||
|aws_elasticache_cluster_invalid_parameter_group|Disallow using invalid parameter group|||
|aws_elasticache_cluster_invalid_security_group|Disallow using invalid security groups|||
|aws_elasticache_cluster_invalid_subnet_group|Disallow using invalid subnet group|||
Expand Down
1 change: 1 addition & 0 deletions docs/rules/README.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ These rules warn of possible errors that can occur at `terraform apply`. Rules m
|[aws_db_instance_invalid_type](aws_db_instance_invalid_type.md)|Disallow using invalid instance class||✔|
|aws_db_instance_invalid_vpc_security_group|Disallow using invalid VPC security groups|✔|✔|
|aws_dynamodb_table_invalid_stream_view_type|Disallow using invalid stream view types for DynamoDB||✔|
|[aws_elastic_beanstalk_environment_invalid_name_format](aws_elastic_beanstalk_environment_invalid_name_format.md)|Disallow invalid environment name||✔|
|aws_elasticache_cluster_invalid_parameter_group|Disallow using invalid parameter group|✔|✔|
|aws_elasticache_cluster_invalid_security_group|Disallow using invalid security groups|✔|✔|
|aws_elasticache_cluster_invalid_subnet_group|Disallow using invalid subnet group|✔|✔|
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# aws_elastic_beanstalk_environment_invalid_name_format

Disallow invalid Elastic Beanstalk environment name

## Example

```hcl
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "env_name_underscores"
application = "example-app"
solution_stack_name = "64bit Amazon Linux 2015.03 v2.0.3 running Go 1.4"
}
```

```
$ tflint
1 issue(s) found:
Error: env_name_underscores does not match constraint: must contain only letters, digits, and
the dash character and may not start or end with a dash
(^[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]$) (aws_elastic_beanstalk_environment_invalid_name_format)
on example.tf line 2:
2: name = "env_name_underscores"
```

## Why

When attempting to create the resource, Terraform will return the error:
```
Error: InvalidParameterValue: Value env_name_underscores at 'EnvironmentName' failed to satisfy
constraint: Member must contain only letters, digits, and the dash character and may not start
or end with a dash
status code: 400
```

## How To Fix

Ensure your environment name consists only of letters, digits, and the dash character, and does
not start or end with a dash.
The regex used is `^[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]$`
85 changes: 85 additions & 0 deletions rules/aws_elastic_beanstalk_environment_invalid_name_format.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package rules

import (
"fmt"
"regexp"

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

// AwsElasticBeanstalkEnvironmentInvalidNameFormatRule checks EB environment name matches a pattern
type AwsElasticBeanstalkEnvironmentInvalidNameFormatRule struct {
tflint.DefaultRule

resourceType string
attributeName string
pattern *regexp.Regexp
}

// NewAwsElasticBeanstalkEnvironmentInvalidNameFormatRule returns new rule with default attributes
func NewAwsElasticBeanstalkEnvironmentInvalidNameFormatRule() *AwsElasticBeanstalkEnvironmentInvalidNameFormatRule {
return &AwsElasticBeanstalkEnvironmentInvalidNameFormatRule{
resourceType: "aws_elastic_beanstalk_environment",
attributeName: "name",
pattern: regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]$"),
}
}

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

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

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

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

// Check checks the environment name matches the pattern provided
func (r *AwsElasticBeanstalkEnvironmentInvalidNameFormatRule) 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
}

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

var val string
err := runner.EvaluateExpr(attribute.Expr, &val, nil)

err = runner.EnsureNoError(err, func() error {
if !r.pattern.MatchString(val) {
runner.EmitIssue(
r,
fmt.Sprintf(`%s does not match constraint: must contain only letters, digits, and the dash `+
`character and may not start or end with a dash (^[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]$)`, val),
attribute.Expr.Range(),
)
}
return nil
})
if err != nil {
return err
}
}

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package rules

import (
"testing"

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

func Test_AwsElasticBeanstalkEnvironmentInvalidNameFormat(t *testing.T) {
cases := []struct {
Name string
Content string
Expected helper.Issues
}{
{
Name: "tf-test-name dash valid",
Content: `
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name"
application = "tf-test-name"
solution_stack_name = "64bit Amazon Linux 2015.03 v2.0.3 running Go 1.4"
}
`,
Expected: helper.Issues{},
},
{
Name: "underscores invalid",
Content: `
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf_test_name"
application = "tf-test-name"
solution_stack_name = "64bit Amazon Linux 2015.03 v2.0.3 running Go 1.4"
}
`,
Expected: helper.Issues{
{
Rule: NewAwsElasticBeanstalkEnvironmentInvalidNameFormatRule(),
Message: "tf_test_name does not match constraint: must contain only letters, digits, and " +
"the dash character and may not start or end with a dash (^[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]$)",
Range: hcl.Range{
Filename: "resource.tf",
Start: hcl.Pos{Line: 3, Column: 24},
End: hcl.Pos{Line: 3, Column: 38},
},
},
},
},
{
Name: "end with dash invalid",
Content: `
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name-"
application = "tf-test-name"
solution_stack_name = "64bit Amazon Linux 2015.03 v2.0.3 running Go 1.4"
}
`,
Expected: helper.Issues{
{
Rule: NewAwsElasticBeanstalkEnvironmentInvalidNameFormatRule(),
Message: "tf-test-name- does not match constraint: must contain only letters, digits, and " +
"the dash character and may not start or end with a dash (^[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]$)",
Range: hcl.Range{
Filename: "resource.tf",
Start: hcl.Pos{Line: 3, Column: 24},
End: hcl.Pos{Line: 3, Column: 39},
},
},
},
},
}

rule := NewAwsElasticBeanstalkEnvironmentInvalidNameFormatRule()

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 @@ -38,6 +38,7 @@ var rules = [][]tflint.Rule{
NewAwsLambdaFunctionDeprecatedRuntimeRule(),
NewAwsIAMGroupPolicyTooLongRule(),
NewAwsAcmCertificateLifecycleRule(),
NewAwsElasticBeanstalkEnvironmentInvalidNameFormatRule(),
},
models.Rules,
api.Rules,
Expand Down

0 comments on commit 69c3f2b

Please sign in to comment.