From 2b6d63aa9eb72fa038fe3e10be8fb8b8a7b8e330 Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Fri, 21 Jun 2024 10:39:30 +0100 Subject: [PATCH] Add missing rules and make names nicer (#49) * Use replection to add waf rules and make the names nicer * linting * Fix integration tests * Update waf/waf.go Co-authored-by: Matt White <16320656+matt-FFFFFF@users.noreply.github.com> * Update waf/waf.go Co-authored-by: Matt White <16320656+matt-FFFFFF@users.noreply.github.com> * fix: duff suggestion * Make the code more readable * Simplify code --------- Co-authored-by: Matt White <16320656+matt-FFFFFF@users.noreply.github.com> --- attrvalue/nested_block_value_test.go | 24 ++++----- attrvalue/set_value.go | 12 +++-- attrvalue/set_value_test.go | 14 ++--- attrvalue/simple_value.go | 15 ++++-- attrvalue/simple_value_test.go | 36 ++++++------- attrvalue/unknown_value.go | 15 ++++-- attrvalue/unknown_value_test.go | 20 +++---- .../optional-defaults-incorrect/result.json | 2 +- .../unknownrule-null-incorrect/result.json | 2 +- rules/rule_register.go | 2 +- rules/rule_register_test.go | 20 +++++++ waf/azurerm_application_gateway.go | 6 ++- waf/azurerm_cosmosdb_account.go | 3 +- waf/azurerm_cosmosdb_account_test.go | 18 ++++--- waf/azurerm_kubernetes_cluster.go | 3 +- waf/azurerm_lb.go | 3 +- waf/azurerm_mysql_flexible_server.go | 6 ++- waf/azurerm_mysql_flexible_server_test.go | 24 +++++---- waf/azurerm_postgresql_flexible_server.go | 6 ++- ...azurerm_postgresql_flexible_server_test.go | 24 +++++---- waf/azurerm_public_ip.go | 6 ++- waf/azurerm_service_plan.go | 3 +- waf/azurerm_storage_account.go | 3 +- waf/azurerm_virtual_machine.go | 6 ++- waf/azurerm_virtual_network_gateway.go | 3 +- waf/waf.go | 52 +++++++++++++------ waf/{test_helpers_test.go => waf_test.go} | 8 +++ 27 files changed, 214 insertions(+), 122 deletions(-) create mode 100644 rules/rule_register_test.go rename waf/{test_helpers_test.go => waf_test.go} (50%) diff --git a/attrvalue/nested_block_value_test.go b/attrvalue/nested_block_value_test.go index 6431642..e8947ed 100644 --- a/attrvalue/nested_block_value_test.go +++ b/attrvalue/nested_block_value_test.go @@ -21,7 +21,7 @@ func TestNestedBlockValueRule(t *testing.T) { }{ { name: "correct string", - rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false), + rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false, ""), content: ` variable "test" { type = string @@ -36,7 +36,7 @@ func TestNestedBlockValueRule(t *testing.T) { }, { name: "incorrect string", - rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false), + rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false, ""), content: ` variable "test" { type = string @@ -49,14 +49,14 @@ func TestNestedBlockValueRule(t *testing.T) { }`, expected: helper.Issues{ { - Rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false), + Rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false, ""), Message: "baz is an invalid attribute value of `bar` - expecting (one of) [biz bat]", }, }, }, { name: "incorrect resource with correct block", - rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false), + rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false, ""), content: ` variable "test" { type = string @@ -71,7 +71,7 @@ func TestNestedBlockValueRule(t *testing.T) { }, { name: "no nested block of that type", - rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false), + rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false, ""), content: ` variable "test" { type = string @@ -86,7 +86,7 @@ func TestNestedBlockValueRule(t *testing.T) { }, { name: "no nested block of that type with must exist set", - rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", true), + rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", true, ""), content: ` variable "test" { type = string @@ -99,14 +99,14 @@ func TestNestedBlockValueRule(t *testing.T) { }`, expected: helper.Issues{ { - Rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", true), + Rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", true, ""), Message: "The attribute `bar` must be specified", }, }, }, { name: "no nested block attribute of that type with must exist set", - rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", true), + rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", true, ""), content: ` variable "test" { type = string @@ -119,14 +119,14 @@ func TestNestedBlockValueRule(t *testing.T) { }`, expected: helper.Issues{ { - Rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", true), + Rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", true, ""), Message: "The attribute `bar` must be specified", }, }, }, { name: "multiple blocks correct", - rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false), + rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false, ""), content: ` variable "test" { type = string @@ -144,7 +144,7 @@ func TestNestedBlockValueRule(t *testing.T) { }, { name: "multiple blocks partially correct", - rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false), + rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false, ""), content: ` variable "test" { type = string @@ -164,7 +164,7 @@ func TestNestedBlockValueRule(t *testing.T) { }`, expected: helper.Issues{ { - Rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false), + Rule: attrvalue.NewSimpleNestedBlockRule("foo", "fiz", "bar", []string{"biz", "bat"}, "", false, ""), Message: "incorrect is an invalid attribute value of `bar` - expecting (one of) [biz bat]", }, }, diff --git a/attrvalue/set_value.go b/attrvalue/set_value.go index 4114a55..77758ad 100644 --- a/attrvalue/set_value.go +++ b/attrvalue/set_value.go @@ -16,24 +16,30 @@ type SetRule[T cmp.Ordered] struct { tflint.DefaultRule // Embed the default rule to reuse its implementation baseValue expectedValues [][]T // e.g. [][int{1, 2, 3}] + ruleName string } var _ tflint.Rule = (*SetRule[int])(nil) var _ AttrValueRule = (*SimpleRule[any])(nil) // NewSetRule returns a new rule with the given resource type, attribute name, and expected values. -func NewSetRule[T cmp.Ordered](resourceType string, attributeName string, expectedValues [][]T, link string) *SetRule[T] { +func NewSetRule[T cmp.Ordered](resourceType string, attributeName string, expectedValues [][]T, link string, ruleName string) *SetRule[T] { return &SetRule[T]{ baseValue: newBaseValue(resourceType, nil, attributeName, true, link, tflint.ERROR), expectedValues: expectedValues, + ruleName: ruleName, } } func (r *SetRule[T]) Name() string { + if r.ruleName != "" { + return r.ruleName + } + if r.nestedBlockType != nil { - return fmt.Sprintf("set_value_%s.%s.%s", r.resourceType, *r.nestedBlockType, r.attributeName) + return fmt.Sprintf("%s.%s.%s", r.resourceType, *r.nestedBlockType, r.attributeName) } - return fmt.Sprintf("set_value_%s.%s", r.resourceType, r.attributeName) + return fmt.Sprintf("%s.%s", r.resourceType, r.attributeName) } func (r *SetRule[T]) Check(runner tflint.Runner) error { diff --git a/attrvalue/set_value_test.go b/attrvalue/set_value_test.go index a94e9a8..a21f8a4 100644 --- a/attrvalue/set_value_test.go +++ b/attrvalue/set_value_test.go @@ -19,7 +19,7 @@ func TestListNumberValueRule(t *testing.T) { }{ { name: "incorrect", - rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, ""), + rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, "", ""), content: ` variable "test" { type = list(number) @@ -30,14 +30,14 @@ func TestListNumberValueRule(t *testing.T) { }`, expected: helper.Issues{ { - Rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, ""), + Rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, "", ""), Message: "\"[3]\" is an invalid attribute value of `bar` - expecting (one of) [[1 2 3]]", }, }, }, { name: "correct", - rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, ""), + rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, "", ""), content: ` variable "test" { type = list(number) @@ -50,7 +50,7 @@ func TestListNumberValueRule(t *testing.T) { }, { name: "correct with string list", - rule: attrvalue.NewSetRule("foo", "bar", [][]string{{"1", "2", "3"}}, ""), + rule: attrvalue.NewSetRule("foo", "bar", [][]string{{"1", "2", "3"}}, "", ""), content: ` variable "test" { type = list(string) @@ -63,7 +63,7 @@ func TestListNumberValueRule(t *testing.T) { }, { name: "correct but different order", - rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, ""), + rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, "", ""), content: ` variable "test" { type = list(number) @@ -76,7 +76,7 @@ func TestListNumberValueRule(t *testing.T) { }, { name: "variable without default", - rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, ""), + rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, "", ""), content: ` variable "test" { type = list(number) @@ -88,7 +88,7 @@ func TestListNumberValueRule(t *testing.T) { }, { name: "variable with convertable element type", - rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, ""), + rule: attrvalue.NewSetRule("foo", "bar", [][]int{{1, 2, 3}}, "", ""), content: ` variable "test" { type = list(string) diff --git a/attrvalue/simple_value.go b/attrvalue/simple_value.go index 8bee00b..5d7ae39 100644 --- a/attrvalue/simple_value.go +++ b/attrvalue/simple_value.go @@ -17,26 +17,29 @@ type SimpleRule[T any] struct { baseValue expectedValues []T // e.g. []string{"ZRS"} mustExist bool + ruleName string } var _ tflint.Rule = (*SimpleRule[any])(nil) var _ AttrValueRule = (*SimpleRule[any])(nil) // NewSimpleRule returns a new rule with the given resource type, attribute name, and expected values. -func NewSimpleRule[T any](resourceType, attributeName string, expectedValues []T, link string, mustExist bool) *SimpleRule[T] { +func NewSimpleRule[T any](resourceType, attributeName string, expectedValues []T, link string, mustExist bool, ruleName string) *SimpleRule[T] { return &SimpleRule[T]{ baseValue: newBaseValue(resourceType, nil, attributeName, true, link, tflint.ERROR), expectedValues: expectedValues, mustExist: mustExist, + ruleName: ruleName, } } // NewSimpleNestedBlockRule returns a new rule with the given resource type, attribute name, and expected values. -func NewSimpleNestedBlockRule[T any](resourceType, nestedBlockType, attributeName string, expectedValues []T, link string, mustExist bool) *SimpleRule[T] { +func NewSimpleNestedBlockRule[T any](resourceType, nestedBlockType, attributeName string, expectedValues []T, link string, mustExist bool, ruleName string) *SimpleRule[T] { return &SimpleRule[T]{ baseValue: newBaseValue(resourceType, &nestedBlockType, attributeName, true, link, tflint.ERROR), expectedValues: expectedValues, mustExist: mustExist, + ruleName: ruleName, } } @@ -45,10 +48,14 @@ func (r *SimpleRule[T]) Link() string { } func (r *SimpleRule[T]) Name() string { + if r.ruleName != "" { + return r.ruleName + } + if r.nestedBlockType != nil { - return fmt.Sprintf("simple_value_%s.%s.%s", r.resourceType, *r.nestedBlockType, r.attributeName) + return fmt.Sprintf("%s.%s.%s", r.resourceType, *r.nestedBlockType, r.attributeName) } - return fmt.Sprintf("simple_value_%s.%s", r.resourceType, r.attributeName) + return fmt.Sprintf("%s.%s", r.resourceType, r.attributeName) } func (r *SimpleRule[T]) Check(runner tflint.Runner) error { diff --git a/attrvalue/simple_value_test.go b/attrvalue/simple_value_test.go index dcc17b5..6f1f7bc 100644 --- a/attrvalue/simple_value_test.go +++ b/attrvalue/simple_value_test.go @@ -19,7 +19,7 @@ func TestSimpleValueRule(t *testing.T) { }{ { name: "correct string", - rule: attrvalue.NewSimpleRule("foo", "bar", []string{"bar", "bat"}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []string{"bar", "bat"}, "", false, ""), content: ` variable "test" { type = string @@ -32,7 +32,7 @@ func TestSimpleValueRule(t *testing.T) { }, { name: "incorrect string", - rule: attrvalue.NewSimpleRule("foo", "bar", []string{"bar", "bat"}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []string{"bar", "bat"}, "", false, ""), content: ` variable "test" { type = string @@ -43,14 +43,14 @@ func TestSimpleValueRule(t *testing.T) { }`, expected: helper.Issues{ { - Rule: attrvalue.NewSimpleRule("foo", "bar", []string{"bar", "bat"}, "", false), + Rule: attrvalue.NewSimpleRule("foo", "bar", []string{"bar", "bat"}, "", false, ""), Message: "fiz is an invalid attribute value of `bar` - expecting (one of) [bar bat]", }, }, }, { name: "correct number", - rule: attrvalue.NewSimpleRule("foo", "bar", []int{1, 2}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []int{1, 2}, "", false, ""), content: ` variable "test" { type = number @@ -63,7 +63,7 @@ func TestSimpleValueRule(t *testing.T) { }, { name: "correct number float", - rule: attrvalue.NewSimpleRule("foo", "bar", []float64{1.2, 2.1}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []float64{1.2, 2.1}, "", false, ""), content: ` variable "test" { type = number @@ -76,7 +76,7 @@ resource "foo" "example" { }, { name: "incorrect number", - rule: attrvalue.NewSimpleRule("foo", "bar", []int{1, 2}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []int{1, 2}, "", false, ""), content: ` variable "test" { type = number @@ -87,14 +87,14 @@ resource "foo" "example" { }`, expected: helper.Issues{ { - Rule: attrvalue.NewSimpleRule("foo", "bar", []int{1, 2}, "", false), + Rule: attrvalue.NewSimpleRule("foo", "bar", []int{1, 2}, "", false, ""), Message: "3 is an invalid attribute value of `bar` - expecting (one of) [1 2]", }, }, }, { name: "incorrect number float", - rule: attrvalue.NewSimpleRule("foo", "bar", []float64{1.1, 2.2}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []float64{1.1, 2.2}, "", false, ""), content: ` variable "test" { type = number @@ -105,14 +105,14 @@ resource "foo" "example" { }`, expected: helper.Issues{ { - Rule: attrvalue.NewSimpleRule("foo", "bar", []float64{1.1, 2.2}, "", false), + Rule: attrvalue.NewSimpleRule("foo", "bar", []float64{1.1, 2.2}, "", false, ""), Message: "2.1 is an invalid attribute value of `bar` - expecting (one of) [1.1 2.2]", }, }, }, { name: "correct bool", - rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false, ""), content: ` variable "test" { type = bool @@ -125,7 +125,7 @@ resource "foo" "example" { }, { name: "incorrect bool", - rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false, ""), content: ` variable "test" { type = bool @@ -136,14 +136,14 @@ resource "foo" "example" { }`, expected: helper.Issues{ { - Rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false), + Rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false, ""), Message: "false is an invalid attribute value of `bar` - expecting (one of) [true]", }, }, }, { name: "null value", - rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false, ""), content: ` variable "test" { type = bool @@ -156,7 +156,7 @@ resource "foo" "example" { }, { name: "optional value", - rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false, ""), content: ` variable "test" { type = object({ @@ -171,7 +171,7 @@ resource "foo" "example" { }, { name: "missing attribute", - rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false, ""), content: ` resource "foo" "example" { @@ -180,21 +180,21 @@ resource "foo" "example" { }, { name: "missing attribute with must exist", - rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", true), + rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", true, ""), content: ` resource "foo" "example" { }`, expected: helper.Issues{ { - Rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", true), + Rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", true, ""), Message: "The attribute `bar` must be specified", }, }, }, { name: "correct attribute incorrect resource", - rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false), + rule: attrvalue.NewSimpleRule("foo", "bar", []bool{true}, "", false, ""), content: ` variable "test" { type = bool diff --git a/attrvalue/unknown_value.go b/attrvalue/unknown_value.go index 640e200..92541de 100644 --- a/attrvalue/unknown_value.go +++ b/attrvalue/unknown_value.go @@ -13,6 +13,7 @@ import ( type UnknownValueRule struct { tflint.DefaultRule // Embed the default rule to reuse its implementation baseValue + ruleName string } var _ tflint.Rule = (*UnknownValueRule)(nil) @@ -23,9 +24,10 @@ func (r *UnknownValueRule) GetNestedBlockType() *string { } // NewUnknownValueRule returns a new rule with the given resource type, and attribute name -func NewUnknownValueRule(resourceType, attributeName, link string) *UnknownValueRule { +func NewUnknownValueRule(resourceType, attributeName, link string, ruleName string) *UnknownValueRule { return &UnknownValueRule{ baseValue: newBaseValue(resourceType, nil, attributeName, true, link, tflint.ERROR), + ruleName: ruleName, } } @@ -34,17 +36,22 @@ func (r *UnknownValueRule) Link() string { } // NewUnknownValueNestedBlockRule returns a new rule with the given resource type, nested block type, and attribute name -func NewUnknownValueNestedBlockRule(resourceType, nestedBlockType, attributeName, link string) *UnknownValueRule { +func NewUnknownValueNestedBlockRule(resourceType, nestedBlockType, attributeName, link string, ruleName string) *UnknownValueRule { return &UnknownValueRule{ baseValue: newBaseValue(resourceType, &nestedBlockType, attributeName, true, link, tflint.ERROR), + ruleName: ruleName, } } func (r *UnknownValueRule) Name() string { + if r.ruleName != "" { + return r.ruleName + } + if r.nestedBlockType != nil { - return fmt.Sprintf("unknown_value_%s.%s.%s", r.resourceType, *r.nestedBlockType, r.attributeName) + return fmt.Sprintf("%s.%s.%s", r.resourceType, *r.nestedBlockType, r.attributeName) } - return fmt.Sprintf("unknown_value_%s.%s", r.resourceType, r.attributeName) + return fmt.Sprintf("%s.%s", r.resourceType, r.attributeName) } func (r *UnknownValueRule) Check(runner tflint.Runner) error { diff --git a/attrvalue/unknown_value_test.go b/attrvalue/unknown_value_test.go index 0efa65d..9e7c2df 100644 --- a/attrvalue/unknown_value_test.go +++ b/attrvalue/unknown_value_test.go @@ -19,7 +19,7 @@ func TestUnknownValueRule(t *testing.T) { }{ { name: "unknown string value", - rule: attrvalue.NewUnknownValueRule("foo", "bar", ""), + rule: attrvalue.NewUnknownValueRule("foo", "bar", "", ""), content: ` variable "test" { type = string @@ -32,7 +32,7 @@ func TestUnknownValueRule(t *testing.T) { }, { name: "null value with local", - rule: attrvalue.NewUnknownValueRule("foo", "bar", ""), + rule: attrvalue.NewUnknownValueRule("foo", "bar", "", ""), content: ` locals { bar = null @@ -43,14 +43,14 @@ func TestUnknownValueRule(t *testing.T) { }`, expected: helper.Issues{ { - Rule: attrvalue.NewUnknownValueRule("foo", "bar", ""), + Rule: attrvalue.NewUnknownValueRule("foo", "bar", "", ""), Message: "invalid attribute value of `bar` - expecting unknown", }, }, }, { name: "default value", - rule: attrvalue.NewUnknownValueRule("foo", "bar", ""), + rule: attrvalue.NewUnknownValueRule("foo", "bar", "", ""), content: ` variable "test" { type = string @@ -61,14 +61,14 @@ func TestUnknownValueRule(t *testing.T) { }`, expected: helper.Issues{ { - Rule: attrvalue.NewUnknownValueRule("foo", "bar", ""), + Rule: attrvalue.NewUnknownValueRule("foo", "bar", "", ""), Message: "invalid attribute value of `bar` - expecting unknown", }, }, }, { name: "unknown number value", - rule: attrvalue.NewUnknownValueRule("foo", "bar", ""), + rule: attrvalue.NewUnknownValueRule("foo", "bar", "", ""), content: ` variable "test" { type = number @@ -80,7 +80,7 @@ func TestUnknownValueRule(t *testing.T) { }, { name: "not null (number)", - rule: attrvalue.NewUnknownValueRule("foo", "bar", ""), + rule: attrvalue.NewUnknownValueRule("foo", "bar", "", ""), content: ` variable "test" { type = number @@ -91,14 +91,14 @@ func TestUnknownValueRule(t *testing.T) { }`, expected: helper.Issues{ { - Rule: attrvalue.NewUnknownValueRule("foo", "bar", ""), + Rule: attrvalue.NewUnknownValueRule("foo", "bar", "", ""), Message: "invalid attribute value of `bar` - expecting unknown", }, }, }, { name: "attribute not found", - rule: attrvalue.NewUnknownValueRule("foo", "bar", ""), + rule: attrvalue.NewUnknownValueRule("foo", "bar", "", ""), content: ` variable "test" { type = bool @@ -110,7 +110,7 @@ func TestUnknownValueRule(t *testing.T) { }, { name: "empty config", - rule: attrvalue.NewUnknownValueRule("foo", "bar", ""), + rule: attrvalue.NewUnknownValueRule("foo", "bar", "", ""), content: ``, expected: helper.Issues{}, }, diff --git a/integration/optional-defaults-incorrect/result.json b/integration/optional-defaults-incorrect/result.json index 2a21e31..99c81f9 100644 --- a/integration/optional-defaults-incorrect/result.json +++ b/integration/optional-defaults-incorrect/result.json @@ -17,7 +17,7 @@ }, "rule": { "link": "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/networking/load-balancer/#lb-1---use-standard-load-balancer-sku", - "name": "simple_value_azurerm_lb.sku", + "name": "azurerm_lb.sku", "severity": "error" } } diff --git a/integration/unknownrule-null-incorrect/result.json b/integration/unknownrule-null-incorrect/result.json index 435ac1c..5c862e6 100644 --- a/integration/unknownrule-null-incorrect/result.json +++ b/integration/unknownrule-null-incorrect/result.json @@ -17,7 +17,7 @@ }, "rule": { "link": "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/compute/virtual-machines/#vm-2---deploy-vms-across-availability-zones", - "name": "unknown_value_azurerm_virtual_machine.zone", + "name": "azurerm_virtual_machine.zone", "severity": "error" } } diff --git a/rules/rule_register.go b/rules/rule_register.go index 5c3603a..581b0ef 100644 --- a/rules/rule_register.go +++ b/rules/rule_register.go @@ -26,7 +26,7 @@ var Rules = func() []tflint.Rule { NewTerraformDotTfRule(), NewModuleSourceRule(), }, - waf.Rules, + waf.GetRules(), interfaces.Rules, outputs.Rules, ) diff --git a/rules/rule_register_test.go b/rules/rule_register_test.go new file mode 100644 index 0000000..5b41c75 --- /dev/null +++ b/rules/rule_register_test.go @@ -0,0 +1,20 @@ +package rules_test + +import ( + "testing" + + "github.com/Azure/tflint-ruleset-avm/rules" +) + +func TestDuplicateRuleNames(t *testing.T) { + rules := rules.Rules + + names := make(map[string]bool) + for _, rule := range rules { + name := rule.Name() + if names[name] { + t.Errorf("duplicate rule name: %s", name) + } + names[name] = true + } +} diff --git a/waf/azurerm_application_gateway.go b/waf/azurerm_application_gateway.go index 08db6b3..d86c664 100644 --- a/waf/azurerm_application_gateway.go +++ b/waf/azurerm_application_gateway.go @@ -2,16 +2,17 @@ package waf import "github.com/Azure/tflint-ruleset-avm/attrvalue" -func AzurermApplicationGatewayZones() *attrvalue.SetRule[int] { +func (wf WafRules) AzurermApplicationGatewayZones() *attrvalue.SetRule[int] { return attrvalue.NewSetRule( "azurerm_application_gateway", "zones", [][]int{{1, 2, 3}}, "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/networking/application-gateway/#agw-1---set-a-minimum-instance-count-of-2", + "", ) } -func AzurermApplicationGatewaySku() *attrvalue.SimpleRule[string] { +func (wf WafRules) AzurermApplicationGatewaySku() *attrvalue.SimpleRule[string] { return attrvalue.NewSimpleNestedBlockRule[string]( "azurerm_application_gateway", "sku", @@ -19,5 +20,6 @@ func AzurermApplicationGatewaySku() *attrvalue.SimpleRule[string] { []string{"Standard_v2", "WAF_v2"}, "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/networking/application-gateway/#agw-4---use-application-gw-v2-instead-of-v1", false, + "", ) } diff --git a/waf/azurerm_cosmosdb_account.go b/waf/azurerm_cosmosdb_account.go index 18d6d97..5e4e956 100644 --- a/waf/azurerm_cosmosdb_account.go +++ b/waf/azurerm_cosmosdb_account.go @@ -4,7 +4,7 @@ import ( "github.com/Azure/tflint-ruleset-avm/attrvalue" ) -func AzurermCosmosDbAccountBackupMode() *attrvalue.SimpleRule[string] { +func (wf WafRules) AzurermCosmosDbAccountBackupMode() *attrvalue.SimpleRule[string] { return attrvalue.NewSimpleNestedBlockRule[string]( "azurerm_cosmosdb_account", "backup", @@ -12,5 +12,6 @@ func AzurermCosmosDbAccountBackupMode() *attrvalue.SimpleRule[string] { []string{"Continuous"}, "https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/DocumentDB/databaseAccounts/#configure-continuous-backup-mode", true, + "", ) } diff --git a/waf/azurerm_cosmosdb_account_test.go b/waf/azurerm_cosmosdb_account_test.go index 6132fba..ef90f56 100644 --- a/waf/azurerm_cosmosdb_account_test.go +++ b/waf/azurerm_cosmosdb_account_test.go @@ -12,6 +12,8 @@ import ( ) func TestAzurermCosmosDbAccountBackupMode(t *testing.T) { + wafRules := waf.WafRules{} + testCases := []struct { name string rule tflint.Rule @@ -20,7 +22,7 @@ func TestAzurermCosmosDbAccountBackupMode(t *testing.T) { }{ { name: "correct setting", - rule: waf.AzurermCosmosDbAccountBackupMode(), + rule: wafRules.AzurermCosmosDbAccountBackupMode(), content: ` variable "backup_type" { type = string @@ -35,7 +37,7 @@ func TestAzurermCosmosDbAccountBackupMode(t *testing.T) { }, { name: "incorrect setting", - rule: waf.AzurermCosmosDbAccountBackupMode(), + rule: wafRules.AzurermCosmosDbAccountBackupMode(), content: ` variable "backup_type" { type = string @@ -48,28 +50,28 @@ func TestAzurermCosmosDbAccountBackupMode(t *testing.T) { }`, expected: helper.Issues{ { - Rule: waf.AzurermCosmosDbAccountBackupMode(), + Rule: wafRules.AzurermCosmosDbAccountBackupMode(), Message: "Periodic is an invalid attribute value of `type` - expecting (one of) [Continuous]", }, }, }, { name: "missing block", - rule: waf.AzurermCosmosDbAccountBackupMode(), + rule: wafRules.AzurermCosmosDbAccountBackupMode(), content: ` resource "azurerm_cosmosdb_account" "example" { }`, expected: helper.Issues{ { - Rule: waf.AzurermCosmosDbAccountBackupMode(), + Rule: wafRules.AzurermCosmosDbAccountBackupMode(), Message: "The attribute `type` must be specified", }, }, }, { name: "missing block attribute", - rule: waf.AzurermCosmosDbAccountBackupMode(), + rule: wafRules.AzurermCosmosDbAccountBackupMode(), content: ` resource "azurerm_cosmosdb_account" "example" { backup { @@ -78,14 +80,14 @@ func TestAzurermCosmosDbAccountBackupMode(t *testing.T) { }`, expected: helper.Issues{ { - Rule: waf.AzurermCosmosDbAccountBackupMode(), + Rule: wafRules.AzurermCosmosDbAccountBackupMode(), Message: "The attribute `type` must be specified", }, }, }, { name: "missing resource", - rule: waf.AzurermCosmosDbAccountBackupMode(), + rule: wafRules.AzurermCosmosDbAccountBackupMode(), content: ` resource "something_else" "example" { diff --git a/waf/azurerm_kubernetes_cluster.go b/waf/azurerm_kubernetes_cluster.go index bedc7b2..4104506 100644 --- a/waf/azurerm_kubernetes_cluster.go +++ b/waf/azurerm_kubernetes_cluster.go @@ -2,11 +2,12 @@ package waf import "github.com/Azure/tflint-ruleset-avm/attrvalue" -func AzurermKubernetesClusterZones() *attrvalue.SetRule[int] { +func (wf WafRules) AzurermKubernetesClusterZones() *attrvalue.SetRule[int] { return attrvalue.NewSetRule( "azurerm_kubernetes_cluster", "zones", [][]int{{1, 2, 3}}, "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/container/aks/#aks-1---deploy-aks-cluster-across-availability-zones", + "", ) } diff --git a/waf/azurerm_lb.go b/waf/azurerm_lb.go index 9a89828..7c57e7f 100644 --- a/waf/azurerm_lb.go +++ b/waf/azurerm_lb.go @@ -4,12 +4,13 @@ import ( "github.com/Azure/tflint-ruleset-avm/attrvalue" ) -func AzurermLbSku() *attrvalue.SimpleRule[string] { +func (wf WafRules) AzurermLbSku() *attrvalue.SimpleRule[string] { return attrvalue.NewSimpleRule[string]( "azurerm_lb", "sku", []string{"Standard"}, "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/networking/load-balancer/#lb-1---use-standard-load-balancer-sku", false, + "", ) } diff --git a/waf/azurerm_mysql_flexible_server.go b/waf/azurerm_mysql_flexible_server.go index 0cf7ab0..cce88c8 100644 --- a/waf/azurerm_mysql_flexible_server.go +++ b/waf/azurerm_mysql_flexible_server.go @@ -4,7 +4,7 @@ import ( "github.com/Azure/tflint-ruleset-avm/attrvalue" ) -func AzurermMySqlFlexibleServerZoneRedundancy() *attrvalue.SimpleRule[string] { +func (wf WafRules) AzurermMySqlFlexibleServerZoneRedundancy() *attrvalue.SimpleRule[string] { return attrvalue.NewSimpleNestedBlockRule[string]( "azurerm_mysql_flexible_server", "high_availability", @@ -12,10 +12,11 @@ func AzurermMySqlFlexibleServerZoneRedundancy() *attrvalue.SimpleRule[string] { []string{"ZoneRedundant"}, "https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/DBforMySQL/flexibleServers/#enable-ha-with-zone-redundancy", true, + "", ) } -func AzurermMySqlFlexibleServerCustomMaintenanceSchedule() *attrvalue.SimpleRule[string] { +func (wf WafRules) AzurermMySqlFlexibleServerCustomMaintenanceSchedule() *attrvalue.SimpleRule[string] { return attrvalue.NewSimpleNestedBlockRule[string]( "azurerm_mysql_flexible_server", "maintenance_window", @@ -23,5 +24,6 @@ func AzurermMySqlFlexibleServerCustomMaintenanceSchedule() *attrvalue.SimpleRule []string{"0", "1", "2", "3", "4", "5", "6"}, "https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/DBforMySQL/flexibleServers/#enable-custom-maintenance-schedule", true, + "", ) } diff --git a/waf/azurerm_mysql_flexible_server_test.go b/waf/azurerm_mysql_flexible_server_test.go index 70e7f1c..48b2188 100644 --- a/waf/azurerm_mysql_flexible_server_test.go +++ b/waf/azurerm_mysql_flexible_server_test.go @@ -12,6 +12,8 @@ import ( ) func TestAzurermMySqlFlexibleServerZoneRedundancy(t *testing.T) { + wafRules := waf.WafRules{} + testCases := []struct { name string rule tflint.Rule @@ -20,7 +22,7 @@ func TestAzurermMySqlFlexibleServerZoneRedundancy(t *testing.T) { }{ { name: "correct setting", - rule: waf.AzurermMySqlFlexibleServerZoneRedundancy(), + rule: wafRules.AzurermMySqlFlexibleServerZoneRedundancy(), content: ` variable "high_availability_mode" { type = string @@ -35,7 +37,7 @@ func TestAzurermMySqlFlexibleServerZoneRedundancy(t *testing.T) { }, { name: "incorrect setting", - rule: waf.AzurermMySqlFlexibleServerZoneRedundancy(), + rule: wafRules.AzurermMySqlFlexibleServerZoneRedundancy(), content: ` variable "high_availability_mode" { type = string @@ -48,21 +50,21 @@ func TestAzurermMySqlFlexibleServerZoneRedundancy(t *testing.T) { }`, expected: helper.Issues{ { - Rule: waf.AzurermMySqlFlexibleServerZoneRedundancy(), + Rule: wafRules.AzurermMySqlFlexibleServerZoneRedundancy(), Message: "SameZone is an invalid attribute value of `mode` - expecting (one of) [ZoneRedundant]", }, }, }, { name: "missing block", - rule: waf.AzurermMySqlFlexibleServerZoneRedundancy(), + rule: wafRules.AzurermMySqlFlexibleServerZoneRedundancy(), content: ` resource "azurerm_mysql_flexible_server" "example" { }`, expected: helper.Issues{ { - Rule: waf.AzurermMySqlFlexibleServerZoneRedundancy(), + Rule: wafRules.AzurermMySqlFlexibleServerZoneRedundancy(), Message: "The attribute `mode` must be specified", }, }, @@ -85,6 +87,8 @@ func TestAzurermMySqlFlexibleServerZoneRedundancy(t *testing.T) { } func TestAzurermMySqlFlexibleServerCustomMaintenanceSchedule(t *testing.T) { + wafRules := waf.WafRules{} + testCases := []struct { name string rule tflint.Rule @@ -93,7 +97,7 @@ func TestAzurermMySqlFlexibleServerCustomMaintenanceSchedule(t *testing.T) { }{ { name: "correct setting", - rule: waf.AzurermMySqlFlexibleServerCustomMaintenanceSchedule(), + rule: wafRules.AzurermMySqlFlexibleServerCustomMaintenanceSchedule(), content: ` variable "maintenance_window" { type = string @@ -108,7 +112,7 @@ func TestAzurermMySqlFlexibleServerCustomMaintenanceSchedule(t *testing.T) { }, { name: "incorrect setting", - rule: waf.AzurermMySqlFlexibleServerCustomMaintenanceSchedule(), + rule: wafRules.AzurermMySqlFlexibleServerCustomMaintenanceSchedule(), content: ` variable "maintenance_window" { type = string @@ -121,21 +125,21 @@ func TestAzurermMySqlFlexibleServerCustomMaintenanceSchedule(t *testing.T) { }`, expected: helper.Issues{ { - Rule: waf.AzurermMySqlFlexibleServerCustomMaintenanceSchedule(), + Rule: wafRules.AzurermMySqlFlexibleServerCustomMaintenanceSchedule(), Message: "20 is an invalid attribute value of `day_of_week` - expecting (one of) [0 1 2 3 4 5 6]", }, }, }, { name: "missing block", - rule: waf.AzurermMySqlFlexibleServerCustomMaintenanceSchedule(), + rule: wafRules.AzurermMySqlFlexibleServerCustomMaintenanceSchedule(), content: ` resource "azurerm_mysql_flexible_server" "example" { }`, expected: helper.Issues{ { - Rule: waf.AzurermMySqlFlexibleServerCustomMaintenanceSchedule(), + Rule: wafRules.AzurermMySqlFlexibleServerCustomMaintenanceSchedule(), Message: "The attribute `day_of_week` must be specified", }, }, diff --git a/waf/azurerm_postgresql_flexible_server.go b/waf/azurerm_postgresql_flexible_server.go index c9b6e6d..122ad8c 100644 --- a/waf/azurerm_postgresql_flexible_server.go +++ b/waf/azurerm_postgresql_flexible_server.go @@ -4,7 +4,7 @@ import ( "github.com/Azure/tflint-ruleset-avm/attrvalue" ) -func AzurermPostgreSqlFlexibleServerZoneRedundancy() *attrvalue.SimpleRule[string] { +func (wf WafRules) AzurermPostgreSqlFlexibleServerZoneRedundancy() *attrvalue.SimpleRule[string] { return attrvalue.NewSimpleNestedBlockRule[string]( "azurerm_postgresql_flexible_server", "high_availability", @@ -12,10 +12,11 @@ func AzurermPostgreSqlFlexibleServerZoneRedundancy() *attrvalue.SimpleRule[strin []string{"ZoneRedundant"}, "https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/DBforPostgreSQL/flexibleServers/#enable-ha-with-zone-redundancy", true, + "", ) } -func AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule() *attrvalue.SimpleRule[string] { +func (wf WafRules) AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule() *attrvalue.SimpleRule[string] { return attrvalue.NewSimpleNestedBlockRule[string]( "azurerm_postgresql_flexible_server", "maintenance_window", @@ -23,5 +24,6 @@ func AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule() *attrvalue.Simpl []string{"0", "1", "2", "3", "4", "5", "6"}, "https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/DBforPostgreSQL/flexibleServers/#enable-custom-maintenance-schedule", true, + "", ) } diff --git a/waf/azurerm_postgresql_flexible_server_test.go b/waf/azurerm_postgresql_flexible_server_test.go index d752ead..ecd594f 100644 --- a/waf/azurerm_postgresql_flexible_server_test.go +++ b/waf/azurerm_postgresql_flexible_server_test.go @@ -12,6 +12,8 @@ import ( ) func TestAzurermPostgreSqlFlexibleServerZoneRedundancy(t *testing.T) { + wafRules := waf.WafRules{} + testCases := []struct { name string rule tflint.Rule @@ -20,7 +22,7 @@ func TestAzurermPostgreSqlFlexibleServerZoneRedundancy(t *testing.T) { }{ { name: "correct setting", - rule: waf.AzurermPostgreSqlFlexibleServerZoneRedundancy(), + rule: wafRules.AzurermPostgreSqlFlexibleServerZoneRedundancy(), content: ` variable "high_availability_mode" { type = string @@ -35,7 +37,7 @@ func TestAzurermPostgreSqlFlexibleServerZoneRedundancy(t *testing.T) { }, { name: "incorrect setting", - rule: waf.AzurermPostgreSqlFlexibleServerZoneRedundancy(), + rule: wafRules.AzurermPostgreSqlFlexibleServerZoneRedundancy(), content: ` variable "high_availability_mode" { type = string @@ -48,21 +50,21 @@ func TestAzurermPostgreSqlFlexibleServerZoneRedundancy(t *testing.T) { }`, expected: helper.Issues{ { - Rule: waf.AzurermPostgreSqlFlexibleServerZoneRedundancy(), + Rule: wafRules.AzurermPostgreSqlFlexibleServerZoneRedundancy(), Message: "SameZone is an invalid attribute value of `mode` - expecting (one of) [ZoneRedundant]", }, }, }, { name: "missing block", - rule: waf.AzurermPostgreSqlFlexibleServerZoneRedundancy(), + rule: wafRules.AzurermPostgreSqlFlexibleServerZoneRedundancy(), content: ` resource "azurerm_postgresql_flexible_server" "example" { }`, expected: helper.Issues{ { - Rule: waf.AzurermPostgreSqlFlexibleServerZoneRedundancy(), + Rule: wafRules.AzurermPostgreSqlFlexibleServerZoneRedundancy(), Message: "The attribute `mode` must be specified", }, }, @@ -85,6 +87,8 @@ func TestAzurermPostgreSqlFlexibleServerZoneRedundancy(t *testing.T) { } func TestAzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(t *testing.T) { + wafRules := waf.WafRules{} + testCases := []struct { name string rule tflint.Rule @@ -93,7 +97,7 @@ func TestAzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(t *testing.T) }{ { name: "correct setting", - rule: waf.AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(), + rule: wafRules.AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(), content: ` variable "maintenance_window" { type = string @@ -108,7 +112,7 @@ func TestAzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(t *testing.T) }, { name: "incorrect setting", - rule: waf.AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(), + rule: wafRules.AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(), content: ` variable "maintenance_window" { type = string @@ -121,21 +125,21 @@ func TestAzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(t *testing.T) }`, expected: helper.Issues{ { - Rule: waf.AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(), + Rule: wafRules.AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(), Message: "20 is an invalid attribute value of `day_of_week` - expecting (one of) [0 1 2 3 4 5 6]", }, }, }, { name: "missing block", - rule: waf.AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(), + rule: wafRules.AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(), content: ` resource "azurerm_postgresql_flexible_server" "example" { }`, expected: helper.Issues{ { - Rule: waf.AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(), + Rule: wafRules.AzurermPostgreSqlFlexibleServerCustomMaintenanceSchedule(), Message: "The attribute `day_of_week` must be specified", }, }, diff --git a/waf/azurerm_public_ip.go b/waf/azurerm_public_ip.go index 3a470ed..9c487a2 100644 --- a/waf/azurerm_public_ip.go +++ b/waf/azurerm_public_ip.go @@ -4,21 +4,23 @@ import ( "github.com/Azure/tflint-ruleset-avm/attrvalue" ) -func AzurermPublicIpSku() *attrvalue.SimpleRule[string] { +func (wf WafRules) AzurermPublicIpSku() *attrvalue.SimpleRule[string] { return attrvalue.NewSimpleRule[string]( "azurerm_public_ip", "sku", []string{"Standard"}, "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/networking/public-ip/#pip-1---use-standard-sku-and-zone-redundant-ips-when-applicable", false, + "", ) } -func AzurermPublicIpZones() *attrvalue.SetRule[int] { +func (wf WafRules) AzurermPublicIpZones() *attrvalue.SetRule[int] { return attrvalue.NewSetRule( "azurerm_public_ip", "zones", [][]int{{1, 2, 3}}, "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/networking/public-ip/#pip-1---use-standard-sku-and-zone-redundant-ips-when-applicable", + "", ) } diff --git a/waf/azurerm_service_plan.go b/waf/azurerm_service_plan.go index 74ba911..13fe201 100644 --- a/waf/azurerm_service_plan.go +++ b/waf/azurerm_service_plan.go @@ -4,12 +4,13 @@ import ( "github.com/Azure/tflint-ruleset-avm/attrvalue" ) -func AzurermServicePlanZoneBalancingEnabled() *attrvalue.SimpleRule[bool] { +func (wf WafRules) AzurermServicePlanZoneBalancingEnabled() *attrvalue.SimpleRule[bool] { return attrvalue.NewSimpleRule[bool]( "azurerm_service_plan", "zone_balancing_enabled", []bool{true}, "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/web/app-service-plan/#asp-1---migrate-app-service-to-availability-zone-support", false, + "", ) } diff --git a/waf/azurerm_storage_account.go b/waf/azurerm_storage_account.go index 7a89f51..c121273 100644 --- a/waf/azurerm_storage_account.go +++ b/waf/azurerm_storage_account.go @@ -4,12 +4,13 @@ import ( "github.com/Azure/tflint-ruleset-avm/attrvalue" ) -func AzurermStorageAccountAccountReplicationType() *attrvalue.SimpleRule[string] { +func (wf WafRules) AzurermStorageAccountAccountReplicationType() *attrvalue.SimpleRule[string] { return attrvalue.NewSimpleRule[string]( "azurerm_storage_account", "account_replication_type", []string{"ZRS"}, "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/storage/storage-account/#st-1---ensure-that-storage-accounts-are-zone-or-region-redundant", false, + "", ) } diff --git a/waf/azurerm_virtual_machine.go b/waf/azurerm_virtual_machine.go index cfae9eb..f27733f 100644 --- a/waf/azurerm_virtual_machine.go +++ b/waf/azurerm_virtual_machine.go @@ -2,18 +2,20 @@ package waf import "github.com/Azure/tflint-ruleset-avm/attrvalue" -func AzurermVirtualMachineZoneUnknown() *attrvalue.UnknownValueRule { +func (wf WafRules) AzurermVirtualMachineZoneUnknown() *attrvalue.UnknownValueRule { return attrvalue.NewUnknownValueRule( "azurerm_virtual_machine", "zone", "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/compute/virtual-machines/#vm-2---deploy-vms-across-availability-zones", + "", ) } -func AzurermVirtualMachineZonesUnknown() *attrvalue.UnknownValueRule { +func (wf WafRules) AzurermVirtualMachineZonesUnknown() *attrvalue.UnknownValueRule { return attrvalue.NewUnknownValueRule( "azurerm_virtual_machine", "zones", "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/compute/virtual-machines/#vm-2---deploy-vms-across-availability-zones", + "", ) } diff --git a/waf/azurerm_virtual_network_gateway.go b/waf/azurerm_virtual_network_gateway.go index a705af0..1cd827e 100644 --- a/waf/azurerm_virtual_network_gateway.go +++ b/waf/azurerm_virtual_network_gateway.go @@ -4,12 +4,13 @@ import ( "github.com/Azure/tflint-ruleset-avm/attrvalue" ) -func AzurermVirtualNetworkGatewaySku() *attrvalue.SimpleRule[string] { +func (wf WafRules) AzurermVirtualNetworkGatewaySku() *attrvalue.SimpleRule[string] { return attrvalue.NewSimpleRule[string]( "azurerm_virtual_network_gateway", "sku", []string{"ErGw1AZ", "ErGw2AZ", "ErGw3AZ", "VpnGw1AZ", "VpnGw2AZ", "VpnGw3AZ", "VpnGw4AZ", "VpnGw5AZ"}, "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/networking/expressroute-gateway/#ergw-2---use-zone-redundant-gateway-skus", false, + "", ) } diff --git a/waf/waf.go b/waf/waf.go index 5a1eb5e..cbbc335 100644 --- a/waf/waf.go +++ b/waf/waf.go @@ -3,21 +3,39 @@ // Then add the rule to the Rules slice. package waf -import "github.com/terraform-linters/tflint-plugin-sdk/tflint" - -// Rules is the list of rules for Well Architected Alignment. -// Make sure to add any new rules to this list. -// Please sort the list to be kind to your fellow maintainers. -var Rules = []tflint.Rule{ - AzurermApplicationGatewaySku(), - AzurermApplicationGatewayZones(), - AzurermKubernetesClusterZones(), - AzurermLbSku(), - AzurermPublicIpSku(), - AzurermPublicIpZones(), - AzurermServicePlanZoneBalancingEnabled(), - AzurermStorageAccountAccountReplicationType(), - AzurermVirtualMachineZoneUnknown(), - AzurermVirtualMachineZonesUnknown(), - AzurermVirtualNetworkGatewaySku(), +import ( + "reflect" + + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// WafRules is a helper struct. Methods are created on this type that generate the rules for the WAF package. +// We then use reflection to automatically generate a slice of the rules to add the the ruleset. +type WafRules struct{} + +// GetRules uses reflection to iterate over all the methods of the WafRules struct and add them to a slice of Rules to be included in the ruleset. +// See `GetRules()` implementation for more detail. +func GetRules() []tflint.Rule { + // Create a slice to add the rules to + rules := []tflint.Rule{} + + // Get an instance of the WefRules struct we can use to iterate and call functions on + wafRulesInstance := reflect.ValueOf(WafRules{}) + + // Iterate over all the functions of the WafRules struct + for i := 0; i < wafRulesInstance.NumMethod(); i++ { + // Get an instance of the function + methodInstance := wafRulesInstance.Method(i) + + // Call the function with no parameters (WAF rules don't require them), this returns a slice of outputs + ruleOutputs := methodInstance.Call([]reflect.Value{}) + + // Cast the first (and only for WAF rules) output to its proper type + rule := ruleOutputs[0].Interface().(tflint.Rule) + + // Apend the rule to slice + rules = append(rules, rule) + } + + return rules } diff --git a/waf/test_helpers_test.go b/waf/waf_test.go similarity index 50% rename from waf/test_helpers_test.go rename to waf/waf_test.go index 5c5b650..74313a8 100644 --- a/waf/test_helpers_test.go +++ b/waf/waf_test.go @@ -2,8 +2,11 @@ package waf_test import ( "os" + "testing" + "github.com/Azure/tflint-ruleset-avm/waf" "github.com/spf13/afero" + "github.com/stretchr/testify/assert" ) func mockFs(c string) afero.Afero { @@ -11,3 +14,8 @@ func mockFs(c string) afero.Afero { _ = afero.WriteFile(fs, "main.tf", []byte(c), os.ModePerm) return afero.Afero{Fs: fs} } + +func TestGetRules(t *testing.T) { + rules := waf.GetRules() + assert.Truef(t, len(rules) > 0, "rules should not be empty") +}