diff --git a/docs/rules/README.md b/docs/rules/README.md index 04a9b022..1f4b71f8 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -517,6 +517,14 @@ These rules enforce best practices and naming conventions: |aws_dms_endpoint_invalid_endpoint_type|✔| |aws_dms_endpoint_invalid_ssl_mode|✔| |aws_dms_replication_task_invalid_migration_type|✔| +|aws_dms_s3_endpoint_invalid_canned_acl_for_objects|✔| +|aws_dms_s3_endpoint_invalid_compression_type|✔| +|aws_dms_s3_endpoint_invalid_data_format|✔| +|aws_dms_s3_endpoint_invalid_date_partition_delimiter|✔| +|aws_dms_s3_endpoint_invalid_date_partition_sequence|✔| +|aws_dms_s3_endpoint_invalid_encoding_type|✔| +|aws_dms_s3_endpoint_invalid_encryption_mode|✔| +|aws_dms_s3_endpoint_invalid_parquet_version|✔| |aws_docdb_global_cluster_invalid_global_cluster_identifier|✔| |aws_dx_bgp_peer_invalid_address_family|✔| |aws_dx_hosted_private_virtual_interface_invalid_address_family|✔| diff --git a/rules/models/aws_dms_s3_endpoint_invalid_canned_acl_for_objects.go b/rules/models/aws_dms_s3_endpoint_invalid_canned_acl_for_objects.go new file mode 100644 index 00000000..6e960bde --- /dev/null +++ b/rules/models/aws_dms_s3_endpoint_invalid_canned_acl_for_objects.go @@ -0,0 +1,101 @@ +// This file generated by `generator/`. DO NOT EDIT + +package models + +import ( + "fmt" + + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/logger" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AwsDmsS3EndpointInvalidCannedACLForObjectsRule checks the pattern is valid +type AwsDmsS3EndpointInvalidCannedACLForObjectsRule struct { + tflint.DefaultRule + + resourceType string + attributeName string + enum []string +} + +// NewAwsDmsS3EndpointInvalidCannedACLForObjectsRule returns new rule with default attributes +func NewAwsDmsS3EndpointInvalidCannedACLForObjectsRule() *AwsDmsS3EndpointInvalidCannedACLForObjectsRule { + return &AwsDmsS3EndpointInvalidCannedACLForObjectsRule{ + resourceType: "aws_dms_s3_endpoint", + attributeName: "canned_acl_for_objects", + enum: []string{ + "AUTHENTICATED-READ", + "AWS-EXEC-READ", + "BUCKET-OWNER-FULL-CONTROL", + "BUCKET-OWNER-READ", + "NONE", + "PRIVATE", + "PUBLIC-READ", + "PUBLIC-READ-WRITE", + }, + } +} + +// Name returns the rule name +func (r *AwsDmsS3EndpointInvalidCannedACLForObjectsRule) Name() string { + return "aws_dms_s3_endpoint_invalid_canned_acl_for_objects" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsDmsS3EndpointInvalidCannedACLForObjectsRule) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AwsDmsS3EndpointInvalidCannedACLForObjectsRule) Severity() tflint.Severity { + return tflint.ERROR +} + +// Link returns the rule reference link +func (r *AwsDmsS3EndpointInvalidCannedACLForObjectsRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsDmsS3EndpointInvalidCannedACLForObjectsRule) Check(runner tflint.Runner) error { + logger.Trace("Check `%s` rule", r.Name()) + + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: r.attributeName}, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + attribute, exists := resource.Body.Attributes[r.attributeName] + if !exists { + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func (val string) error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + fmt.Sprintf(`"%s" is an invalid value as canned_acl_for_objects`, truncateLongMessage(val)), + attribute.Expr.Range(), + ) + } + return nil + }, nil) + if err != nil { + return err + } + } + + return nil +} diff --git a/rules/models/aws_dms_s3_endpoint_invalid_compression_type.go b/rules/models/aws_dms_s3_endpoint_invalid_compression_type.go new file mode 100644 index 00000000..2876cf0e --- /dev/null +++ b/rules/models/aws_dms_s3_endpoint_invalid_compression_type.go @@ -0,0 +1,95 @@ +// This file generated by `generator/`. DO NOT EDIT + +package models + +import ( + "fmt" + + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/logger" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AwsDmsS3EndpointInvalidCompressionTypeRule checks the pattern is valid +type AwsDmsS3EndpointInvalidCompressionTypeRule struct { + tflint.DefaultRule + + resourceType string + attributeName string + enum []string +} + +// NewAwsDmsS3EndpointInvalidCompressionTypeRule returns new rule with default attributes +func NewAwsDmsS3EndpointInvalidCompressionTypeRule() *AwsDmsS3EndpointInvalidCompressionTypeRule { + return &AwsDmsS3EndpointInvalidCompressionTypeRule{ + resourceType: "aws_dms_s3_endpoint", + attributeName: "compression_type", + enum: []string{ + "GZIP", + "NONE", + }, + } +} + +// Name returns the rule name +func (r *AwsDmsS3EndpointInvalidCompressionTypeRule) Name() string { + return "aws_dms_s3_endpoint_invalid_compression_type" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsDmsS3EndpointInvalidCompressionTypeRule) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AwsDmsS3EndpointInvalidCompressionTypeRule) Severity() tflint.Severity { + return tflint.ERROR +} + +// Link returns the rule reference link +func (r *AwsDmsS3EndpointInvalidCompressionTypeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsDmsS3EndpointInvalidCompressionTypeRule) Check(runner tflint.Runner) error { + logger.Trace("Check `%s` rule", r.Name()) + + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: r.attributeName}, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + attribute, exists := resource.Body.Attributes[r.attributeName] + if !exists { + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func (val string) error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + fmt.Sprintf(`"%s" is an invalid value as compression_type`, truncateLongMessage(val)), + attribute.Expr.Range(), + ) + } + return nil + }, nil) + if err != nil { + return err + } + } + + return nil +} diff --git a/rules/models/aws_dms_s3_endpoint_invalid_data_format.go b/rules/models/aws_dms_s3_endpoint_invalid_data_format.go new file mode 100644 index 00000000..d71d423a --- /dev/null +++ b/rules/models/aws_dms_s3_endpoint_invalid_data_format.go @@ -0,0 +1,95 @@ +// This file generated by `generator/`. DO NOT EDIT + +package models + +import ( + "fmt" + + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/logger" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AwsDmsS3EndpointInvalidDataFormatRule checks the pattern is valid +type AwsDmsS3EndpointInvalidDataFormatRule struct { + tflint.DefaultRule + + resourceType string + attributeName string + enum []string +} + +// NewAwsDmsS3EndpointInvalidDataFormatRule returns new rule with default attributes +func NewAwsDmsS3EndpointInvalidDataFormatRule() *AwsDmsS3EndpointInvalidDataFormatRule { + return &AwsDmsS3EndpointInvalidDataFormatRule{ + resourceType: "aws_dms_s3_endpoint", + attributeName: "data_format", + enum: []string{ + "csv", + "parquet", + }, + } +} + +// Name returns the rule name +func (r *AwsDmsS3EndpointInvalidDataFormatRule) Name() string { + return "aws_dms_s3_endpoint_invalid_data_format" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsDmsS3EndpointInvalidDataFormatRule) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AwsDmsS3EndpointInvalidDataFormatRule) Severity() tflint.Severity { + return tflint.ERROR +} + +// Link returns the rule reference link +func (r *AwsDmsS3EndpointInvalidDataFormatRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsDmsS3EndpointInvalidDataFormatRule) Check(runner tflint.Runner) error { + logger.Trace("Check `%s` rule", r.Name()) + + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: r.attributeName}, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + attribute, exists := resource.Body.Attributes[r.attributeName] + if !exists { + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func (val string) error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + fmt.Sprintf(`"%s" is an invalid value as data_format`, truncateLongMessage(val)), + attribute.Expr.Range(), + ) + } + return nil + }, nil) + if err != nil { + return err + } + } + + return nil +} diff --git a/rules/models/aws_dms_s3_endpoint_invalid_date_partition_delimiter.go b/rules/models/aws_dms_s3_endpoint_invalid_date_partition_delimiter.go new file mode 100644 index 00000000..085ae316 --- /dev/null +++ b/rules/models/aws_dms_s3_endpoint_invalid_date_partition_delimiter.go @@ -0,0 +1,97 @@ +// This file generated by `generator/`. DO NOT EDIT + +package models + +import ( + "fmt" + + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/logger" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AwsDmsS3EndpointInvalidDatePartitionDelimiterRule checks the pattern is valid +type AwsDmsS3EndpointInvalidDatePartitionDelimiterRule struct { + tflint.DefaultRule + + resourceType string + attributeName string + enum []string +} + +// NewAwsDmsS3EndpointInvalidDatePartitionDelimiterRule returns new rule with default attributes +func NewAwsDmsS3EndpointInvalidDatePartitionDelimiterRule() *AwsDmsS3EndpointInvalidDatePartitionDelimiterRule { + return &AwsDmsS3EndpointInvalidDatePartitionDelimiterRule{ + resourceType: "aws_dms_s3_endpoint", + attributeName: "date_partition_delimiter", + enum: []string{ + "DASH", + "NONE", + "SLASH", + "UNDERSCORE", + }, + } +} + +// Name returns the rule name +func (r *AwsDmsS3EndpointInvalidDatePartitionDelimiterRule) Name() string { + return "aws_dms_s3_endpoint_invalid_date_partition_delimiter" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsDmsS3EndpointInvalidDatePartitionDelimiterRule) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AwsDmsS3EndpointInvalidDatePartitionDelimiterRule) Severity() tflint.Severity { + return tflint.ERROR +} + +// Link returns the rule reference link +func (r *AwsDmsS3EndpointInvalidDatePartitionDelimiterRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsDmsS3EndpointInvalidDatePartitionDelimiterRule) Check(runner tflint.Runner) error { + logger.Trace("Check `%s` rule", r.Name()) + + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: r.attributeName}, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + attribute, exists := resource.Body.Attributes[r.attributeName] + if !exists { + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func (val string) error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + fmt.Sprintf(`"%s" is an invalid value as date_partition_delimiter`, truncateLongMessage(val)), + attribute.Expr.Range(), + ) + } + return nil + }, nil) + if err != nil { + return err + } + } + + return nil +} diff --git a/rules/models/aws_dms_s3_endpoint_invalid_date_partition_sequence.go b/rules/models/aws_dms_s3_endpoint_invalid_date_partition_sequence.go new file mode 100644 index 00000000..568d2c2b --- /dev/null +++ b/rules/models/aws_dms_s3_endpoint_invalid_date_partition_sequence.go @@ -0,0 +1,98 @@ +// This file generated by `generator/`. DO NOT EDIT + +package models + +import ( + "fmt" + + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/logger" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AwsDmsS3EndpointInvalidDatePartitionSequenceRule checks the pattern is valid +type AwsDmsS3EndpointInvalidDatePartitionSequenceRule struct { + tflint.DefaultRule + + resourceType string + attributeName string + enum []string +} + +// NewAwsDmsS3EndpointInvalidDatePartitionSequenceRule returns new rule with default attributes +func NewAwsDmsS3EndpointInvalidDatePartitionSequenceRule() *AwsDmsS3EndpointInvalidDatePartitionSequenceRule { + return &AwsDmsS3EndpointInvalidDatePartitionSequenceRule{ + resourceType: "aws_dms_s3_endpoint", + attributeName: "date_partition_sequence", + enum: []string{ + "DDMMYYYY", + "MMYYYYDD", + "YYYYMM", + "YYYYMMDD", + "YYYYMMDDHH", + }, + } +} + +// Name returns the rule name +func (r *AwsDmsS3EndpointInvalidDatePartitionSequenceRule) Name() string { + return "aws_dms_s3_endpoint_invalid_date_partition_sequence" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsDmsS3EndpointInvalidDatePartitionSequenceRule) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AwsDmsS3EndpointInvalidDatePartitionSequenceRule) Severity() tflint.Severity { + return tflint.ERROR +} + +// Link returns the rule reference link +func (r *AwsDmsS3EndpointInvalidDatePartitionSequenceRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsDmsS3EndpointInvalidDatePartitionSequenceRule) Check(runner tflint.Runner) error { + logger.Trace("Check `%s` rule", r.Name()) + + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: r.attributeName}, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + attribute, exists := resource.Body.Attributes[r.attributeName] + if !exists { + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func (val string) error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + fmt.Sprintf(`"%s" is an invalid value as date_partition_sequence`, truncateLongMessage(val)), + attribute.Expr.Range(), + ) + } + return nil + }, nil) + if err != nil { + return err + } + } + + return nil +} diff --git a/rules/models/aws_dms_s3_endpoint_invalid_encoding_type.go b/rules/models/aws_dms_s3_endpoint_invalid_encoding_type.go new file mode 100644 index 00000000..830312dd --- /dev/null +++ b/rules/models/aws_dms_s3_endpoint_invalid_encoding_type.go @@ -0,0 +1,96 @@ +// This file generated by `generator/`. DO NOT EDIT + +package models + +import ( + "fmt" + + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/logger" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AwsDmsS3EndpointInvalidEncodingTypeRule checks the pattern is valid +type AwsDmsS3EndpointInvalidEncodingTypeRule struct { + tflint.DefaultRule + + resourceType string + attributeName string + enum []string +} + +// NewAwsDmsS3EndpointInvalidEncodingTypeRule returns new rule with default attributes +func NewAwsDmsS3EndpointInvalidEncodingTypeRule() *AwsDmsS3EndpointInvalidEncodingTypeRule { + return &AwsDmsS3EndpointInvalidEncodingTypeRule{ + resourceType: "aws_dms_s3_endpoint", + attributeName: "encoding_type", + enum: []string{ + "plain", + "plain-dictionary", + "rle-dictionary", + }, + } +} + +// Name returns the rule name +func (r *AwsDmsS3EndpointInvalidEncodingTypeRule) Name() string { + return "aws_dms_s3_endpoint_invalid_encoding_type" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsDmsS3EndpointInvalidEncodingTypeRule) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AwsDmsS3EndpointInvalidEncodingTypeRule) Severity() tflint.Severity { + return tflint.ERROR +} + +// Link returns the rule reference link +func (r *AwsDmsS3EndpointInvalidEncodingTypeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsDmsS3EndpointInvalidEncodingTypeRule) Check(runner tflint.Runner) error { + logger.Trace("Check `%s` rule", r.Name()) + + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: r.attributeName}, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + attribute, exists := resource.Body.Attributes[r.attributeName] + if !exists { + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func (val string) error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + fmt.Sprintf(`"%s" is an invalid value as encoding_type`, truncateLongMessage(val)), + attribute.Expr.Range(), + ) + } + return nil + }, nil) + if err != nil { + return err + } + } + + return nil +} diff --git a/rules/models/aws_dms_s3_endpoint_invalid_encryption_mode.go b/rules/models/aws_dms_s3_endpoint_invalid_encryption_mode.go new file mode 100644 index 00000000..d5b682ca --- /dev/null +++ b/rules/models/aws_dms_s3_endpoint_invalid_encryption_mode.go @@ -0,0 +1,95 @@ +// This file generated by `generator/`. DO NOT EDIT + +package models + +import ( + "fmt" + + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/logger" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AwsDmsS3EndpointInvalidEncryptionModeRule checks the pattern is valid +type AwsDmsS3EndpointInvalidEncryptionModeRule struct { + tflint.DefaultRule + + resourceType string + attributeName string + enum []string +} + +// NewAwsDmsS3EndpointInvalidEncryptionModeRule returns new rule with default attributes +func NewAwsDmsS3EndpointInvalidEncryptionModeRule() *AwsDmsS3EndpointInvalidEncryptionModeRule { + return &AwsDmsS3EndpointInvalidEncryptionModeRule{ + resourceType: "aws_dms_s3_endpoint", + attributeName: "encryption_mode", + enum: []string{ + "SSE_KMS", + "SSE_S3", + }, + } +} + +// Name returns the rule name +func (r *AwsDmsS3EndpointInvalidEncryptionModeRule) Name() string { + return "aws_dms_s3_endpoint_invalid_encryption_mode" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsDmsS3EndpointInvalidEncryptionModeRule) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AwsDmsS3EndpointInvalidEncryptionModeRule) Severity() tflint.Severity { + return tflint.ERROR +} + +// Link returns the rule reference link +func (r *AwsDmsS3EndpointInvalidEncryptionModeRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsDmsS3EndpointInvalidEncryptionModeRule) Check(runner tflint.Runner) error { + logger.Trace("Check `%s` rule", r.Name()) + + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: r.attributeName}, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + attribute, exists := resource.Body.Attributes[r.attributeName] + if !exists { + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func (val string) error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + fmt.Sprintf(`"%s" is an invalid value as encryption_mode`, truncateLongMessage(val)), + attribute.Expr.Range(), + ) + } + return nil + }, nil) + if err != nil { + return err + } + } + + return nil +} diff --git a/rules/models/aws_dms_s3_endpoint_invalid_parquet_version.go b/rules/models/aws_dms_s3_endpoint_invalid_parquet_version.go new file mode 100644 index 00000000..a102cc15 --- /dev/null +++ b/rules/models/aws_dms_s3_endpoint_invalid_parquet_version.go @@ -0,0 +1,95 @@ +// This file generated by `generator/`. DO NOT EDIT + +package models + +import ( + "fmt" + + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/logger" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AwsDmsS3EndpointInvalidParquetVersionRule checks the pattern is valid +type AwsDmsS3EndpointInvalidParquetVersionRule struct { + tflint.DefaultRule + + resourceType string + attributeName string + enum []string +} + +// NewAwsDmsS3EndpointInvalidParquetVersionRule returns new rule with default attributes +func NewAwsDmsS3EndpointInvalidParquetVersionRule() *AwsDmsS3EndpointInvalidParquetVersionRule { + return &AwsDmsS3EndpointInvalidParquetVersionRule{ + resourceType: "aws_dms_s3_endpoint", + attributeName: "parquet_version", + enum: []string{ + "parquet-1-0", + "parquet-2-0", + }, + } +} + +// Name returns the rule name +func (r *AwsDmsS3EndpointInvalidParquetVersionRule) Name() string { + return "aws_dms_s3_endpoint_invalid_parquet_version" +} + +// Enabled returns whether the rule is enabled by default +func (r *AwsDmsS3EndpointInvalidParquetVersionRule) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AwsDmsS3EndpointInvalidParquetVersionRule) Severity() tflint.Severity { + return tflint.ERROR +} + +// Link returns the rule reference link +func (r *AwsDmsS3EndpointInvalidParquetVersionRule) Link() string { + return "" +} + +// Check checks the pattern is valid +func (r *AwsDmsS3EndpointInvalidParquetVersionRule) Check(runner tflint.Runner) error { + logger.Trace("Check `%s` rule", r.Name()) + + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: r.attributeName}, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + attribute, exists := resource.Body.Attributes[r.attributeName] + if !exists { + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func (val string) error { + found := false + for _, item := range r.enum { + if item == val { + found = true + } + } + if !found { + runner.EmitIssue( + r, + fmt.Sprintf(`"%s" is an invalid value as parquet_version`, truncateLongMessage(val)), + attribute.Expr.Range(), + ) + } + return nil + }, nil) + if err != nil { + return err + } + } + + return nil +} diff --git a/rules/models/generator/main.go b/rules/models/generator/main.go index cf6ee5eb..1aea4fbe 100644 --- a/rules/models/generator/main.go +++ b/rules/models/generator/main.go @@ -5,7 +5,6 @@ package main import ( "encoding/json" "fmt" - "io/ioutil" "os" "path/filepath" "sort" @@ -15,6 +14,9 @@ import ( "github.com/hashicorp/hcl/v2/gohcl" "github.com/hashicorp/hcl/v2/hclparse" tfjson "github.com/hashicorp/terraform-json" + "github.com/zclconf/go-cty/cty" + "github.com/zclconf/go-cty/cty/function" + "github.com/zclconf/go-cty/cty/function/stdlib" utils "github.com/terraform-linters/tflint-ruleset-aws/rules/generator-utils" ) @@ -67,7 +69,7 @@ func main() { panic(err) } - mappingFiles := []mappingFile{} + var mappingFiles []mappingFile for _, file := range files { parser := hclparse.NewParser() f, diags := parser.ParseHCLFile(file) @@ -85,9 +87,9 @@ func main() { awsProvider := utils.LoadProviderSchema("../../tools/provider-schema/schema.json") - generatedRules := []string{} + var generatedRules []string for _, mappingFile := range mappingFiles { - raw, err := ioutil.ReadFile(mappingFile.Import) + raw, err := os.ReadFile(mappingFile.Import) if err != nil { panic(err) } @@ -99,10 +101,22 @@ func main() { } shapes := api["shapes"].(map[string]interface{}) + evalCtx := buildEvalContext() + for _, mapping := range mappingFile.Mappings { for attribute, value := range mapping.Attrs { fmt.Printf("Checking `%s.%s`\n", mapping.Resource, attribute) - shapeName := value.Expr.Variables()[0].RootName() + + // Extract shape name from the expression + vars := value.Expr.Variables() + if len(vars) == 0 { + continue + } + if len(vars) > 1 { + fmt.Fprintf(os.Stderr, "Error: `%s.%s` expression references multiple variables, only one shape allowed\n", mapping.Resource, attribute) + os.Exit(1) + } + shapeName := vars[0].RootName() if shapeName == "any" { continue } @@ -113,6 +127,29 @@ func main() { continue } + // Populate the eval context with this shape's enum values + if enumValues, ok := model["enum"].([]string); ok { + evalCtx.Variables[shapeName] = stringsToCtyList(enumValues) + + // Evaluate the expression to get transformed enum values + result, diags := value.Expr.Value(evalCtx) + if !diags.HasErrors() && result.Type().IsListType() { + var transformedEnums []string + for it := result.ElementIterator(); it.Next(); { + _, val := it.Element() + transformedEnums = append(transformedEnums, val.AsString()) + } + + // Create a new model with transformed enums + transformedModel := make(map[string]interface{}, len(model)) + for k, v := range model { + transformedModel[k] = v + } + transformedModel["enum"] = transformedEnums + model = transformedModel + } + } + schema, err := fetchSchema(mapping.Resource, attribute, model, awsProvider) if err != nil { fmt.Fprintf(os.Stderr, "Error processing `%s.%s`: %v\n", mapping.Resource, attribute, err) @@ -301,3 +338,61 @@ func convertSmithyShape(rawShape map[string]interface{}) map[string]interface{} return result } + +// stringsToCtyList converts a slice of strings to a cty list value +func stringsToCtyList(values []string) cty.Value { + ctyValues := make([]cty.Value, 0, len(values)) + for _, v := range values { + ctyValues = append(ctyValues, cty.StringVal(v)) + } + return cty.ListVal(ctyValues) +} + +// buildEvalContext creates an HCL evaluation context with transform functions +func buildEvalContext() *hcl.EvalContext { + return &hcl.EvalContext{ + Functions: map[string]function.Function{ + "uppercase": makeListTransformFunction(stdlib.UpperFunc), + "replace": makeListTransformFunction(stdlib.ReplaceFunc), + }, + Variables: make(map[string]cty.Value), + } +} + +// makeListTransformFunction wraps a string transform function to work on lists of strings +func makeListTransformFunction(strFunc function.Function) function.Function { + return function.New(&function.Spec{ + VarParam: &function.Parameter{ + Name: "args", + Type: cty.DynamicPseudoType, + }, + Type: func(args []cty.Value) (cty.Type, error) { + return cty.List(cty.String), nil + }, + Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { + if len(args) == 0 { + return cty.NilVal, fmt.Errorf("expected at least one argument") + } + if !args[0].Type().IsListType() { + return cty.NilVal, fmt.Errorf("first argument must be a list") + } + + var results []cty.Value + for it := args[0].ElementIterator(); it.Next(); { + _, val := it.Element() + + // Build args for the string function: [element, ...other args] + elementArgs := make([]cty.Value, len(args)) + elementArgs[0] = val + copy(elementArgs[1:], args[1:]) + + result, err := strFunc.Call(elementArgs) + if err != nil { + return cty.NilVal, err + } + results = append(results, result) + } + return cty.ListVal(results), nil + }, + }) +} diff --git a/rules/models/mappings/dms.hcl b/rules/models/mappings/dms.hcl index be1995e3..a199a4a3 100644 --- a/rules/models/mappings/dms.hcl +++ b/rules/models/mappings/dms.hcl @@ -66,6 +66,17 @@ mapping "aws_dms_replication_task" { target_endpoint_arn = String } +mapping "aws_dms_s3_endpoint" { + compression_type = uppercase(CompressionTypeValue) + encryption_mode = uppercase(replace(EncryptionModeValue, "-", "_")) + data_format = DataFormatValue + encoding_type = EncodingTypeValue + parquet_version = ParquetVersionValue + date_partition_sequence = uppercase(DatePartitionSequenceValue) + date_partition_delimiter = uppercase(DatePartitionDelimiterValue) + canned_acl_for_objects = uppercase(CannedAclForObjectsValue) +} + test "aws_dms_endpoint" "endpoint_type" { ok = "source" ng = "resource" diff --git a/rules/models/provider.go b/rules/models/provider.go index 55b13d1d..f4f2c5b7 100644 --- a/rules/models/provider.go +++ b/rules/models/provider.go @@ -435,6 +435,14 @@ var Rules = []tflint.Rule{ NewAwsDmsEndpointInvalidEndpointTypeRule(), NewAwsDmsEndpointInvalidSslModeRule(), NewAwsDmsReplicationTaskInvalidMigrationTypeRule(), + NewAwsDmsS3EndpointInvalidCannedACLForObjectsRule(), + NewAwsDmsS3EndpointInvalidCompressionTypeRule(), + NewAwsDmsS3EndpointInvalidDataFormatRule(), + NewAwsDmsS3EndpointInvalidDatePartitionDelimiterRule(), + NewAwsDmsS3EndpointInvalidDatePartitionSequenceRule(), + NewAwsDmsS3EndpointInvalidEncodingTypeRule(), + NewAwsDmsS3EndpointInvalidEncryptionModeRule(), + NewAwsDmsS3EndpointInvalidParquetVersionRule(), NewAwsDocDBGlobalClusterInvalidGlobalClusterIdentifierRule(), NewAwsDxBgpPeerInvalidAddressFamilyRule(), NewAwsDxHostedPrivateVirtualInterfaceInvalidAddressFamilyRule(),