diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..0a48921af --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "rules/awsrules/models/aws-sdk-go"] + path = rules/awsrules/models/aws-sdk-go + url = https://github.com/aws/aws-sdk-go.git diff --git a/Makefile b/Makefile index fd2ce88ac..93df3b897 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ prepare: go mod vendor test: prepare - go test $$(go list ./... | grep -v vendor) + go test $$(go list ./... | grep -v vendor | grep -v aws-sdk-go) build: test mkdir -p dist @@ -31,4 +31,7 @@ image: rule: go run tools/rule_generator.go +model_rules: + go run github.com/wata727/tflint/tools/model-rule-gen + .PHONY: default prepare test build install release clean code image rule diff --git a/rules/awsrules/models/aws-sdk-go b/rules/awsrules/models/aws-sdk-go new file mode 160000 index 000000000..594c848f3 --- /dev/null +++ b/rules/awsrules/models/aws-sdk-go @@ -0,0 +1 @@ +Subproject commit 594c848f324de48d7b9fa434b213db7283a859e3 diff --git a/rules/awsrules/models/aws_acm_certificate_invalid_certificate_body.go b/rules/awsrules/models/aws_acm_certificate_invalid_certificate_body.go new file mode 100644 index 000000000..5c4fa01cf --- /dev/null +++ b/rules/awsrules/models/aws_acm_certificate_invalid_certificate_body.go @@ -0,0 +1,87 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAcmCertificateInvalidCertificateBodyRule checks the pattern is valid +type AwsAcmCertificateInvalidCertificateBodyRule struct { + resourceType string + attributeName string + max int + min int + pattern *regexp.Regexp +} + +// NewAwsAcmCertificateInvalidCertificateBodyRule returns new rule with default attributes +func NewAwsAcmCertificateInvalidCertificateBodyRule() *AwsAcmCertificateInvalidCertificateBodyRule { + return &AwsAcmCertificateInvalidCertificateBodyRule{ + resourceType: "aws_acm_certificate", + attributeName: "certificate_body", + max: 32768, + min: 1, + pattern: regexp.MustCompile(`^-{5}BEGIN CERTIFICATE-{5}\x{000D}?\x{000A}([A-Za-z0-9/+]{64}\x{000D}?\x{000A})*[A-Za-z0-9/+]{1,64}={0,2}\x{000D}?\x{000A}-{5}END CERTIFICATE-{5}(\x{000D}?\x{000A})?$`), + } +} + +// Name returns the rule name +func (r *AwsAcmCertificateInvalidCertificateBodyRule) Name() string { + return "aws_acm_certificate_invalid_certificate_body" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAcmCertificateInvalidCertificateBodyRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAcmCertificateInvalidCertificateBodyRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAcmCertificateInvalidCertificateBodyRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAcmCertificateInvalidCertificateBodyRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "certificate_body must be 32768 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "certificate_body must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `certificate_body does not match valid pattern ^-{5}BEGIN CERTIFICATE-{5}\x{000D}?\x{000A}([A-Za-z0-9/+]{64}\x{000D}?\x{000A})*[A-Za-z0-9/+]{1,64}={0,2}\x{000D}?\x{000A}-{5}END CERTIFICATE-{5}(\x{000D}?\x{000A})?$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_acm_certificate_invalid_certificate_body_test.go b/rules/awsrules/models/aws_acm_certificate_invalid_certificate_body_test.go new file mode 100644 index 000000000..fbd764676 --- /dev/null +++ b/rules/awsrules/models/aws_acm_certificate_invalid_certificate_body_test.go @@ -0,0 +1,135 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsAcmCertificateInvalidCertificateBodyRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_acm_certificate" "foo" { + certificate_body = < r.max { + runner.EmitIssue( + r, + "certificate_chain must be 2097152 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "certificate_chain must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `certificate_chain does not match valid pattern ^(-{5}BEGIN CERTIFICATE-{5}\x{000D}?\x{000A}([A-Za-z0-9/+]{64}\x{000D}?\x{000A})*[A-Za-z0-9/+]{1,64}={0,2}\x{000D}?\x{000A}-{5}END CERTIFICATE-{5}\x{000D}?\x{000A})*-{5}BEGIN CERTIFICATE-{5}\x{000D}?\x{000A}([A-Za-z0-9/+]{64}\x{000D}?\x{000A})*[A-Za-z0-9/+]{1,64}={0,2}\x{000D}?\x{000A}-{5}END CERTIFICATE-{5}(\x{000D}?\x{000A})?$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_acm_certificate_invalid_certificate_chain_test.go b/rules/awsrules/models/aws_acm_certificate_invalid_certificate_chain_test.go new file mode 100644 index 000000000..ff88b901b --- /dev/null +++ b/rules/awsrules/models/aws_acm_certificate_invalid_certificate_chain_test.go @@ -0,0 +1,153 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsAcmCertificateInvalidCertificateChainRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_acm_certificate" "foo" { + certificate_chain = < r.max { + runner.EmitIssue( + r, + "private_key must be 524288 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "private_key must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `private_key does not match valid pattern ^-{5}BEGIN PRIVATE KEY-{5}\x{000D}?\x{000A}([A-Za-z0-9/+]{64}\x{000D}?\x{000A})*[A-Za-z0-9/+]{1,64}={0,2}\x{000D}?\x{000A}-{5}END PRIVATE KEY-{5}(\x{000D}?\x{000A})?$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_acm_certificate_invalid_private_key_test.go b/rules/awsrules/models/aws_acm_certificate_invalid_private_key_test.go new file mode 100644 index 000000000..0c6b3781d --- /dev/null +++ b/rules/awsrules/models/aws_acm_certificate_invalid_private_key_test.go @@ -0,0 +1,146 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsAcmCertificateInvalidPrivateKeyRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_acm_certificate" "foo" { + private_key = < r.max { + runner.EmitIssue( + r, + "name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appmesh_route_invalid_mesh_name.go b/rules/awsrules/models/aws_appmesh_route_invalid_mesh_name.go new file mode 100644 index 000000000..a52bee078 --- /dev/null +++ b/rules/awsrules/models/aws_appmesh_route_invalid_mesh_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppmeshRouteInvalidMeshNameRule checks the pattern is valid +type AwsAppmeshRouteInvalidMeshNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppmeshRouteInvalidMeshNameRule returns new rule with default attributes +func NewAwsAppmeshRouteInvalidMeshNameRule() *AwsAppmeshRouteInvalidMeshNameRule { + return &AwsAppmeshRouteInvalidMeshNameRule{ + resourceType: "aws_appmesh_route", + attributeName: "mesh_name", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppmeshRouteInvalidMeshNameRule) Name() string { + return "aws_appmesh_route_invalid_mesh_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppmeshRouteInvalidMeshNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppmeshRouteInvalidMeshNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppmeshRouteInvalidMeshNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppmeshRouteInvalidMeshNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "mesh_name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "mesh_name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appmesh_route_invalid_name.go b/rules/awsrules/models/aws_appmesh_route_invalid_name.go new file mode 100644 index 000000000..8d0965c37 --- /dev/null +++ b/rules/awsrules/models/aws_appmesh_route_invalid_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppmeshRouteInvalidNameRule checks the pattern is valid +type AwsAppmeshRouteInvalidNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppmeshRouteInvalidNameRule returns new rule with default attributes +func NewAwsAppmeshRouteInvalidNameRule() *AwsAppmeshRouteInvalidNameRule { + return &AwsAppmeshRouteInvalidNameRule{ + resourceType: "aws_appmesh_route", + attributeName: "name", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppmeshRouteInvalidNameRule) Name() string { + return "aws_appmesh_route_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppmeshRouteInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppmeshRouteInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppmeshRouteInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppmeshRouteInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appmesh_route_invalid_virtual_router_name.go b/rules/awsrules/models/aws_appmesh_route_invalid_virtual_router_name.go new file mode 100644 index 000000000..3595f6f22 --- /dev/null +++ b/rules/awsrules/models/aws_appmesh_route_invalid_virtual_router_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppmeshRouteInvalidVirtualRouterNameRule checks the pattern is valid +type AwsAppmeshRouteInvalidVirtualRouterNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppmeshRouteInvalidVirtualRouterNameRule returns new rule with default attributes +func NewAwsAppmeshRouteInvalidVirtualRouterNameRule() *AwsAppmeshRouteInvalidVirtualRouterNameRule { + return &AwsAppmeshRouteInvalidVirtualRouterNameRule{ + resourceType: "aws_appmesh_route", + attributeName: "virtual_router_name", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppmeshRouteInvalidVirtualRouterNameRule) Name() string { + return "aws_appmesh_route_invalid_virtual_router_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppmeshRouteInvalidVirtualRouterNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppmeshRouteInvalidVirtualRouterNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppmeshRouteInvalidVirtualRouterNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppmeshRouteInvalidVirtualRouterNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "virtual_router_name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "virtual_router_name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appmesh_virtual_node_invalid_mesh_name.go b/rules/awsrules/models/aws_appmesh_virtual_node_invalid_mesh_name.go new file mode 100644 index 000000000..039d235af --- /dev/null +++ b/rules/awsrules/models/aws_appmesh_virtual_node_invalid_mesh_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppmeshVirtualNodeInvalidMeshNameRule checks the pattern is valid +type AwsAppmeshVirtualNodeInvalidMeshNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppmeshVirtualNodeInvalidMeshNameRule returns new rule with default attributes +func NewAwsAppmeshVirtualNodeInvalidMeshNameRule() *AwsAppmeshVirtualNodeInvalidMeshNameRule { + return &AwsAppmeshVirtualNodeInvalidMeshNameRule{ + resourceType: "aws_appmesh_virtual_node", + attributeName: "mesh_name", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppmeshVirtualNodeInvalidMeshNameRule) Name() string { + return "aws_appmesh_virtual_node_invalid_mesh_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppmeshVirtualNodeInvalidMeshNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppmeshVirtualNodeInvalidMeshNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppmeshVirtualNodeInvalidMeshNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppmeshVirtualNodeInvalidMeshNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "mesh_name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "mesh_name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appmesh_virtual_node_invalid_name.go b/rules/awsrules/models/aws_appmesh_virtual_node_invalid_name.go new file mode 100644 index 000000000..c7e3aa8b3 --- /dev/null +++ b/rules/awsrules/models/aws_appmesh_virtual_node_invalid_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppmeshVirtualNodeInvalidNameRule checks the pattern is valid +type AwsAppmeshVirtualNodeInvalidNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppmeshVirtualNodeInvalidNameRule returns new rule with default attributes +func NewAwsAppmeshVirtualNodeInvalidNameRule() *AwsAppmeshVirtualNodeInvalidNameRule { + return &AwsAppmeshVirtualNodeInvalidNameRule{ + resourceType: "aws_appmesh_virtual_node", + attributeName: "name", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppmeshVirtualNodeInvalidNameRule) Name() string { + return "aws_appmesh_virtual_node_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppmeshVirtualNodeInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppmeshVirtualNodeInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppmeshVirtualNodeInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppmeshVirtualNodeInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appmesh_virtual_router_invalid_mesh_name.go b/rules/awsrules/models/aws_appmesh_virtual_router_invalid_mesh_name.go new file mode 100644 index 000000000..3c92b32dd --- /dev/null +++ b/rules/awsrules/models/aws_appmesh_virtual_router_invalid_mesh_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppmeshVirtualRouterInvalidMeshNameRule checks the pattern is valid +type AwsAppmeshVirtualRouterInvalidMeshNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppmeshVirtualRouterInvalidMeshNameRule returns new rule with default attributes +func NewAwsAppmeshVirtualRouterInvalidMeshNameRule() *AwsAppmeshVirtualRouterInvalidMeshNameRule { + return &AwsAppmeshVirtualRouterInvalidMeshNameRule{ + resourceType: "aws_appmesh_virtual_router", + attributeName: "mesh_name", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppmeshVirtualRouterInvalidMeshNameRule) Name() string { + return "aws_appmesh_virtual_router_invalid_mesh_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppmeshVirtualRouterInvalidMeshNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppmeshVirtualRouterInvalidMeshNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppmeshVirtualRouterInvalidMeshNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppmeshVirtualRouterInvalidMeshNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "mesh_name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "mesh_name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appmesh_virtual_router_invalid_name.go b/rules/awsrules/models/aws_appmesh_virtual_router_invalid_name.go new file mode 100644 index 000000000..f45ed15c4 --- /dev/null +++ b/rules/awsrules/models/aws_appmesh_virtual_router_invalid_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppmeshVirtualRouterInvalidNameRule checks the pattern is valid +type AwsAppmeshVirtualRouterInvalidNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppmeshVirtualRouterInvalidNameRule returns new rule with default attributes +func NewAwsAppmeshVirtualRouterInvalidNameRule() *AwsAppmeshVirtualRouterInvalidNameRule { + return &AwsAppmeshVirtualRouterInvalidNameRule{ + resourceType: "aws_appmesh_virtual_router", + attributeName: "name", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppmeshVirtualRouterInvalidNameRule) Name() string { + return "aws_appmesh_virtual_router_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppmeshVirtualRouterInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppmeshVirtualRouterInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppmeshVirtualRouterInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppmeshVirtualRouterInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appmesh_virtual_service_invalid_mesh_name.go b/rules/awsrules/models/aws_appmesh_virtual_service_invalid_mesh_name.go new file mode 100644 index 000000000..d92ba3744 --- /dev/null +++ b/rules/awsrules/models/aws_appmesh_virtual_service_invalid_mesh_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppmeshVirtualServiceInvalidMeshNameRule checks the pattern is valid +type AwsAppmeshVirtualServiceInvalidMeshNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppmeshVirtualServiceInvalidMeshNameRule returns new rule with default attributes +func NewAwsAppmeshVirtualServiceInvalidMeshNameRule() *AwsAppmeshVirtualServiceInvalidMeshNameRule { + return &AwsAppmeshVirtualServiceInvalidMeshNameRule{ + resourceType: "aws_appmesh_virtual_service", + attributeName: "mesh_name", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppmeshVirtualServiceInvalidMeshNameRule) Name() string { + return "aws_appmesh_virtual_service_invalid_mesh_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppmeshVirtualServiceInvalidMeshNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppmeshVirtualServiceInvalidMeshNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppmeshVirtualServiceInvalidMeshNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppmeshVirtualServiceInvalidMeshNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "mesh_name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "mesh_name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appmesh_virtual_service_invalid_name.go b/rules/awsrules/models/aws_appmesh_virtual_service_invalid_name.go new file mode 100644 index 000000000..1cc14e1d0 --- /dev/null +++ b/rules/awsrules/models/aws_appmesh_virtual_service_invalid_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppmeshVirtualServiceInvalidNameRule checks the pattern is valid +type AwsAppmeshVirtualServiceInvalidNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppmeshVirtualServiceInvalidNameRule returns new rule with default attributes +func NewAwsAppmeshVirtualServiceInvalidNameRule() *AwsAppmeshVirtualServiceInvalidNameRule { + return &AwsAppmeshVirtualServiceInvalidNameRule{ + resourceType: "aws_appmesh_virtual_service", + attributeName: "name", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppmeshVirtualServiceInvalidNameRule) Name() string { + return "aws_appmesh_virtual_service_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppmeshVirtualServiceInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppmeshVirtualServiceInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppmeshVirtualServiceInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppmeshVirtualServiceInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appsync_datasource_invalid_name.go b/rules/awsrules/models/aws_appsync_datasource_invalid_name.go new file mode 100644 index 000000000..1dae6ffea --- /dev/null +++ b/rules/awsrules/models/aws_appsync_datasource_invalid_name.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppsyncDatasourceInvalidNameRule checks the pattern is valid +type AwsAppsyncDatasourceInvalidNameRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsAppsyncDatasourceInvalidNameRule returns new rule with default attributes +func NewAwsAppsyncDatasourceInvalidNameRule() *AwsAppsyncDatasourceInvalidNameRule { + return &AwsAppsyncDatasourceInvalidNameRule{ + resourceType: "aws_appsync_datasource", + attributeName: "name", + pattern: regexp.MustCompile(`^[_A-Za-z][_0-9A-Za-z]*$`), + } +} + +// Name returns the rule name +func (r *AwsAppsyncDatasourceInvalidNameRule) Name() string { + return "aws_appsync_datasource_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppsyncDatasourceInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppsyncDatasourceInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppsyncDatasourceInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppsyncDatasourceInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `name does not match valid pattern ^[_A-Za-z][_0-9A-Za-z]*$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appsync_datasource_invalid_name_test.go b/rules/awsrules/models/aws_appsync_datasource_invalid_name_test.go new file mode 100644 index 000000000..8764367f5 --- /dev/null +++ b/rules/awsrules/models/aws_appsync_datasource_invalid_name_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsAppsyncDatasourceInvalidNameRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_appsync_datasource" "foo" { + name = "01_tf_example" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_appsync_datasource_invalid_name", + Type: "ERROR", + Message: `name does not match valid pattern ^[_A-Za-z][_0-9A-Za-z]*$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_appsync_datasource" "foo" { + name = "tf_appsync_example" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsAppsyncDatasourceInvalidNameRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsAppsyncDatasourceInvalidNameRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_appsync_datasource_invalid_type.go b/rules/awsrules/models/aws_appsync_datasource_invalid_type.go new file mode 100644 index 000000000..6282dee2e --- /dev/null +++ b/rules/awsrules/models/aws_appsync_datasource_invalid_type.go @@ -0,0 +1,81 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppsyncDatasourceInvalidTypeRule checks the pattern is valid +type AwsAppsyncDatasourceInvalidTypeRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsAppsyncDatasourceInvalidTypeRule returns new rule with default attributes +func NewAwsAppsyncDatasourceInvalidTypeRule() *AwsAppsyncDatasourceInvalidTypeRule { + return &AwsAppsyncDatasourceInvalidTypeRule{ + resourceType: "aws_appsync_datasource", + attributeName: "type", + enum: []string{ + "AWS_LAMBDA", + "AMAZON_DYNAMODB", + "AMAZON_ELASTICSEARCH", + "NONE", + "HTTP", + "RELATIONAL_DATABASE", + }, + } +} + +// Name returns the rule name +func (r *AwsAppsyncDatasourceInvalidTypeRule) Name() string { + return "aws_appsync_datasource_invalid_type" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppsyncDatasourceInvalidTypeRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppsyncDatasourceInvalidTypeRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppsyncDatasourceInvalidTypeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppsyncDatasourceInvalidTypeRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `type is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appsync_datasource_invalid_type_test.go b/rules/awsrules/models/aws_appsync_datasource_invalid_type_test.go new file mode 100644 index 000000000..29386fea6 --- /dev/null +++ b/rules/awsrules/models/aws_appsync_datasource_invalid_type_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsAppsyncDatasourceInvalidTypeRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_appsync_datasource" "foo" { + type = "AMAZON_SIMPLEDB" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_appsync_datasource_invalid_type", + Type: "ERROR", + Message: `type is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_appsync_datasource" "foo" { + type = "AWS_LAMBDA" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsAppsyncDatasourceInvalidTypeRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsAppsyncDatasourceInvalidTypeRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_appsync_graphql_api_invalid_authentication_type.go b/rules/awsrules/models/aws_appsync_graphql_api_invalid_authentication_type.go new file mode 100644 index 000000000..01022dad8 --- /dev/null +++ b/rules/awsrules/models/aws_appsync_graphql_api_invalid_authentication_type.go @@ -0,0 +1,79 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule checks the pattern is valid +type AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule returns new rule with default attributes +func NewAwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule() *AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule { + return &AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule{ + resourceType: "aws_appsync_graphql_api", + attributeName: "authentication_type", + enum: []string{ + "API_KEY", + "AWS_IAM", + "AMAZON_COGNITO_USER_POOLS", + "OPENID_CONNECT", + }, + } +} + +// Name returns the rule name +func (r *AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule) Name() string { + return "aws_appsync_graphql_api_invalid_authentication_type" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `authentication_type is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appsync_graphql_api_invalid_authentication_type_test.go b/rules/awsrules/models/aws_appsync_graphql_api_invalid_authentication_type_test.go new file mode 100644 index 000000000..2c9d85603 --- /dev/null +++ b/rules/awsrules/models/aws_appsync_graphql_api_invalid_authentication_type_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_appsync_graphql_api" "foo" { + authentication_type = "AWS_KEY" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_appsync_graphql_api_invalid_authentication_type", + Type: "ERROR", + Message: `authentication_type is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_appsync_graphql_api" "foo" { + authentication_type = "API_KEY" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_appsync_resolver_invalid_data_source.go b/rules/awsrules/models/aws_appsync_resolver_invalid_data_source.go new file mode 100644 index 000000000..e4183f0dc --- /dev/null +++ b/rules/awsrules/models/aws_appsync_resolver_invalid_data_source.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppsyncResolverInvalidDataSourceRule checks the pattern is valid +type AwsAppsyncResolverInvalidDataSourceRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsAppsyncResolverInvalidDataSourceRule returns new rule with default attributes +func NewAwsAppsyncResolverInvalidDataSourceRule() *AwsAppsyncResolverInvalidDataSourceRule { + return &AwsAppsyncResolverInvalidDataSourceRule{ + resourceType: "aws_appsync_resolver", + attributeName: "data_source", + pattern: regexp.MustCompile(`^[_A-Za-z][_0-9A-Za-z]*$`), + } +} + +// Name returns the rule name +func (r *AwsAppsyncResolverInvalidDataSourceRule) Name() string { + return "aws_appsync_resolver_invalid_data_source" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppsyncResolverInvalidDataSourceRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppsyncResolverInvalidDataSourceRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppsyncResolverInvalidDataSourceRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppsyncResolverInvalidDataSourceRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `data_source does not match valid pattern ^[_A-Za-z][_0-9A-Za-z]*$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appsync_resolver_invalid_data_source_test.go b/rules/awsrules/models/aws_appsync_resolver_invalid_data_source_test.go new file mode 100644 index 000000000..0fe75b50f --- /dev/null +++ b/rules/awsrules/models/aws_appsync_resolver_invalid_data_source_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsAppsyncResolverInvalidDataSourceRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_appsync_resolver" "foo" { + data_source = "tf-example" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_appsync_resolver_invalid_data_source", + Type: "ERROR", + Message: `data_source does not match valid pattern ^[_A-Za-z][_0-9A-Za-z]*$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_appsync_resolver" "foo" { + data_source = "tfexample" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsAppsyncResolverInvalidDataSourceRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsAppsyncResolverInvalidDataSourceRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_appsync_resolver_invalid_field.go b/rules/awsrules/models/aws_appsync_resolver_invalid_field.go new file mode 100644 index 000000000..6809cfc12 --- /dev/null +++ b/rules/awsrules/models/aws_appsync_resolver_invalid_field.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppsyncResolverInvalidFieldRule checks the pattern is valid +type AwsAppsyncResolverInvalidFieldRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsAppsyncResolverInvalidFieldRule returns new rule with default attributes +func NewAwsAppsyncResolverInvalidFieldRule() *AwsAppsyncResolverInvalidFieldRule { + return &AwsAppsyncResolverInvalidFieldRule{ + resourceType: "aws_appsync_resolver", + attributeName: "field", + pattern: regexp.MustCompile(`^[_A-Za-z][_0-9A-Za-z]*$`), + } +} + +// Name returns the rule name +func (r *AwsAppsyncResolverInvalidFieldRule) Name() string { + return "aws_appsync_resolver_invalid_field" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppsyncResolverInvalidFieldRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppsyncResolverInvalidFieldRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppsyncResolverInvalidFieldRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppsyncResolverInvalidFieldRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `field does not match valid pattern ^[_A-Za-z][_0-9A-Za-z]*$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appsync_resolver_invalid_field_test.go b/rules/awsrules/models/aws_appsync_resolver_invalid_field_test.go new file mode 100644 index 000000000..2fe5a6ae9 --- /dev/null +++ b/rules/awsrules/models/aws_appsync_resolver_invalid_field_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsAppsyncResolverInvalidFieldRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_appsync_resolver" "foo" { + field = "single-post" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_appsync_resolver_invalid_field", + Type: "ERROR", + Message: `field does not match valid pattern ^[_A-Za-z][_0-9A-Za-z]*$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_appsync_resolver" "foo" { + field = "singlePost" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsAppsyncResolverInvalidFieldRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsAppsyncResolverInvalidFieldRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_appsync_resolver_invalid_request_template.go b/rules/awsrules/models/aws_appsync_resolver_invalid_request_template.go new file mode 100644 index 000000000..5dc31c7f5 --- /dev/null +++ b/rules/awsrules/models/aws_appsync_resolver_invalid_request_template.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppsyncResolverInvalidRequestTemplateRule checks the pattern is valid +type AwsAppsyncResolverInvalidRequestTemplateRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppsyncResolverInvalidRequestTemplateRule returns new rule with default attributes +func NewAwsAppsyncResolverInvalidRequestTemplateRule() *AwsAppsyncResolverInvalidRequestTemplateRule { + return &AwsAppsyncResolverInvalidRequestTemplateRule{ + resourceType: "aws_appsync_resolver", + attributeName: "request_template", + max: 65536, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppsyncResolverInvalidRequestTemplateRule) Name() string { + return "aws_appsync_resolver_invalid_request_template" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppsyncResolverInvalidRequestTemplateRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppsyncResolverInvalidRequestTemplateRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppsyncResolverInvalidRequestTemplateRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppsyncResolverInvalidRequestTemplateRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "request_template must be 65536 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "request_template must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appsync_resolver_invalid_response_template.go b/rules/awsrules/models/aws_appsync_resolver_invalid_response_template.go new file mode 100644 index 000000000..5f7529be4 --- /dev/null +++ b/rules/awsrules/models/aws_appsync_resolver_invalid_response_template.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppsyncResolverInvalidResponseTemplateRule checks the pattern is valid +type AwsAppsyncResolverInvalidResponseTemplateRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAppsyncResolverInvalidResponseTemplateRule returns new rule with default attributes +func NewAwsAppsyncResolverInvalidResponseTemplateRule() *AwsAppsyncResolverInvalidResponseTemplateRule { + return &AwsAppsyncResolverInvalidResponseTemplateRule{ + resourceType: "aws_appsync_resolver", + attributeName: "response_template", + max: 65536, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAppsyncResolverInvalidResponseTemplateRule) Name() string { + return "aws_appsync_resolver_invalid_response_template" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppsyncResolverInvalidResponseTemplateRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppsyncResolverInvalidResponseTemplateRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppsyncResolverInvalidResponseTemplateRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppsyncResolverInvalidResponseTemplateRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "response_template must be 65536 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "response_template must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appsync_resolver_invalid_type.go b/rules/awsrules/models/aws_appsync_resolver_invalid_type.go new file mode 100644 index 000000000..c6684dcd7 --- /dev/null +++ b/rules/awsrules/models/aws_appsync_resolver_invalid_type.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAppsyncResolverInvalidTypeRule checks the pattern is valid +type AwsAppsyncResolverInvalidTypeRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsAppsyncResolverInvalidTypeRule returns new rule with default attributes +func NewAwsAppsyncResolverInvalidTypeRule() *AwsAppsyncResolverInvalidTypeRule { + return &AwsAppsyncResolverInvalidTypeRule{ + resourceType: "aws_appsync_resolver", + attributeName: "type", + pattern: regexp.MustCompile(`^[_A-Za-z][_0-9A-Za-z]*$`), + } +} + +// Name returns the rule name +func (r *AwsAppsyncResolverInvalidTypeRule) Name() string { + return "aws_appsync_resolver_invalid_type" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAppsyncResolverInvalidTypeRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAppsyncResolverInvalidTypeRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAppsyncResolverInvalidTypeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAppsyncResolverInvalidTypeRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `type does not match valid pattern ^[_A-Za-z][_0-9A-Za-z]*$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_appsync_resolver_invalid_type_test.go b/rules/awsrules/models/aws_appsync_resolver_invalid_type_test.go new file mode 100644 index 000000000..12427c067 --- /dev/null +++ b/rules/awsrules/models/aws_appsync_resolver_invalid_type_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsAppsyncResolverInvalidTypeRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_appsync_resolver" "foo" { + type = "User-Config" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_appsync_resolver_invalid_type", + Type: "ERROR", + Message: `type does not match valid pattern ^[_A-Za-z][_0-9A-Za-z]*$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_appsync_resolver" "foo" { + type = "Query" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsAppsyncResolverInvalidTypeRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsAppsyncResolverInvalidTypeRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_athena_database_invalid_name.go b/rules/awsrules/models/aws_athena_database_invalid_name.go new file mode 100644 index 000000000..214ea5851 --- /dev/null +++ b/rules/awsrules/models/aws_athena_database_invalid_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAthenaDatabaseInvalidNameRule checks the pattern is valid +type AwsAthenaDatabaseInvalidNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAthenaDatabaseInvalidNameRule returns new rule with default attributes +func NewAwsAthenaDatabaseInvalidNameRule() *AwsAthenaDatabaseInvalidNameRule { + return &AwsAthenaDatabaseInvalidNameRule{ + resourceType: "aws_athena_database", + attributeName: "name", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAthenaDatabaseInvalidNameRule) Name() string { + return "aws_athena_database_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAthenaDatabaseInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAthenaDatabaseInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAthenaDatabaseInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAthenaDatabaseInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "name must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_athena_named_query_invalid_database.go b/rules/awsrules/models/aws_athena_named_query_invalid_database.go new file mode 100644 index 000000000..d5dedfac5 --- /dev/null +++ b/rules/awsrules/models/aws_athena_named_query_invalid_database.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAthenaNamedQueryInvalidDatabaseRule checks the pattern is valid +type AwsAthenaNamedQueryInvalidDatabaseRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAthenaNamedQueryInvalidDatabaseRule returns new rule with default attributes +func NewAwsAthenaNamedQueryInvalidDatabaseRule() *AwsAthenaNamedQueryInvalidDatabaseRule { + return &AwsAthenaNamedQueryInvalidDatabaseRule{ + resourceType: "aws_athena_named_query", + attributeName: "database", + max: 255, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAthenaNamedQueryInvalidDatabaseRule) Name() string { + return "aws_athena_named_query_invalid_database" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAthenaNamedQueryInvalidDatabaseRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAthenaNamedQueryInvalidDatabaseRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAthenaNamedQueryInvalidDatabaseRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAthenaNamedQueryInvalidDatabaseRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "database must be 255 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "database must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_athena_named_query_invalid_description.go b/rules/awsrules/models/aws_athena_named_query_invalid_description.go new file mode 100644 index 000000000..2990e5bcc --- /dev/null +++ b/rules/awsrules/models/aws_athena_named_query_invalid_description.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAthenaNamedQueryInvalidDescriptionRule checks the pattern is valid +type AwsAthenaNamedQueryInvalidDescriptionRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAthenaNamedQueryInvalidDescriptionRule returns new rule with default attributes +func NewAwsAthenaNamedQueryInvalidDescriptionRule() *AwsAthenaNamedQueryInvalidDescriptionRule { + return &AwsAthenaNamedQueryInvalidDescriptionRule{ + resourceType: "aws_athena_named_query", + attributeName: "description", + max: 1024, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAthenaNamedQueryInvalidDescriptionRule) Name() string { + return "aws_athena_named_query_invalid_description" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAthenaNamedQueryInvalidDescriptionRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAthenaNamedQueryInvalidDescriptionRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAthenaNamedQueryInvalidDescriptionRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAthenaNamedQueryInvalidDescriptionRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "description must be 1024 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "description must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_athena_named_query_invalid_name.go b/rules/awsrules/models/aws_athena_named_query_invalid_name.go new file mode 100644 index 000000000..7311e4531 --- /dev/null +++ b/rules/awsrules/models/aws_athena_named_query_invalid_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAthenaNamedQueryInvalidNameRule checks the pattern is valid +type AwsAthenaNamedQueryInvalidNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAthenaNamedQueryInvalidNameRule returns new rule with default attributes +func NewAwsAthenaNamedQueryInvalidNameRule() *AwsAthenaNamedQueryInvalidNameRule { + return &AwsAthenaNamedQueryInvalidNameRule{ + resourceType: "aws_athena_named_query", + attributeName: "name", + max: 128, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAthenaNamedQueryInvalidNameRule) Name() string { + return "aws_athena_named_query_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAthenaNamedQueryInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAthenaNamedQueryInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAthenaNamedQueryInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAthenaNamedQueryInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "name must be 128 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_athena_named_query_invalid_query.go b/rules/awsrules/models/aws_athena_named_query_invalid_query.go new file mode 100644 index 000000000..8563a096c --- /dev/null +++ b/rules/awsrules/models/aws_athena_named_query_invalid_query.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsAthenaNamedQueryInvalidQueryRule checks the pattern is valid +type AwsAthenaNamedQueryInvalidQueryRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsAthenaNamedQueryInvalidQueryRule returns new rule with default attributes +func NewAwsAthenaNamedQueryInvalidQueryRule() *AwsAthenaNamedQueryInvalidQueryRule { + return &AwsAthenaNamedQueryInvalidQueryRule{ + resourceType: "aws_athena_named_query", + attributeName: "query", + max: 262144, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsAthenaNamedQueryInvalidQueryRule) Name() string { + return "aws_athena_named_query_invalid_query" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsAthenaNamedQueryInvalidQueryRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsAthenaNamedQueryInvalidQueryRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsAthenaNamedQueryInvalidQueryRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsAthenaNamedQueryInvalidQueryRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "query must be 262144 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "query must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_backup_selection_invalid_name.go b/rules/awsrules/models/aws_backup_selection_invalid_name.go new file mode 100644 index 000000000..fb7d3c870 --- /dev/null +++ b/rules/awsrules/models/aws_backup_selection_invalid_name.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsBackupSelectionInvalidNameRule checks the pattern is valid +type AwsBackupSelectionInvalidNameRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsBackupSelectionInvalidNameRule returns new rule with default attributes +func NewAwsBackupSelectionInvalidNameRule() *AwsBackupSelectionInvalidNameRule { + return &AwsBackupSelectionInvalidNameRule{ + resourceType: "aws_backup_selection", + attributeName: "name", + pattern: regexp.MustCompile(`^[a-zA-Z0-9\-\_\.]{1,50}$`), + } +} + +// Name returns the rule name +func (r *AwsBackupSelectionInvalidNameRule) Name() string { + return "aws_backup_selection_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsBackupSelectionInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsBackupSelectionInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsBackupSelectionInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsBackupSelectionInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `name does not match valid pattern ^[a-zA-Z0-9\-\_\.]{1,50}$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_backup_selection_invalid_name_test.go b/rules/awsrules/models/aws_backup_selection_invalid_name_test.go new file mode 100644 index 000000000..5a4588f09 --- /dev/null +++ b/rules/awsrules/models/aws_backup_selection_invalid_name_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsBackupSelectionInvalidNameRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_backup_selection" "foo" { + name = "tf_example_backup_selection_tf_example_backup_selection" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_backup_selection_invalid_name", + Type: "ERROR", + Message: `name does not match valid pattern ^[a-zA-Z0-9\-\_\.]{1,50}$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_backup_selection" "foo" { + name = "tf_example_backup_selection" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsBackupSelectionInvalidNameRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsBackupSelectionInvalidNameRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_backup_vault_invalid_name.go b/rules/awsrules/models/aws_backup_vault_invalid_name.go new file mode 100644 index 000000000..3b3229c08 --- /dev/null +++ b/rules/awsrules/models/aws_backup_vault_invalid_name.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsBackupVaultInvalidNameRule checks the pattern is valid +type AwsBackupVaultInvalidNameRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsBackupVaultInvalidNameRule returns new rule with default attributes +func NewAwsBackupVaultInvalidNameRule() *AwsBackupVaultInvalidNameRule { + return &AwsBackupVaultInvalidNameRule{ + resourceType: "aws_backup_vault", + attributeName: "name", + pattern: regexp.MustCompile(`^[a-zA-Z0-9\-\_\.]{1,50}$`), + } +} + +// Name returns the rule name +func (r *AwsBackupVaultInvalidNameRule) Name() string { + return "aws_backup_vault_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsBackupVaultInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsBackupVaultInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsBackupVaultInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsBackupVaultInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `name does not match valid pattern ^[a-zA-Z0-9\-\_\.]{1,50}$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_backup_vault_invalid_name_test.go b/rules/awsrules/models/aws_backup_vault_invalid_name_test.go new file mode 100644 index 000000000..23c3f513d --- /dev/null +++ b/rules/awsrules/models/aws_backup_vault_invalid_name_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsBackupVaultInvalidNameRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_backup_vault" "foo" { + name = "example_backup_vault_example_backup_vault_example_backup_vault" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_backup_vault_invalid_name", + Type: "ERROR", + Message: `name does not match valid pattern ^[a-zA-Z0-9\-\_\.]{1,50}$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_backup_vault" "foo" { + name = "example_backup_vault" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsBackupVaultInvalidNameRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsBackupVaultInvalidNameRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_batch_compute_environment_invalid_state.go b/rules/awsrules/models/aws_batch_compute_environment_invalid_state.go new file mode 100644 index 000000000..9aec1b6be --- /dev/null +++ b/rules/awsrules/models/aws_batch_compute_environment_invalid_state.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsBatchComputeEnvironmentInvalidStateRule checks the pattern is valid +type AwsBatchComputeEnvironmentInvalidStateRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsBatchComputeEnvironmentInvalidStateRule returns new rule with default attributes +func NewAwsBatchComputeEnvironmentInvalidStateRule() *AwsBatchComputeEnvironmentInvalidStateRule { + return &AwsBatchComputeEnvironmentInvalidStateRule{ + resourceType: "aws_batch_compute_environment", + attributeName: "state", + enum: []string{ + "ENABLED", + "DISABLED", + }, + } +} + +// Name returns the rule name +func (r *AwsBatchComputeEnvironmentInvalidStateRule) Name() string { + return "aws_batch_compute_environment_invalid_state" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsBatchComputeEnvironmentInvalidStateRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsBatchComputeEnvironmentInvalidStateRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsBatchComputeEnvironmentInvalidStateRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsBatchComputeEnvironmentInvalidStateRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `state is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_batch_compute_environment_invalid_state_test.go b/rules/awsrules/models/aws_batch_compute_environment_invalid_state_test.go new file mode 100644 index 000000000..a112627a4 --- /dev/null +++ b/rules/awsrules/models/aws_batch_compute_environment_invalid_state_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsBatchComputeEnvironmentInvalidStateRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_batch_compute_environment" "foo" { + state = "ON" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_batch_compute_environment_invalid_state", + Type: "ERROR", + Message: `state is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_batch_compute_environment" "foo" { + state = "ENABLED" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsBatchComputeEnvironmentInvalidStateRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsBatchComputeEnvironmentInvalidStateRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_batch_compute_environment_invalid_type.go b/rules/awsrules/models/aws_batch_compute_environment_invalid_type.go new file mode 100644 index 000000000..c504a1ede --- /dev/null +++ b/rules/awsrules/models/aws_batch_compute_environment_invalid_type.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsBatchComputeEnvironmentInvalidTypeRule checks the pattern is valid +type AwsBatchComputeEnvironmentInvalidTypeRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsBatchComputeEnvironmentInvalidTypeRule returns new rule with default attributes +func NewAwsBatchComputeEnvironmentInvalidTypeRule() *AwsBatchComputeEnvironmentInvalidTypeRule { + return &AwsBatchComputeEnvironmentInvalidTypeRule{ + resourceType: "aws_batch_compute_environment", + attributeName: "type", + enum: []string{ + "MANAGED", + "UNMANAGED", + }, + } +} + +// Name returns the rule name +func (r *AwsBatchComputeEnvironmentInvalidTypeRule) Name() string { + return "aws_batch_compute_environment_invalid_type" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsBatchComputeEnvironmentInvalidTypeRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsBatchComputeEnvironmentInvalidTypeRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsBatchComputeEnvironmentInvalidTypeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsBatchComputeEnvironmentInvalidTypeRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `type is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_batch_compute_environment_invalid_type_test.go b/rules/awsrules/models/aws_batch_compute_environment_invalid_type_test.go new file mode 100644 index 000000000..2267c7b8d --- /dev/null +++ b/rules/awsrules/models/aws_batch_compute_environment_invalid_type_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsBatchComputeEnvironmentInvalidTypeRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_batch_compute_environment" "foo" { + type = "CONTROLLED" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_batch_compute_environment_invalid_type", + Type: "ERROR", + Message: `type is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_batch_compute_environment" "foo" { + type = "MANAGED" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsBatchComputeEnvironmentInvalidTypeRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsBatchComputeEnvironmentInvalidTypeRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_batch_job_definition_invalid_type.go b/rules/awsrules/models/aws_batch_job_definition_invalid_type.go new file mode 100644 index 000000000..1ed996829 --- /dev/null +++ b/rules/awsrules/models/aws_batch_job_definition_invalid_type.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsBatchJobDefinitionInvalidTypeRule checks the pattern is valid +type AwsBatchJobDefinitionInvalidTypeRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsBatchJobDefinitionInvalidTypeRule returns new rule with default attributes +func NewAwsBatchJobDefinitionInvalidTypeRule() *AwsBatchJobDefinitionInvalidTypeRule { + return &AwsBatchJobDefinitionInvalidTypeRule{ + resourceType: "aws_batch_job_definition", + attributeName: "type", + enum: []string{ + "container", + "multinode", + }, + } +} + +// Name returns the rule name +func (r *AwsBatchJobDefinitionInvalidTypeRule) Name() string { + return "aws_batch_job_definition_invalid_type" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsBatchJobDefinitionInvalidTypeRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsBatchJobDefinitionInvalidTypeRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsBatchJobDefinitionInvalidTypeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsBatchJobDefinitionInvalidTypeRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `type is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_batch_job_definition_invalid_type_test.go b/rules/awsrules/models/aws_batch_job_definition_invalid_type_test.go new file mode 100644 index 000000000..8d595e704 --- /dev/null +++ b/rules/awsrules/models/aws_batch_job_definition_invalid_type_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsBatchJobDefinitionInvalidTypeRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_batch_job_definition" "foo" { + type = "docker" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_batch_job_definition_invalid_type", + Type: "ERROR", + Message: `type is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_batch_job_definition" "foo" { + type = "container" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsBatchJobDefinitionInvalidTypeRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsBatchJobDefinitionInvalidTypeRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_batch_job_queue_invalid_state.go b/rules/awsrules/models/aws_batch_job_queue_invalid_state.go new file mode 100644 index 000000000..74e9a073f --- /dev/null +++ b/rules/awsrules/models/aws_batch_job_queue_invalid_state.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsBatchJobQueueInvalidStateRule checks the pattern is valid +type AwsBatchJobQueueInvalidStateRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsBatchJobQueueInvalidStateRule returns new rule with default attributes +func NewAwsBatchJobQueueInvalidStateRule() *AwsBatchJobQueueInvalidStateRule { + return &AwsBatchJobQueueInvalidStateRule{ + resourceType: "aws_batch_job_queue", + attributeName: "state", + enum: []string{ + "ENABLED", + "DISABLED", + }, + } +} + +// Name returns the rule name +func (r *AwsBatchJobQueueInvalidStateRule) Name() string { + return "aws_batch_job_queue_invalid_state" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsBatchJobQueueInvalidStateRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsBatchJobQueueInvalidStateRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsBatchJobQueueInvalidStateRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsBatchJobQueueInvalidStateRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `state is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_batch_job_queue_invalid_state_test.go b/rules/awsrules/models/aws_batch_job_queue_invalid_state_test.go new file mode 100644 index 000000000..2a1d8ca51 --- /dev/null +++ b/rules/awsrules/models/aws_batch_job_queue_invalid_state_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsBatchJobQueueInvalidStateRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_batch_job_queue" "foo" { + state = "ON" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_batch_job_queue_invalid_state", + Type: "ERROR", + Message: `state is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_batch_job_queue" "foo" { + state = "ENABLED" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsBatchJobQueueInvalidStateRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsBatchJobQueueInvalidStateRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_budgets_budget_invalid_account_id.go b/rules/awsrules/models/aws_budgets_budget_invalid_account_id.go new file mode 100644 index 000000000..5f099f2a0 --- /dev/null +++ b/rules/awsrules/models/aws_budgets_budget_invalid_account_id.go @@ -0,0 +1,87 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsBudgetsBudgetInvalidAccountIDRule checks the pattern is valid +type AwsBudgetsBudgetInvalidAccountIDRule struct { + resourceType string + attributeName string + max int + min int + pattern *regexp.Regexp +} + +// NewAwsBudgetsBudgetInvalidAccountIDRule returns new rule with default attributes +func NewAwsBudgetsBudgetInvalidAccountIDRule() *AwsBudgetsBudgetInvalidAccountIDRule { + return &AwsBudgetsBudgetInvalidAccountIDRule{ + resourceType: "aws_budgets_budget", + attributeName: "account_id", + max: 12, + min: 12, + pattern: regexp.MustCompile(`^\d{12}$`), + } +} + +// Name returns the rule name +func (r *AwsBudgetsBudgetInvalidAccountIDRule) Name() string { + return "aws_budgets_budget_invalid_account_id" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsBudgetsBudgetInvalidAccountIDRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsBudgetsBudgetInvalidAccountIDRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsBudgetsBudgetInvalidAccountIDRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsBudgetsBudgetInvalidAccountIDRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "account_id must be 12 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "account_id must be 12 characters or higher", + attribute.Expr.Range(), + ) + } + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `account_id does not match valid pattern ^\d{12}$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_budgets_budget_invalid_account_id_test.go b/rules/awsrules/models/aws_budgets_budget_invalid_account_id_test.go new file mode 100644 index 000000000..f82444cdc --- /dev/null +++ b/rules/awsrules/models/aws_budgets_budget_invalid_account_id_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsBudgetsBudgetInvalidAccountIDRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_budgets_budget" "foo" { + account_id = "abcdefghijkl" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_budgets_budget_invalid_account_id", + Type: "ERROR", + Message: `account_id does not match valid pattern ^\d{12}$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_budgets_budget" "foo" { + account_id = "123456789012" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsBudgetsBudgetInvalidAccountIDRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsBudgetsBudgetInvalidAccountIDRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_budgets_budget_invalid_budget_type.go b/rules/awsrules/models/aws_budgets_budget_invalid_budget_type.go new file mode 100644 index 000000000..c2143d933 --- /dev/null +++ b/rules/awsrules/models/aws_budgets_budget_invalid_budget_type.go @@ -0,0 +1,79 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsBudgetsBudgetInvalidBudgetTypeRule checks the pattern is valid +type AwsBudgetsBudgetInvalidBudgetTypeRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsBudgetsBudgetInvalidBudgetTypeRule returns new rule with default attributes +func NewAwsBudgetsBudgetInvalidBudgetTypeRule() *AwsBudgetsBudgetInvalidBudgetTypeRule { + return &AwsBudgetsBudgetInvalidBudgetTypeRule{ + resourceType: "aws_budgets_budget", + attributeName: "budget_type", + enum: []string{ + "USAGE", + "COST", + "RI_UTILIZATION", + "RI_COVERAGE", + }, + } +} + +// Name returns the rule name +func (r *AwsBudgetsBudgetInvalidBudgetTypeRule) Name() string { + return "aws_budgets_budget_invalid_budget_type" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsBudgetsBudgetInvalidBudgetTypeRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsBudgetsBudgetInvalidBudgetTypeRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsBudgetsBudgetInvalidBudgetTypeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsBudgetsBudgetInvalidBudgetTypeRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `budget_type is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_budgets_budget_invalid_budget_type_test.go b/rules/awsrules/models/aws_budgets_budget_invalid_budget_type_test.go new file mode 100644 index 000000000..a207d5c56 --- /dev/null +++ b/rules/awsrules/models/aws_budgets_budget_invalid_budget_type_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsBudgetsBudgetInvalidBudgetTypeRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_budgets_budget" "foo" { + budget_type = "MONEY" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_budgets_budget_invalid_budget_type", + Type: "ERROR", + Message: `budget_type is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_budgets_budget" "foo" { + budget_type = "USAGE" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsBudgetsBudgetInvalidBudgetTypeRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsBudgetsBudgetInvalidBudgetTypeRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_budgets_budget_invalid_name.go b/rules/awsrules/models/aws_budgets_budget_invalid_name.go new file mode 100644 index 000000000..cd5a92356 --- /dev/null +++ b/rules/awsrules/models/aws_budgets_budget_invalid_name.go @@ -0,0 +1,87 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsBudgetsBudgetInvalidNameRule checks the pattern is valid +type AwsBudgetsBudgetInvalidNameRule struct { + resourceType string + attributeName string + max int + min int + pattern *regexp.Regexp +} + +// NewAwsBudgetsBudgetInvalidNameRule returns new rule with default attributes +func NewAwsBudgetsBudgetInvalidNameRule() *AwsBudgetsBudgetInvalidNameRule { + return &AwsBudgetsBudgetInvalidNameRule{ + resourceType: "aws_budgets_budget", + attributeName: "name", + max: 100, + min: 1, + pattern: regexp.MustCompile(`^[^:\\]+$`), + } +} + +// Name returns the rule name +func (r *AwsBudgetsBudgetInvalidNameRule) Name() string { + return "aws_budgets_budget_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsBudgetsBudgetInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsBudgetsBudgetInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsBudgetsBudgetInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsBudgetsBudgetInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "name must be 100 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `name does not match valid pattern ^[^:\\]+$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_budgets_budget_invalid_name_test.go b/rules/awsrules/models/aws_budgets_budget_invalid_name_test.go new file mode 100644 index 000000000..44f8df5d5 --- /dev/null +++ b/rules/awsrules/models/aws_budgets_budget_invalid_name_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsBudgetsBudgetInvalidNameRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_budgets_budget" "foo" { + name = "budget:ec2:monthly" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_budgets_budget_invalid_name", + Type: "ERROR", + Message: `name does not match valid pattern ^[^:\\]+$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_budgets_budget" "foo" { + name = "budget-ec2-monthly" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsBudgetsBudgetInvalidNameRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsBudgetsBudgetInvalidNameRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_budgets_budget_invalid_time_unit.go b/rules/awsrules/models/aws_budgets_budget_invalid_time_unit.go new file mode 100644 index 000000000..60eeb8f3b --- /dev/null +++ b/rules/awsrules/models/aws_budgets_budget_invalid_time_unit.go @@ -0,0 +1,79 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsBudgetsBudgetInvalidTimeUnitRule checks the pattern is valid +type AwsBudgetsBudgetInvalidTimeUnitRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsBudgetsBudgetInvalidTimeUnitRule returns new rule with default attributes +func NewAwsBudgetsBudgetInvalidTimeUnitRule() *AwsBudgetsBudgetInvalidTimeUnitRule { + return &AwsBudgetsBudgetInvalidTimeUnitRule{ + resourceType: "aws_budgets_budget", + attributeName: "time_unit", + enum: []string{ + "DAILY", + "MONTHLY", + "QUARTERLY", + "ANNUALLY", + }, + } +} + +// Name returns the rule name +func (r *AwsBudgetsBudgetInvalidTimeUnitRule) Name() string { + return "aws_budgets_budget_invalid_time_unit" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsBudgetsBudgetInvalidTimeUnitRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsBudgetsBudgetInvalidTimeUnitRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsBudgetsBudgetInvalidTimeUnitRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsBudgetsBudgetInvalidTimeUnitRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `time_unit is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_budgets_budget_invalid_time_unit_test.go b/rules/awsrules/models/aws_budgets_budget_invalid_time_unit_test.go new file mode 100644 index 000000000..c14058683 --- /dev/null +++ b/rules/awsrules/models/aws_budgets_budget_invalid_time_unit_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsBudgetsBudgetInvalidTimeUnitRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_budgets_budget" "foo" { + time_unit = "HOURLY" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_budgets_budget_invalid_time_unit", + Type: "ERROR", + Message: `time_unit is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_budgets_budget" "foo" { + time_unit = "MONTHLY" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsBudgetsBudgetInvalidTimeUnitRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsBudgetsBudgetInvalidTimeUnitRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_automatic_stop_time_minutes.go b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_automatic_stop_time_minutes.go new file mode 100644 index 000000000..e42749f80 --- /dev/null +++ b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_automatic_stop_time_minutes.go @@ -0,0 +1,68 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule checks the pattern is valid +type AwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule struct { + resourceType string + attributeName string + max int +} + +// NewAwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule returns new rule with default attributes +func NewAwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule() *AwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule { + return &AwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule{ + resourceType: "aws_cloud9_environment_ec2", + attributeName: "automatic_stop_time_minutes", + max: 20160, + } +} + +// Name returns the rule name +func (r *AwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule) Name() string { + return "aws_cloud9_environment_ec2_invalid_automatic_stop_time_minutes" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "automatic_stop_time_minutes must be 20160 characters or less", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_description.go b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_description.go new file mode 100644 index 000000000..ca5c4fb29 --- /dev/null +++ b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_description.go @@ -0,0 +1,68 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloud9EnvironmentEc2InvalidDescriptionRule checks the pattern is valid +type AwsCloud9EnvironmentEc2InvalidDescriptionRule struct { + resourceType string + attributeName string + max int +} + +// NewAwsCloud9EnvironmentEc2InvalidDescriptionRule returns new rule with default attributes +func NewAwsCloud9EnvironmentEc2InvalidDescriptionRule() *AwsCloud9EnvironmentEc2InvalidDescriptionRule { + return &AwsCloud9EnvironmentEc2InvalidDescriptionRule{ + resourceType: "aws_cloud9_environment_ec2", + attributeName: "description", + max: 200, + } +} + +// Name returns the rule name +func (r *AwsCloud9EnvironmentEc2InvalidDescriptionRule) Name() string { + return "aws_cloud9_environment_ec2_invalid_description" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloud9EnvironmentEc2InvalidDescriptionRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloud9EnvironmentEc2InvalidDescriptionRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloud9EnvironmentEc2InvalidDescriptionRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloud9EnvironmentEc2InvalidDescriptionRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "description must be 200 characters or less", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_instance_type.go b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_instance_type.go new file mode 100644 index 000000000..22c83d4f2 --- /dev/null +++ b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_instance_type.go @@ -0,0 +1,87 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloud9EnvironmentEc2InvalidInstanceTypeRule checks the pattern is valid +type AwsCloud9EnvironmentEc2InvalidInstanceTypeRule struct { + resourceType string + attributeName string + max int + min int + pattern *regexp.Regexp +} + +// NewAwsCloud9EnvironmentEc2InvalidInstanceTypeRule returns new rule with default attributes +func NewAwsCloud9EnvironmentEc2InvalidInstanceTypeRule() *AwsCloud9EnvironmentEc2InvalidInstanceTypeRule { + return &AwsCloud9EnvironmentEc2InvalidInstanceTypeRule{ + resourceType: "aws_cloud9_environment_ec2", + attributeName: "instance_type", + max: 20, + min: 5, + pattern: regexp.MustCompile(`^[a-z][1-9][.][a-z0-9]+$`), + } +} + +// Name returns the rule name +func (r *AwsCloud9EnvironmentEc2InvalidInstanceTypeRule) Name() string { + return "aws_cloud9_environment_ec2_invalid_instance_type" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloud9EnvironmentEc2InvalidInstanceTypeRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloud9EnvironmentEc2InvalidInstanceTypeRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloud9EnvironmentEc2InvalidInstanceTypeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloud9EnvironmentEc2InvalidInstanceTypeRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "instance_type must be 20 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "instance_type must be 5 characters or higher", + attribute.Expr.Range(), + ) + } + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `instance_type does not match valid pattern ^[a-z][1-9][.][a-z0-9]+$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_instance_type_test.go b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_instance_type_test.go new file mode 100644 index 000000000..219cdaf35 --- /dev/null +++ b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_instance_type_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloud9EnvironmentEc2InvalidInstanceTypeRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloud9_environment_ec2" "foo" { + instance_type = "t20.micro" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloud9_environment_ec2_invalid_instance_type", + Type: "ERROR", + Message: `instance_type does not match valid pattern ^[a-z][1-9][.][a-z0-9]+$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloud9_environment_ec2" "foo" { + instance_type = "t2.micro" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloud9EnvironmentEc2InvalidInstanceTypeRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloud9EnvironmentEc2InvalidInstanceTypeRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_name.go b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_name.go new file mode 100644 index 000000000..de90fe74e --- /dev/null +++ b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_name.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloud9EnvironmentEc2InvalidNameRule checks the pattern is valid +type AwsCloud9EnvironmentEc2InvalidNameRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsCloud9EnvironmentEc2InvalidNameRule returns new rule with default attributes +func NewAwsCloud9EnvironmentEc2InvalidNameRule() *AwsCloud9EnvironmentEc2InvalidNameRule { + return &AwsCloud9EnvironmentEc2InvalidNameRule{ + resourceType: "aws_cloud9_environment_ec2", + attributeName: "name", + max: 60, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsCloud9EnvironmentEc2InvalidNameRule) Name() string { + return "aws_cloud9_environment_ec2_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloud9EnvironmentEc2InvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloud9EnvironmentEc2InvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloud9EnvironmentEc2InvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloud9EnvironmentEc2InvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "name must be 60 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_owner_arn.go b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_owner_arn.go new file mode 100644 index 000000000..11d57807f --- /dev/null +++ b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_owner_arn.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloud9EnvironmentEc2InvalidOwnerArnRule checks the pattern is valid +type AwsCloud9EnvironmentEc2InvalidOwnerArnRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsCloud9EnvironmentEc2InvalidOwnerArnRule returns new rule with default attributes +func NewAwsCloud9EnvironmentEc2InvalidOwnerArnRule() *AwsCloud9EnvironmentEc2InvalidOwnerArnRule { + return &AwsCloud9EnvironmentEc2InvalidOwnerArnRule{ + resourceType: "aws_cloud9_environment_ec2", + attributeName: "owner_arn", + pattern: regexp.MustCompile(`^arn:aws:(iam|sts)::\d+:(root|user|federated-user|assumed-role)\/?\S*$`), + } +} + +// Name returns the rule name +func (r *AwsCloud9EnvironmentEc2InvalidOwnerArnRule) Name() string { + return "aws_cloud9_environment_ec2_invalid_owner_arn" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloud9EnvironmentEc2InvalidOwnerArnRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloud9EnvironmentEc2InvalidOwnerArnRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloud9EnvironmentEc2InvalidOwnerArnRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloud9EnvironmentEc2InvalidOwnerArnRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `owner_arn does not match valid pattern ^arn:aws:(iam|sts)::\d+:(root|user|federated-user|assumed-role)\/?\S*$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_owner_arn_test.go b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_owner_arn_test.go new file mode 100644 index 000000000..7b36d2136 --- /dev/null +++ b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_owner_arn_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloud9EnvironmentEc2InvalidOwnerArnRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloud9_environment_ec2" "foo" { + owner_arn = "arn:aws:elasticbeanstalk:us-east-1:123456789012:environment/My App/MyEnvironment" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloud9_environment_ec2_invalid_owner_arn", + Type: "ERROR", + Message: `owner_arn does not match valid pattern ^arn:aws:(iam|sts)::\d+:(root|user|federated-user|assumed-role)\/?\S*$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloud9_environment_ec2" "foo" { + owner_arn = "arn:aws:iam::123456789012:user/David" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloud9EnvironmentEc2InvalidOwnerArnRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloud9EnvironmentEc2InvalidOwnerArnRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_subnet_id.go b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_subnet_id.go new file mode 100644 index 000000000..744e3433a --- /dev/null +++ b/rules/awsrules/models/aws_cloud9_environment_ec2_invalid_subnet_id.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloud9EnvironmentEc2InvalidSubnetIDRule checks the pattern is valid +type AwsCloud9EnvironmentEc2InvalidSubnetIDRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsCloud9EnvironmentEc2InvalidSubnetIDRule returns new rule with default attributes +func NewAwsCloud9EnvironmentEc2InvalidSubnetIDRule() *AwsCloud9EnvironmentEc2InvalidSubnetIDRule { + return &AwsCloud9EnvironmentEc2InvalidSubnetIDRule{ + resourceType: "aws_cloud9_environment_ec2", + attributeName: "subnet_id", + max: 30, + min: 5, + } +} + +// Name returns the rule name +func (r *AwsCloud9EnvironmentEc2InvalidSubnetIDRule) Name() string { + return "aws_cloud9_environment_ec2_invalid_subnet_id" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloud9EnvironmentEc2InvalidSubnetIDRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloud9EnvironmentEc2InvalidSubnetIDRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloud9EnvironmentEc2InvalidSubnetIDRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloud9EnvironmentEc2InvalidSubnetIDRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "subnet_id must be 30 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "subnet_id must be 5 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_invalid_capabilities.go b/rules/awsrules/models/aws_cloudformation_stack_invalid_capabilities.go new file mode 100644 index 000000000..a09ebc9d0 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_invalid_capabilities.go @@ -0,0 +1,78 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackInvalidCapabilitiesRule checks the pattern is valid +type AwsCloudformationStackInvalidCapabilitiesRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsCloudformationStackInvalidCapabilitiesRule returns new rule with default attributes +func NewAwsCloudformationStackInvalidCapabilitiesRule() *AwsCloudformationStackInvalidCapabilitiesRule { + return &AwsCloudformationStackInvalidCapabilitiesRule{ + resourceType: "aws_cloudformation_stack", + attributeName: "capabilities", + enum: []string{ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND", + }, + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackInvalidCapabilitiesRule) Name() string { + return "aws_cloudformation_stack_invalid_capabilities" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackInvalidCapabilitiesRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackInvalidCapabilitiesRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackInvalidCapabilitiesRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackInvalidCapabilitiesRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `capabilities is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_invalid_capabilities_test.go b/rules/awsrules/models/aws_cloudformation_stack_invalid_capabilities_test.go new file mode 100644 index 000000000..a6d13647f --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_invalid_capabilities_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudformationStackInvalidCapabilitiesRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudformation_stack" "foo" { + capabilities = "CAPABILITY_EXPAND" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudformation_stack_invalid_capabilities", + Type: "ERROR", + Message: `capabilities is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudformation_stack" "foo" { + capabilities = "CAPABILITY_NAMED_IAM" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudformationStackInvalidCapabilitiesRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudformationStackInvalidCapabilitiesRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_invalid_iam_role_arn.go b/rules/awsrules/models/aws_cloudformation_stack_invalid_iam_role_arn.go new file mode 100644 index 000000000..08f819625 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_invalid_iam_role_arn.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackInvalidIAMRoleArnRule checks the pattern is valid +type AwsCloudformationStackInvalidIAMRoleArnRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsCloudformationStackInvalidIAMRoleArnRule returns new rule with default attributes +func NewAwsCloudformationStackInvalidIAMRoleArnRule() *AwsCloudformationStackInvalidIAMRoleArnRule { + return &AwsCloudformationStackInvalidIAMRoleArnRule{ + resourceType: "aws_cloudformation_stack", + attributeName: "iam_role_arn", + max: 2048, + min: 20, + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackInvalidIAMRoleArnRule) Name() string { + return "aws_cloudformation_stack_invalid_iam_role_arn" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackInvalidIAMRoleArnRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackInvalidIAMRoleArnRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackInvalidIAMRoleArnRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackInvalidIAMRoleArnRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "iam_role_arn must be 2048 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "iam_role_arn must be 20 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_invalid_on_failure.go b/rules/awsrules/models/aws_cloudformation_stack_invalid_on_failure.go new file mode 100644 index 000000000..e8a2e2743 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_invalid_on_failure.go @@ -0,0 +1,78 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackInvalidOnFailureRule checks the pattern is valid +type AwsCloudformationStackInvalidOnFailureRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsCloudformationStackInvalidOnFailureRule returns new rule with default attributes +func NewAwsCloudformationStackInvalidOnFailureRule() *AwsCloudformationStackInvalidOnFailureRule { + return &AwsCloudformationStackInvalidOnFailureRule{ + resourceType: "aws_cloudformation_stack", + attributeName: "on_failure", + enum: []string{ + "DO_NOTHING", + "ROLLBACK", + "DELETE", + }, + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackInvalidOnFailureRule) Name() string { + return "aws_cloudformation_stack_invalid_on_failure" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackInvalidOnFailureRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackInvalidOnFailureRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackInvalidOnFailureRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackInvalidOnFailureRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `on_failure is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_invalid_on_failure_test.go b/rules/awsrules/models/aws_cloudformation_stack_invalid_on_failure_test.go new file mode 100644 index 000000000..e098265b5 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_invalid_on_failure_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudformationStackInvalidOnFailureRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudformation_stack" "foo" { + on_failure = "DO_ANYTHING" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudformation_stack_invalid_on_failure", + Type: "ERROR", + Message: `on_failure is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudformation_stack" "foo" { + on_failure = "DO_NOTHING" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudformationStackInvalidOnFailureRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudformationStackInvalidOnFailureRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_invalid_policy_body.go b/rules/awsrules/models/aws_cloudformation_stack_invalid_policy_body.go new file mode 100644 index 000000000..24207653b --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_invalid_policy_body.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackInvalidPolicyBodyRule checks the pattern is valid +type AwsCloudformationStackInvalidPolicyBodyRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsCloudformationStackInvalidPolicyBodyRule returns new rule with default attributes +func NewAwsCloudformationStackInvalidPolicyBodyRule() *AwsCloudformationStackInvalidPolicyBodyRule { + return &AwsCloudformationStackInvalidPolicyBodyRule{ + resourceType: "aws_cloudformation_stack", + attributeName: "policy_body", + max: 16384, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackInvalidPolicyBodyRule) Name() string { + return "aws_cloudformation_stack_invalid_policy_body" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackInvalidPolicyBodyRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackInvalidPolicyBodyRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackInvalidPolicyBodyRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackInvalidPolicyBodyRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "policy_body must be 16384 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "policy_body must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_invalid_policy_url.go b/rules/awsrules/models/aws_cloudformation_stack_invalid_policy_url.go new file mode 100644 index 000000000..53bb4ef89 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_invalid_policy_url.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackInvalidPolicyURLRule checks the pattern is valid +type AwsCloudformationStackInvalidPolicyURLRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsCloudformationStackInvalidPolicyURLRule returns new rule with default attributes +func NewAwsCloudformationStackInvalidPolicyURLRule() *AwsCloudformationStackInvalidPolicyURLRule { + return &AwsCloudformationStackInvalidPolicyURLRule{ + resourceType: "aws_cloudformation_stack", + attributeName: "policy_url", + max: 1350, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackInvalidPolicyURLRule) Name() string { + return "aws_cloudformation_stack_invalid_policy_url" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackInvalidPolicyURLRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackInvalidPolicyURLRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackInvalidPolicyURLRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackInvalidPolicyURLRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "policy_url must be 1350 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "policy_url must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_invalid_template_url.go b/rules/awsrules/models/aws_cloudformation_stack_invalid_template_url.go new file mode 100644 index 000000000..fb933fae8 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_invalid_template_url.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackInvalidTemplateURLRule checks the pattern is valid +type AwsCloudformationStackInvalidTemplateURLRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsCloudformationStackInvalidTemplateURLRule returns new rule with default attributes +func NewAwsCloudformationStackInvalidTemplateURLRule() *AwsCloudformationStackInvalidTemplateURLRule { + return &AwsCloudformationStackInvalidTemplateURLRule{ + resourceType: "aws_cloudformation_stack", + attributeName: "template_url", + max: 1024, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackInvalidTemplateURLRule) Name() string { + return "aws_cloudformation_stack_invalid_template_url" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackInvalidTemplateURLRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackInvalidTemplateURLRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackInvalidTemplateURLRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackInvalidTemplateURLRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "template_url must be 1024 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "template_url must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_set_instance_invalid_account_id.go b/rules/awsrules/models/aws_cloudformation_stack_set_instance_invalid_account_id.go new file mode 100644 index 000000000..ce3304411 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_set_instance_invalid_account_id.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackSetInstanceInvalidAccountIDRule checks the pattern is valid +type AwsCloudformationStackSetInstanceInvalidAccountIDRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsCloudformationStackSetInstanceInvalidAccountIDRule returns new rule with default attributes +func NewAwsCloudformationStackSetInstanceInvalidAccountIDRule() *AwsCloudformationStackSetInstanceInvalidAccountIDRule { + return &AwsCloudformationStackSetInstanceInvalidAccountIDRule{ + resourceType: "aws_cloudformation_stack_set_instance", + attributeName: "account_id", + pattern: regexp.MustCompile(`^[0-9]{12}$`), + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackSetInstanceInvalidAccountIDRule) Name() string { + return "aws_cloudformation_stack_set_instance_invalid_account_id" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackSetInstanceInvalidAccountIDRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackSetInstanceInvalidAccountIDRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackSetInstanceInvalidAccountIDRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackSetInstanceInvalidAccountIDRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `account_id does not match valid pattern ^[0-9]{12}$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_set_instance_invalid_account_id_test.go b/rules/awsrules/models/aws_cloudformation_stack_set_instance_invalid_account_id_test.go new file mode 100644 index 000000000..5a3be26c1 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_set_instance_invalid_account_id_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudformationStackSetInstanceInvalidAccountIDRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudformation_stack_set_instance" "foo" { + account_id = "1234567890123" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudformation_stack_set_instance_invalid_account_id", + Type: "ERROR", + Message: `account_id does not match valid pattern ^[0-9]{12}$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudformation_stack_set_instance" "foo" { + account_id = "123456789012" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudformationStackSetInstanceInvalidAccountIDRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudformationStackSetInstanceInvalidAccountIDRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_set_invalid_administration_role_arn.go b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_administration_role_arn.go new file mode 100644 index 000000000..f48df809b --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_administration_role_arn.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackSetInvalidAdministrationRoleArnRule checks the pattern is valid +type AwsCloudformationStackSetInvalidAdministrationRoleArnRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsCloudformationStackSetInvalidAdministrationRoleArnRule returns new rule with default attributes +func NewAwsCloudformationStackSetInvalidAdministrationRoleArnRule() *AwsCloudformationStackSetInvalidAdministrationRoleArnRule { + return &AwsCloudformationStackSetInvalidAdministrationRoleArnRule{ + resourceType: "aws_cloudformation_stack_set", + attributeName: "administration_role_arn", + max: 2048, + min: 20, + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackSetInvalidAdministrationRoleArnRule) Name() string { + return "aws_cloudformation_stack_set_invalid_administration_role_arn" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackSetInvalidAdministrationRoleArnRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackSetInvalidAdministrationRoleArnRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackSetInvalidAdministrationRoleArnRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackSetInvalidAdministrationRoleArnRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "administration_role_arn must be 2048 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "administration_role_arn must be 20 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_set_invalid_capabilities.go b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_capabilities.go new file mode 100644 index 000000000..5cd248fbb --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_capabilities.go @@ -0,0 +1,78 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackSetInvalidCapabilitiesRule checks the pattern is valid +type AwsCloudformationStackSetInvalidCapabilitiesRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsCloudformationStackSetInvalidCapabilitiesRule returns new rule with default attributes +func NewAwsCloudformationStackSetInvalidCapabilitiesRule() *AwsCloudformationStackSetInvalidCapabilitiesRule { + return &AwsCloudformationStackSetInvalidCapabilitiesRule{ + resourceType: "aws_cloudformation_stack_set", + attributeName: "capabilities", + enum: []string{ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND", + }, + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackSetInvalidCapabilitiesRule) Name() string { + return "aws_cloudformation_stack_set_invalid_capabilities" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackSetInvalidCapabilitiesRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackSetInvalidCapabilitiesRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackSetInvalidCapabilitiesRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackSetInvalidCapabilitiesRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `capabilities is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_set_invalid_capabilities_test.go b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_capabilities_test.go new file mode 100644 index 000000000..ca5aec4b1 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_capabilities_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudformationStackSetInvalidCapabilitiesRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudformation_stack_set" "foo" { + capabilities = "CAPABILITY_EXPAND" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudformation_stack_set_invalid_capabilities", + Type: "ERROR", + Message: `capabilities is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudformation_stack_set" "foo" { + capabilities = "CAPABILITY_NAMED_IAM" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudformationStackSetInvalidCapabilitiesRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudformationStackSetInvalidCapabilitiesRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_set_invalid_description.go b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_description.go new file mode 100644 index 000000000..353102cde --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_description.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackSetInvalidDescriptionRule checks the pattern is valid +type AwsCloudformationStackSetInvalidDescriptionRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsCloudformationStackSetInvalidDescriptionRule returns new rule with default attributes +func NewAwsCloudformationStackSetInvalidDescriptionRule() *AwsCloudformationStackSetInvalidDescriptionRule { + return &AwsCloudformationStackSetInvalidDescriptionRule{ + resourceType: "aws_cloudformation_stack_set", + attributeName: "description", + max: 1024, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackSetInvalidDescriptionRule) Name() string { + return "aws_cloudformation_stack_set_invalid_description" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackSetInvalidDescriptionRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackSetInvalidDescriptionRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackSetInvalidDescriptionRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackSetInvalidDescriptionRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "description must be 1024 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "description must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_set_invalid_execution_role_name.go b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_execution_role_name.go new file mode 100644 index 000000000..40bd6e978 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_execution_role_name.go @@ -0,0 +1,87 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackSetInvalidExecutionRoleNameRule checks the pattern is valid +type AwsCloudformationStackSetInvalidExecutionRoleNameRule struct { + resourceType string + attributeName string + max int + min int + pattern *regexp.Regexp +} + +// NewAwsCloudformationStackSetInvalidExecutionRoleNameRule returns new rule with default attributes +func NewAwsCloudformationStackSetInvalidExecutionRoleNameRule() *AwsCloudformationStackSetInvalidExecutionRoleNameRule { + return &AwsCloudformationStackSetInvalidExecutionRoleNameRule{ + resourceType: "aws_cloudformation_stack_set", + attributeName: "execution_role_name", + max: 64, + min: 1, + pattern: regexp.MustCompile(`^[a-zA-Z_0-9+=,.@-]+$`), + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackSetInvalidExecutionRoleNameRule) Name() string { + return "aws_cloudformation_stack_set_invalid_execution_role_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackSetInvalidExecutionRoleNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackSetInvalidExecutionRoleNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackSetInvalidExecutionRoleNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackSetInvalidExecutionRoleNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "execution_role_name must be 64 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "execution_role_name must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `execution_role_name does not match valid pattern ^[a-zA-Z_0-9+=,.@-]+$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_set_invalid_execution_role_name_test.go b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_execution_role_name_test.go new file mode 100644 index 000000000..db3586ae1 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_execution_role_name_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudformationStackSetInvalidExecutionRoleNameRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudformation_stack_set" "foo" { + execution_role_name = "AWSCloudFormation/StackSet/ExecutionRole" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudformation_stack_set_invalid_execution_role_name", + Type: "ERROR", + Message: `execution_role_name does not match valid pattern ^[a-zA-Z_0-9+=,.@-]+$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudformation_stack_set" "foo" { + execution_role_name = "AWSCloudFormationStackSetExecutionRole" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudformationStackSetInvalidExecutionRoleNameRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudformationStackSetInvalidExecutionRoleNameRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudformation_stack_set_invalid_template_url.go b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_template_url.go new file mode 100644 index 000000000..ac4fde421 --- /dev/null +++ b/rules/awsrules/models/aws_cloudformation_stack_set_invalid_template_url.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudformationStackSetInvalidTemplateURLRule checks the pattern is valid +type AwsCloudformationStackSetInvalidTemplateURLRule struct { + resourceType string + attributeName string + max int + min int +} + +// NewAwsCloudformationStackSetInvalidTemplateURLRule returns new rule with default attributes +func NewAwsCloudformationStackSetInvalidTemplateURLRule() *AwsCloudformationStackSetInvalidTemplateURLRule { + return &AwsCloudformationStackSetInvalidTemplateURLRule{ + resourceType: "aws_cloudformation_stack_set", + attributeName: "template_url", + max: 1024, + min: 1, + } +} + +// Name returns the rule name +func (r *AwsCloudformationStackSetInvalidTemplateURLRule) Name() string { + return "aws_cloudformation_stack_set_invalid_template_url" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudformationStackSetInvalidTemplateURLRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudformationStackSetInvalidTemplateURLRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudformationStackSetInvalidTemplateURLRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudformationStackSetInvalidTemplateURLRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "template_url must be 1024 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "template_url must be 1 characters or higher", + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudfront_distribution_invalid_http_version.go b/rules/awsrules/models/aws_cloudfront_distribution_invalid_http_version.go new file mode 100644 index 000000000..4a99e3493 --- /dev/null +++ b/rules/awsrules/models/aws_cloudfront_distribution_invalid_http_version.go @@ -0,0 +1,77 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudfrontDistributionInvalidHTTPVersionRule checks the pattern is valid +type AwsCloudfrontDistributionInvalidHTTPVersionRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsCloudfrontDistributionInvalidHTTPVersionRule returns new rule with default attributes +func NewAwsCloudfrontDistributionInvalidHTTPVersionRule() *AwsCloudfrontDistributionInvalidHTTPVersionRule { + return &AwsCloudfrontDistributionInvalidHTTPVersionRule{ + resourceType: "aws_cloudfront_distribution", + attributeName: "http_version", + enum: []string{ + "http1.1", + "http2", + }, + } +} + +// Name returns the rule name +func (r *AwsCloudfrontDistributionInvalidHTTPVersionRule) Name() string { + return "aws_cloudfront_distribution_invalid_http_version" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudfrontDistributionInvalidHTTPVersionRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudfrontDistributionInvalidHTTPVersionRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudfrontDistributionInvalidHTTPVersionRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudfrontDistributionInvalidHTTPVersionRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `http_version is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudfront_distribution_invalid_http_version_test.go b/rules/awsrules/models/aws_cloudfront_distribution_invalid_http_version_test.go new file mode 100644 index 000000000..b1f1e6f75 --- /dev/null +++ b/rules/awsrules/models/aws_cloudfront_distribution_invalid_http_version_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudfrontDistributionInvalidHTTPVersionRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudfront_distribution" "foo" { + http_version = "http1.2" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudfront_distribution_invalid_http_version", + Type: "ERROR", + Message: `http_version is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudfront_distribution" "foo" { + http_version = "http2" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudfrontDistributionInvalidHTTPVersionRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudfrontDistributionInvalidHTTPVersionRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudfront_distribution_invalid_price_class.go b/rules/awsrules/models/aws_cloudfront_distribution_invalid_price_class.go new file mode 100644 index 000000000..e6756d8f8 --- /dev/null +++ b/rules/awsrules/models/aws_cloudfront_distribution_invalid_price_class.go @@ -0,0 +1,78 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudfrontDistributionInvalidPriceClassRule checks the pattern is valid +type AwsCloudfrontDistributionInvalidPriceClassRule struct { + resourceType string + attributeName string + enum []string +} + +// NewAwsCloudfrontDistributionInvalidPriceClassRule returns new rule with default attributes +func NewAwsCloudfrontDistributionInvalidPriceClassRule() *AwsCloudfrontDistributionInvalidPriceClassRule { + return &AwsCloudfrontDistributionInvalidPriceClassRule{ + resourceType: "aws_cloudfront_distribution", + attributeName: "price_class", + enum: []string{ + "PriceClass_100", + "PriceClass_200", + "PriceClass_All", + }, + } +} + +// Name returns the rule name +func (r *AwsCloudfrontDistributionInvalidPriceClassRule) Name() string { + return "aws_cloudfront_distribution_invalid_price_class" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudfrontDistributionInvalidPriceClassRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudfrontDistributionInvalidPriceClassRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudfrontDistributionInvalidPriceClassRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudfrontDistributionInvalidPriceClassRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `price_class is not a valid value`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudfront_distribution_invalid_price_class_test.go b/rules/awsrules/models/aws_cloudfront_distribution_invalid_price_class_test.go new file mode 100644 index 000000000..66fb20b0e --- /dev/null +++ b/rules/awsrules/models/aws_cloudfront_distribution_invalid_price_class_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudfrontDistributionInvalidPriceClassRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudfront_distribution" "foo" { + price_class = "PriceClass_300" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudfront_distribution_invalid_price_class", + Type: "ERROR", + Message: `price_class is not a valid value`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudfront_distribution" "foo" { + price_class = "PriceClass_All" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudfrontDistributionInvalidPriceClassRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudfrontDistributionInvalidPriceClassRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_hsm_type.go b/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_hsm_type.go new file mode 100644 index 000000000..a57134cab --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_hsm_type.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudhsmV2ClusterInvalidHsmTypeRule checks the pattern is valid +type AwsCloudhsmV2ClusterInvalidHsmTypeRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsCloudhsmV2ClusterInvalidHsmTypeRule returns new rule with default attributes +func NewAwsCloudhsmV2ClusterInvalidHsmTypeRule() *AwsCloudhsmV2ClusterInvalidHsmTypeRule { + return &AwsCloudhsmV2ClusterInvalidHsmTypeRule{ + resourceType: "aws_cloudhsm_v2_cluster", + attributeName: "hsm_type", + pattern: regexp.MustCompile(`^(hsm1\.medium)$`), + } +} + +// Name returns the rule name +func (r *AwsCloudhsmV2ClusterInvalidHsmTypeRule) Name() string { + return "aws_cloudhsm_v2_cluster_invalid_hsm_type" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudhsmV2ClusterInvalidHsmTypeRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudhsmV2ClusterInvalidHsmTypeRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudhsmV2ClusterInvalidHsmTypeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudhsmV2ClusterInvalidHsmTypeRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `hsm_type does not match valid pattern ^(hsm1\.medium)$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_hsm_type_test.go b/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_hsm_type_test.go new file mode 100644 index 000000000..a2c16e158 --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_hsm_type_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudhsmV2ClusterInvalidHsmTypeRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudhsm_v2_cluster" "foo" { + hsm_type = "hsm1.micro" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudhsm_v2_cluster_invalid_hsm_type", + Type: "ERROR", + Message: `hsm_type does not match valid pattern ^(hsm1\.medium)$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudhsm_v2_cluster" "foo" { + hsm_type = "hsm1.medium" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudhsmV2ClusterInvalidHsmTypeRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudhsmV2ClusterInvalidHsmTypeRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_source_backup_identifier.go b/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_source_backup_identifier.go new file mode 100644 index 000000000..0851ea710 --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_source_backup_identifier.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule checks the pattern is valid +type AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule returns new rule with default attributes +func NewAwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule() *AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule { + return &AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule{ + resourceType: "aws_cloudhsm_v2_cluster", + attributeName: "source_backup_identifier", + pattern: regexp.MustCompile(`^backup-[2-7a-zA-Z]{11,16}$`), + } +} + +// Name returns the rule name +func (r *AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule) Name() string { + return "aws_cloudhsm_v2_cluster_invalid_source_backup_identifier" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `source_backup_identifier does not match valid pattern ^backup-[2-7a-zA-Z]{11,16}$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_source_backup_identifier_test.go b/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_source_backup_identifier_test.go new file mode 100644 index 000000000..785eb5396 --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_cluster_invalid_source_backup_identifier_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudhsm_v2_cluster" "foo" { + source_backup_identifier = "rtq2dwi2gq6" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudhsm_v2_cluster_invalid_source_backup_identifier", + Type: "ERROR", + Message: `source_backup_identifier does not match valid pattern ^backup-[2-7a-zA-Z]{11,16}$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudhsm_v2_cluster" "foo" { + source_backup_identifier = "backup-rtq2dwi2gq6" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_availability_zone.go b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_availability_zone.go new file mode 100644 index 000000000..78ffb0997 --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_availability_zone.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudhsmV2HsmInvalidAvailabilityZoneRule checks the pattern is valid +type AwsCloudhsmV2HsmInvalidAvailabilityZoneRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsCloudhsmV2HsmInvalidAvailabilityZoneRule returns new rule with default attributes +func NewAwsCloudhsmV2HsmInvalidAvailabilityZoneRule() *AwsCloudhsmV2HsmInvalidAvailabilityZoneRule { + return &AwsCloudhsmV2HsmInvalidAvailabilityZoneRule{ + resourceType: "aws_cloudhsm_v2_hsm", + attributeName: "availability_zone", + pattern: regexp.MustCompile(`^[a-z]{2}(-(gov))?-(east|west|north|south|central){1,2}-\d[a-z]$`), + } +} + +// Name returns the rule name +func (r *AwsCloudhsmV2HsmInvalidAvailabilityZoneRule) Name() string { + return "aws_cloudhsm_v2_hsm_invalid_availability_zone" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudhsmV2HsmInvalidAvailabilityZoneRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudhsmV2HsmInvalidAvailabilityZoneRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudhsmV2HsmInvalidAvailabilityZoneRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudhsmV2HsmInvalidAvailabilityZoneRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `availability_zone does not match valid pattern ^[a-z]{2}(-(gov))?-(east|west|north|south|central){1,2}-\d[a-z]$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_availability_zone_test.go b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_availability_zone_test.go new file mode 100644 index 000000000..8e9db8a9f --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_availability_zone_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudhsmV2HsmInvalidAvailabilityZoneRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudhsm_v2_hsm" "foo" { + availability_zone = "us-east-1" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudhsm_v2_hsm_invalid_availability_zone", + Type: "ERROR", + Message: `availability_zone does not match valid pattern ^[a-z]{2}(-(gov))?-(east|west|north|south|central){1,2}-\d[a-z]$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudhsm_v2_hsm" "foo" { + availability_zone = "us-east-1a" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudhsmV2HsmInvalidAvailabilityZoneRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudhsmV2HsmInvalidAvailabilityZoneRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_cluster_id.go b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_cluster_id.go new file mode 100644 index 000000000..30435cbb6 --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_cluster_id.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudhsmV2HsmInvalidClusterIDRule checks the pattern is valid +type AwsCloudhsmV2HsmInvalidClusterIDRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsCloudhsmV2HsmInvalidClusterIDRule returns new rule with default attributes +func NewAwsCloudhsmV2HsmInvalidClusterIDRule() *AwsCloudhsmV2HsmInvalidClusterIDRule { + return &AwsCloudhsmV2HsmInvalidClusterIDRule{ + resourceType: "aws_cloudhsm_v2_hsm", + attributeName: "cluster_id", + pattern: regexp.MustCompile(`^cluster-[2-7a-zA-Z]{11,16}$`), + } +} + +// Name returns the rule name +func (r *AwsCloudhsmV2HsmInvalidClusterIDRule) Name() string { + return "aws_cloudhsm_v2_hsm_invalid_cluster_id" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudhsmV2HsmInvalidClusterIDRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudhsmV2HsmInvalidClusterIDRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudhsmV2HsmInvalidClusterIDRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudhsmV2HsmInvalidClusterIDRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `cluster_id does not match valid pattern ^cluster-[2-7a-zA-Z]{11,16}$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_cluster_id_test.go b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_cluster_id_test.go new file mode 100644 index 000000000..cb39da55f --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_cluster_id_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudhsmV2HsmInvalidClusterIDRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudhsm_v2_hsm" "foo" { + cluster_id = "jxhlf7644ne" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudhsm_v2_hsm_invalid_cluster_id", + Type: "ERROR", + Message: `cluster_id does not match valid pattern ^cluster-[2-7a-zA-Z]{11,16}$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudhsm_v2_hsm" "foo" { + cluster_id = "cluster-jxhlf7644ne" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudhsmV2HsmInvalidClusterIDRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudhsmV2HsmInvalidClusterIDRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_ip_address.go b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_ip_address.go new file mode 100644 index 000000000..48a4b6f3e --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_ip_address.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudhsmV2HsmInvalidIPAddressRule checks the pattern is valid +type AwsCloudhsmV2HsmInvalidIPAddressRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsCloudhsmV2HsmInvalidIPAddressRule returns new rule with default attributes +func NewAwsCloudhsmV2HsmInvalidIPAddressRule() *AwsCloudhsmV2HsmInvalidIPAddressRule { + return &AwsCloudhsmV2HsmInvalidIPAddressRule{ + resourceType: "aws_cloudhsm_v2_hsm", + attributeName: "ip_address", + pattern: regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`), + } +} + +// Name returns the rule name +func (r *AwsCloudhsmV2HsmInvalidIPAddressRule) Name() string { + return "aws_cloudhsm_v2_hsm_invalid_ip_address" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudhsmV2HsmInvalidIPAddressRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudhsmV2HsmInvalidIPAddressRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudhsmV2HsmInvalidIPAddressRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudhsmV2HsmInvalidIPAddressRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `ip_address does not match valid pattern ^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_ip_address_test.go b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_ip_address_test.go new file mode 100644 index 000000000..e65671250 --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_ip_address_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudhsmV2HsmInvalidIPAddressRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudhsm_v2_hsm" "foo" { + ip_address = "2001:4860:4860::8888" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudhsm_v2_hsm_invalid_ip_address", + Type: "ERROR", + Message: `ip_address does not match valid pattern ^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudhsm_v2_hsm" "foo" { + ip_address = "8.8.8.8" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudhsmV2HsmInvalidIPAddressRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudhsmV2HsmInvalidIPAddressRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_subnet_id.go b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_subnet_id.go new file mode 100644 index 000000000..5f02e5c94 --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_subnet_id.go @@ -0,0 +1,69 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsCloudhsmV2HsmInvalidSubnetIDRule checks the pattern is valid +type AwsCloudhsmV2HsmInvalidSubnetIDRule struct { + resourceType string + attributeName string + pattern *regexp.Regexp +} + +// NewAwsCloudhsmV2HsmInvalidSubnetIDRule returns new rule with default attributes +func NewAwsCloudhsmV2HsmInvalidSubnetIDRule() *AwsCloudhsmV2HsmInvalidSubnetIDRule { + return &AwsCloudhsmV2HsmInvalidSubnetIDRule{ + resourceType: "aws_cloudhsm_v2_hsm", + attributeName: "subnet_id", + pattern: regexp.MustCompile(`^subnet-[0-9a-fA-F]{8,17}$`), + } +} + +// Name returns the rule name +func (r *AwsCloudhsmV2HsmInvalidSubnetIDRule) Name() string { + return "aws_cloudhsm_v2_hsm_invalid_subnet_id" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsCloudhsmV2HsmInvalidSubnetIDRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsCloudhsmV2HsmInvalidSubnetIDRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsCloudhsmV2HsmInvalidSubnetIDRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsCloudhsmV2HsmInvalidSubnetIDRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `subnet_id does not match valid pattern ^subnet-[0-9a-fA-F]{8,17}$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_subnet_id_test.go b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_subnet_id_test.go new file mode 100644 index 000000000..0c610996f --- /dev/null +++ b/rules/awsrules/models/aws_cloudhsm_v2_hsm_invalid_subnet_id_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsCloudhsmV2HsmInvalidSubnetIDRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_cloudhsm_v2_hsm" "foo" { + subnet_id = "0e358c43" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_cloudhsm_v2_hsm_invalid_subnet_id", + Type: "ERROR", + Message: `subnet_id does not match valid pattern ^subnet-[0-9a-fA-F]{8,17}$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_cloudhsm_v2_hsm" "foo" { + subnet_id = "subnet-0e358c43" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsCloudhsmV2HsmInvalidSubnetIDRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsCloudhsmV2HsmInvalidSubnetIDRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/aws_launch_template_invalid_name.go b/rules/awsrules/models/aws_launch_template_invalid_name.go new file mode 100644 index 000000000..23630524b --- /dev/null +++ b/rules/awsrules/models/aws_launch_template_invalid_name.go @@ -0,0 +1,87 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "log" + "regexp" + + "github.com/hashicorp/hcl2/hcl" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +// AwsLaunchTemplateInvalidNameRule checks the pattern is valid +type AwsLaunchTemplateInvalidNameRule struct { + resourceType string + attributeName string + max int + min int + pattern *regexp.Regexp +} + +// NewAwsLaunchTemplateInvalidNameRule returns new rule with default attributes +func NewAwsLaunchTemplateInvalidNameRule() *AwsLaunchTemplateInvalidNameRule { + return &AwsLaunchTemplateInvalidNameRule{ + resourceType: "aws_launch_template", + attributeName: "name", + max: 128, + min: 3, + pattern: regexp.MustCompile(`^[a-zA-Z0-9\(\)\.\-/_]+$`), + } +} + +// Name returns the rule name +func (r *AwsLaunchTemplateInvalidNameRule) Name() string { + return "aws_launch_template_invalid_name" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsLaunchTemplateInvalidNameRule) Enabled() bool { + return true +} + +// Type returns the rule severity +func (r *AwsLaunchTemplateInvalidNameRule) Type() string { + return issue.ERROR +} + +// Link returns the rule reference link +func (r *AwsLaunchTemplateInvalidNameRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsLaunchTemplateInvalidNameRule) Check(runner *tflint.Runner) error { + log.Printf("[INFO] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) + + return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error { + var val string + err := runner.EvaluateExpr(attribute.Expr, &val) + + return runner.EnsureNoError(err, func() error { + if len(val) > r.max { + runner.EmitIssue( + r, + "name must be 128 characters or less", + attribute.Expr.Range(), + ) + } + if len(val) < r.min { + runner.EmitIssue( + r, + "name must be 3 characters or higher", + attribute.Expr.Range(), + ) + } + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `name does not match valid pattern ^[a-zA-Z0-9\(\)\.\-/_]+$`, + attribute.Expr.Range(), + ) + } + return nil + }) + }) +} diff --git a/rules/awsrules/models/aws_launch_template_invalid_name_test.go b/rules/awsrules/models/aws_launch_template_invalid_name_test.go new file mode 100644 index 000000000..e45b783cd --- /dev/null +++ b/rules/awsrules/models/aws_launch_template_invalid_name_test.go @@ -0,0 +1,98 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_AwsLaunchTemplateInvalidNameRule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "aws_launch_template" "foo" { + name = "foo[bar]" +}`, + Expected: []*issue.Issue{ + { + Detector: "aws_launch_template_invalid_name", + Type: "ERROR", + Message: `name does not match valid pattern ^[a-zA-Z0-9\(\)\.\-/_]+$`, + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "aws_launch_template" "foo" { + name = "foo" +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "AwsLaunchTemplateInvalidNameRule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := NewAwsLaunchTemplateInvalidNameRule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/awsrules/models/mappings/acm-pca.hcl b/rules/awsrules/models/mappings/acm-pca.hcl new file mode 100644 index 000000000..8ca1b3358 --- /dev/null +++ b/rules/awsrules/models/mappings/acm-pca.hcl @@ -0,0 +1,14 @@ +mapping { + resource { + type = "aws_acmpca_certificate_authority" + attribute = "type" + } + model { + path = "aws-sdk-go/models/apis/acm-pca/2017-08-22/api-2.json" + shape = "CertificateAuthorityType" + } + test { + ok = "SUBORDINATE" + ng = "ORDINATE" + } +} diff --git a/rules/awsrules/models/mappings/acm.hcl b/rules/awsrules/models/mappings/acm.hcl new file mode 100644 index 000000000..10d233e76 --- /dev/null +++ b/rules/awsrules/models/mappings/acm.hcl @@ -0,0 +1,193 @@ +mapping { + resource { + type = "aws_acm_certificate" + attribute = "certificate_body" + } + + model { + path = "aws-sdk-go/models/apis/acm/2015-12-08/api-2.json" + shape = "CertificateBody" + } + + test { + ok = < r.max { + runner.EmitIssue( + r, + "{{ .AttributeName }} must be {{ .Max }} characters or less", + attribute.Expr.Range(), + ) + } +{{- end }} + +{{- if ne .Min 0 }} + if len(val) < r.min { + runner.EmitIssue( + r, + "{{ .AttributeName }} must be {{ .Min }} characters or higher", + attribute.Expr.Range(), + ) + } +{{- end }} + +{{- if ne .Pattern "" }} + if !r.pattern.MatchString(val) { + runner.EmitIssue( + r, + `{{ .AttributeName }} does not match valid pattern {{ .Pattern }}`, + attribute.Expr.Range(), + ) + } +{{- end }} + +{{- if ne (len .Enum) 0 }} + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + `{{ .AttributeName }} is not a valid value`, + attribute.Expr.Range(), + ) + } +{{- end }} + return nil + }) + }) +} diff --git a/rules/awsrules/models/pattern_rule_test.go.tmpl b/rules/awsrules/models/pattern_rule_test.go.tmpl new file mode 100644 index 000000000..afdb30c5f --- /dev/null +++ b/rules/awsrules/models/pattern_rule_test.go.tmpl @@ -0,0 +1,103 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package models + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/configs/configload" + "github.com/hashicorp/terraform/terraform" + "github.com/wata727/tflint/issue" + "github.com/wata727/tflint/tflint" +) + +func Test_{{ .RuleNameCC }}Rule(t *testing.T) { + cases := []struct { + Name string + Content string + Expected issue.Issues + }{ + { + Name: "It includes invalid characters", + Content: ` +resource "{{ .ResourceType }}" "foo" { + {{ .AttributeName }} = {{ .TestNG }} +}`, + Expected: []*issue.Issue{ + { + Detector: "{{ .RuleName }}", + Type: "ERROR", +{{- if ne .Pattern "" }} + Message: `{{ .AttributeName }} does not match valid pattern {{ .Pattern }}`, +{{- end }} +{{- if ne (len .Enum) 0 }} + Message: `{{ .AttributeName }} is not a valid value`, +{{- end }} + Line: 3, + File: "resource.tf", + }, + }, + }, + { + Name: "It is valid", + Content: ` +resource "{{ .ResourceType }}" "foo" { + {{ .AttributeName }} = {{ .TestOK }} +}`, + Expected: []*issue.Issue{}, + }, + } + + dir, err := ioutil.TempDir("", "{{ .RuleNameCC }}Rule") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + currentDir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(currentDir) + + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + for _, tc := range cases { + loader, err := configload.NewLoader(&configload.Config{}) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(dir+"/resource.tf", []byte(tc.Content), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + mod, diags := loader.Parser().LoadConfigDir(".") + if diags.HasErrors() { + t.Fatal(diags) + } + cfg, tfdiags := configs.BuildConfig(mod, configs.DisabledModuleWalker) + if tfdiags.HasErrors() { + t.Fatal(tfdiags) + } + + runner := tflint.NewRunner(tflint.EmptyConfig(), map[string]tflint.Annotations{}, cfg, map[string]*terraform.InputValue{}) + rule := New{{ .RuleNameCC }}Rule() + + if err = rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + if !cmp.Equal(tc.Expected, runner.Issues) { + t.Fatalf("Expected issues are not matched:\n %s\n", cmp.Diff(tc.Expected, runner.Issues)) + } + } +} diff --git a/rules/provider.go b/rules/provider.go index c5c2c7497..fe79cd857 100644 --- a/rules/provider.go +++ b/rules/provider.go @@ -16,7 +16,9 @@ type Rule interface { } // DefaultRules is rules by default -var DefaultRules = []Rule{ +var DefaultRules = append(manualRules, modelRules...) + +var manualRules = []Rule{ awsrules.NewAwsCloudwatchMetricAlarmInvalidUnitRule(), awsrules.NewAwsDBInstanceDefaultParameterGroupRule(), awsrules.NewAwsDBInstanceInvalidTypeRule(), diff --git a/rules/provider_model.go b/rules/provider_model.go new file mode 100644 index 000000000..1c2e9d072 --- /dev/null +++ b/rules/provider_model.go @@ -0,0 +1,90 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package rules + +import awsmodelrules "github.com/wata727/tflint/rules/awsrules/models" + +var modelRules = []Rule{ + awsmodelrules.NewAwsAcmpcaCertificateAuthorityInvalidTypeRule(), + awsmodelrules.NewAwsAcmCertificateInvalidCertificateBodyRule(), + awsmodelrules.NewAwsAcmCertificateInvalidCertificateChainRule(), + awsmodelrules.NewAwsAcmCertificateInvalidPrivateKeyRule(), + awsmodelrules.NewAwsAPIGatewayGatewayResponseInvalidStatusCodeRule(), + awsmodelrules.NewAwsAPIGatewayIntegrationResponseInvalidStatusCodeRule(), + awsmodelrules.NewAwsAPIGatewayMethodResponseInvalidStatusCodeRule(), + awsmodelrules.NewAwsAPIGatewayAuthorizerInvalidTypeRule(), + awsmodelrules.NewAwsAPIGatewayGatewayResponseInvalidResponseTypeRule(), + awsmodelrules.NewAwsAPIGatewayIntegrationInvalidTypeRule(), + awsmodelrules.NewAwsAPIGatewayIntegrationInvalidConnectionTypeRule(), + awsmodelrules.NewAwsAPIGatewayIntegrationInvalidContentHandlingRule(), + awsmodelrules.NewAwsAPIGatewayIntegrationResponseInvalidContentHandlingRule(), + awsmodelrules.NewAwsAPIGatewayRestAPIInvalidAPIKeySourceRule(), + awsmodelrules.NewAwsAPIGatewayStageInvalidCacheClusterSizeRule(), + awsmodelrules.NewAwsAppautoscalingPolicyInvalidPolicyTypeRule(), + awsmodelrules.NewAwsAppautoscalingPolicyInvalidScalableDimensionRule(), + awsmodelrules.NewAwsAppautoscalingScheduledActionInvalidScalableDimensionRule(), + awsmodelrules.NewAwsAppautoscalingTargetInvalidScalableDimensionRule(), + awsmodelrules.NewAwsAppautoscalingPolicyInvalidServiceNamespaceRule(), + awsmodelrules.NewAwsAppautoscalingScheduledActionInvalidServiceNamespaceRule(), + awsmodelrules.NewAwsAppautoscalingTargetInvalidServiceNamespaceRule(), + awsmodelrules.NewAwsAppmeshMeshInvalidNameRule(), + awsmodelrules.NewAwsAppmeshRouteInvalidNameRule(), + awsmodelrules.NewAwsAppmeshRouteInvalidMeshNameRule(), + awsmodelrules.NewAwsAppmeshRouteInvalidVirtualRouterNameRule(), + awsmodelrules.NewAwsAppmeshVirtualNodeInvalidNameRule(), + awsmodelrules.NewAwsAppmeshVirtualNodeInvalidMeshNameRule(), + awsmodelrules.NewAwsAppmeshVirtualRouterInvalidNameRule(), + awsmodelrules.NewAwsAppmeshVirtualRouterInvalidMeshNameRule(), + awsmodelrules.NewAwsAppmeshVirtualServiceInvalidNameRule(), + awsmodelrules.NewAwsAppmeshVirtualServiceInvalidMeshNameRule(), + awsmodelrules.NewAwsAppsyncDatasourceInvalidNameRule(), + awsmodelrules.NewAwsAppsyncDatasourceInvalidTypeRule(), + awsmodelrules.NewAwsAppsyncGraphqlAPIInvalidAuthenticationTypeRule(), + awsmodelrules.NewAwsAppsyncResolverInvalidTypeRule(), + awsmodelrules.NewAwsAppsyncResolverInvalidFieldRule(), + awsmodelrules.NewAwsAppsyncResolverInvalidDataSourceRule(), + awsmodelrules.NewAwsAppsyncResolverInvalidRequestTemplateRule(), + awsmodelrules.NewAwsAppsyncResolverInvalidResponseTemplateRule(), + awsmodelrules.NewAwsAthenaDatabaseInvalidNameRule(), + awsmodelrules.NewAwsAthenaNamedQueryInvalidNameRule(), + awsmodelrules.NewAwsAthenaNamedQueryInvalidDatabaseRule(), + awsmodelrules.NewAwsAthenaNamedQueryInvalidQueryRule(), + awsmodelrules.NewAwsAthenaNamedQueryInvalidDescriptionRule(), + awsmodelrules.NewAwsBackupSelectionInvalidNameRule(), + awsmodelrules.NewAwsBackupVaultInvalidNameRule(), + awsmodelrules.NewAwsBatchComputeEnvironmentInvalidStateRule(), + awsmodelrules.NewAwsBatchComputeEnvironmentInvalidTypeRule(), + awsmodelrules.NewAwsBatchJobDefinitionInvalidTypeRule(), + awsmodelrules.NewAwsBatchJobQueueInvalidStateRule(), + awsmodelrules.NewAwsBudgetsBudgetInvalidAccountIDRule(), + awsmodelrules.NewAwsBudgetsBudgetInvalidNameRule(), + awsmodelrules.NewAwsBudgetsBudgetInvalidBudgetTypeRule(), + awsmodelrules.NewAwsBudgetsBudgetInvalidTimeUnitRule(), + awsmodelrules.NewAwsCloud9EnvironmentEc2InvalidNameRule(), + awsmodelrules.NewAwsCloud9EnvironmentEc2InvalidInstanceTypeRule(), + awsmodelrules.NewAwsCloud9EnvironmentEc2InvalidAutomaticStopTimeMinutesRule(), + awsmodelrules.NewAwsCloud9EnvironmentEc2InvalidDescriptionRule(), + awsmodelrules.NewAwsCloud9EnvironmentEc2InvalidOwnerArnRule(), + awsmodelrules.NewAwsCloud9EnvironmentEc2InvalidSubnetIDRule(), + awsmodelrules.NewAwsCloudformationStackInvalidTemplateURLRule(), + awsmodelrules.NewAwsCloudformationStackInvalidCapabilitiesRule(), + awsmodelrules.NewAwsCloudformationStackInvalidOnFailureRule(), + awsmodelrules.NewAwsCloudformationStackInvalidPolicyBodyRule(), + awsmodelrules.NewAwsCloudformationStackInvalidPolicyURLRule(), + awsmodelrules.NewAwsCloudformationStackInvalidIAMRoleArnRule(), + awsmodelrules.NewAwsCloudformationStackSetInvalidAdministrationRoleArnRule(), + awsmodelrules.NewAwsCloudformationStackSetInvalidCapabilitiesRule(), + awsmodelrules.NewAwsCloudformationStackSetInvalidDescriptionRule(), + awsmodelrules.NewAwsCloudformationStackSetInvalidExecutionRoleNameRule(), + awsmodelrules.NewAwsCloudformationStackSetInvalidTemplateURLRule(), + awsmodelrules.NewAwsCloudformationStackSetInstanceInvalidAccountIDRule(), + awsmodelrules.NewAwsCloudfrontDistributionInvalidHTTPVersionRule(), + awsmodelrules.NewAwsCloudfrontDistributionInvalidPriceClassRule(), + awsmodelrules.NewAwsCloudhsmV2ClusterInvalidSourceBackupIdentifierRule(), + awsmodelrules.NewAwsCloudhsmV2ClusterInvalidHsmTypeRule(), + awsmodelrules.NewAwsCloudhsmV2HsmInvalidClusterIDRule(), + awsmodelrules.NewAwsCloudhsmV2HsmInvalidSubnetIDRule(), + awsmodelrules.NewAwsCloudhsmV2HsmInvalidAvailabilityZoneRule(), + awsmodelrules.NewAwsCloudhsmV2HsmInvalidIPAddressRule(), + awsmodelrules.NewAwsLaunchTemplateInvalidNameRule(), +} diff --git a/rules/provider_model.go.tmpl b/rules/provider_model.go.tmpl new file mode 100644 index 000000000..223d02601 --- /dev/null +++ b/rules/provider_model.go.tmpl @@ -0,0 +1,11 @@ +// This file generated by `tools/model-rule-gen/main.go`. DO NOT EDIT + +package rules + +import awsmodelrules "github.com/wata727/tflint/rules/awsrules/models" + +var modelRules = []Rule{ + {{- range $v := .RuleNameCCList }} + awsmodelrules.New{{ $v }}Rule(), + {{- end }} +} diff --git a/tools/model-rule-gen/main.go b/tools/model-rule-gen/main.go new file mode 100644 index 000000000..39ea6627e --- /dev/null +++ b/tools/model-rule-gen/main.go @@ -0,0 +1,79 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "path/filepath" + + "github.com/hashicorp/hcl2/gohcl" + "github.com/hashicorp/hcl2/hclparse" +) + +type mappingFile struct { + Mappings []mapping `hcl:"mapping,block"` +} + +type mapping struct { + Resource resource `hcl:"resource,block"` + Model model `hcl:"model,block"` + Test *test `hcl:"test,block"` +} + +type mappings []mapping + +type resource struct { + Type string `hcl:"type"` + Attribute string `hcl:"attribute"` +} + +type model struct { + Path string `hcl:"path"` + Shape string `hcl:"shape"` +} + +type test struct { + OK string `hcl:"ok"` + NG string `hcl:"ng"` +} + +func main() { + files, err := filepath.Glob("rules/awsrules/models/mappings/*.hcl") + if err != nil { + panic(err) + } + + mappings := mappings{} + for _, file := range files { + parser := hclparse.NewParser() + f, diags := parser.ParseHCLFile(file) + if diags.HasErrors() { + panic(diags) + } + + var mf mappingFile + diags = gohcl.DecodeBody(f.Body, nil, &mf) + if diags.HasErrors() { + panic(diags) + } + mappings = append(mappings, mf.Mappings...) + } + + for _, mapping := range mappings { + raw, err := ioutil.ReadFile(fmt.Sprintf("rules/awsrules/models/%s", mapping.Model.Path)) + if err != nil { + panic(err) + } + + var api map[string]interface{} + err = json.Unmarshal(raw, &api) + if err != nil { + panic(err) + } + shapes := api["shapes"].(map[string]interface{}) + + generateRuleFile(mapping, shapes) + } + + generateProviderFile(mappings) +} diff --git a/tools/model-rule-gen/provider.go b/tools/model-rule-gen/provider.go new file mode 100644 index 000000000..80ff24c93 --- /dev/null +++ b/tools/model-rule-gen/provider.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + + "github.com/wata727/tflint/tools/utils" +) + +type providerMeta struct { + RuleNameCCList []string +} + +func generateProviderFile(mappings mappings) { + meta := &providerMeta{} + + for _, mapping := range mappings { + resource := mapping.Resource.Type + attribute := mapping.Resource.Attribute + ruleName := fmt.Sprintf("%s_invalid_%s", resource, attribute) + + meta.RuleNameCCList = append(meta.RuleNameCCList, utils.ToCamel(ruleName)) + } + + utils.GenerateFile("rules/provider_model.go", "rules/provider_model.go.tmpl", meta) +} diff --git a/tools/model-rule-gen/rule.go b/tools/model-rule-gen/rule.go new file mode 100644 index 000000000..78313bf63 --- /dev/null +++ b/tools/model-rule-gen/rule.go @@ -0,0 +1,95 @@ +package main + +import ( + "fmt" + "regexp" + "strings" + + "github.com/wata727/tflint/tools/utils" +) + +type ruleMeta struct { + RuleName string + RuleNameCC string + ResourceType string + AttributeName string + Max int + Min int + Pattern string + Enum []string + TestOK string + TestNG string +} + +func generateRuleFile(mapping mapping, shapes map[string]interface{}) { + resource := mapping.Resource.Type + attribute := mapping.Resource.Attribute + ruleName := fmt.Sprintf("%s_invalid_%s", resource, attribute) + model := shapes[mapping.Model.Shape].(map[string]interface{}) + + meta := &ruleMeta{ + RuleName: ruleName, + RuleNameCC: utils.ToCamel(ruleName), + ResourceType: resource, + AttributeName: attribute, + Max: fetchNumber(model, "max"), + Min: fetchNumber(model, "min"), + Pattern: replacePattern(fetchString(model, "pattern")), + Enum: fetchStrings(model, "enum"), + } + + // Testing generated regexp + regexp.MustCompile(meta.Pattern) + + utils.GenerateFile(fmt.Sprintf("rules/awsrules/models/%s.go", ruleName), "rules/awsrules/models/pattern_rule.go.tmpl", meta) + if mapping.Test != nil { + meta.TestOK = formatTest(mapping.Test.OK) + meta.TestNG = formatTest(mapping.Test.NG) + utils.GenerateFile(fmt.Sprintf("rules/awsrules/models/%s_test.go", ruleName), "rules/awsrules/models/pattern_rule_test.go.tmpl", meta) + } +} + +func fetchNumber(model map[string]interface{}, key string) int { + if v, ok := model[key]; ok { + return int(v.(float64)) + } + return 0 +} + +func fetchStrings(model map[string]interface{}, key string) []string { + if raw, ok := model[key]; ok { + list := raw.([]interface{}) + ret := make([]string, len(list)) + for i, v := range list { + ret[i] = v.(string) + } + return ret + } + return []string{} +} + +func fetchString(model map[string]interface{}, key string) string { + if v, ok := model[key]; ok { + return v.(string) + } + return "" +} + +func replacePattern(pattern string) string { + if pattern == "" { + return pattern + } + reg := regexp.MustCompile(`\\u([0-9A-F]{4})`) + replaced := reg.ReplaceAllString(pattern, `\x{$1}`) + if !strings.HasPrefix(replaced, "^") && !strings.HasSuffix(replaced, "$") { + return fmt.Sprintf("^%s$", replaced) + } + return replaced +} + +func formatTest(body string) string { + if strings.Contains(body, "\n") { + return fmt.Sprintf("<