From 90afb0f2f999c9cee2c46794db6f43e42956f84d Mon Sep 17 00:00:00 2001 From: ThomasZalewski Date: Wed, 9 Jul 2025 13:35:22 -0700 Subject: [PATCH 1/8] Add rule_json attribute to aws_wafv2_rule_group resource - Add rule_json attribute to rule group schema with JSON validation - Implement expandRuleGroupRulesJSON helper function in flex.go - Add mutual exclusivity between rule and rule_json attributes - Include comprehensive test coverage with TestAccWAFV2RuleGroup_ruleJSON - Update documentation with usage examples and argument reference - Maintain consistency with existing aws_wafv2_web_acl rule_json implementation Fixes: Support for complex nested rule statements beyond 3 levels Addresses: Feature parity with aws_wafv2_web_acl rule_json functionality --- internal/service/wafv2/flex.go | 82 +++++++++++++++++++ internal/service/wafv2/rule_group.go | 53 ++++++++++-- internal/service/wafv2/rule_group_test.go | 72 ++++++++++++++++ website/docs/r/wafv2_rule_group.html.markdown | 43 ++++++++++ 4 files changed, 244 insertions(+), 6 deletions(-) diff --git a/internal/service/wafv2/flex.go b/internal/service/wafv2/flex.go index 65a84b57a3c8..8bba692a2668 100644 --- a/internal/service/wafv2/flex.go +++ b/internal/service/wafv2/flex.go @@ -1078,6 +1078,41 @@ func expandWebACLRulesJSON(rawRules string) ([]awstypes.Rule, error) { return rules, nil } +func expandRuleGroupRulesJSON(rawRules string) ([]awstypes.Rule, error) { + // Backwards compatibility. + if rawRules == "" { + return nil, errors.New("decoding JSON: unexpected end of JSON input") + } + + var temp []any + err := tfjson.DecodeFromBytes([]byte(rawRules), &temp) + if err != nil { + return nil, fmt.Errorf("decoding JSON: %w", err) + } + + for _, v := range temp { + walkRuleGroupJSON(reflect.ValueOf(v)) + } + + out, err := tfjson.EncodeToBytes(temp) + if err != nil { + return nil, err + } + + var rules []awstypes.Rule + err = tfjson.DecodeFromBytes(out, &rules) + if err != nil { + return nil, err + } + + for i, r := range rules { + if reflect.ValueOf(r).IsZero() { + return nil, fmt.Errorf("invalid Rule Group Rule supplied at index (%d)", i) + } + } + return rules, nil +} + func walkWebACLJSON(v reflect.Value) { m := map[string][]struct { key string @@ -1125,6 +1160,53 @@ func walkWebACLJSON(v reflect.Value) { } } +func walkRuleGroupJSON(v reflect.Value) { + m := map[string][]struct { + key string + outputType any + }{ + "ByteMatchStatement": { + {key: "SearchString", outputType: []byte{}}, + }, + } + + for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + v = v.Elem() + } + + switch v.Kind() { + case reflect.Map: + for _, k := range v.MapKeys() { + if val, ok := m[k.String()]; ok { + st := v.MapIndex(k).Interface().(map[string]any) + for _, va := range val { + if st[va.key] == nil { + continue + } + str := st[va.key] + switch reflect.ValueOf(va.outputType).Kind() { + case reflect.Slice, reflect.Array: + switch reflect.ValueOf(va.outputType).Type().Elem().Kind() { + case reflect.Uint8: + base64String := itypes.Base64Encode([]byte(str.(string))) + st[va.key] = base64String + default: + } + default: + } + } + } else { + walkRuleGroupJSON(v.MapIndex(k)) + } + } + case reflect.Array, reflect.Slice: + for i := range v.Len() { + walkRuleGroupJSON(v.Index(i)) + } + default: + } +} + func expandWebACLRules(l []any) []awstypes.Rule { if len(l) == 0 || l[0] == nil { return nil diff --git a/internal/service/wafv2/rule_group.go b/internal/service/wafv2/rule_group.go index 0636374fffe0..92ec362ef4cf 100644 --- a/internal/service/wafv2/rule_group.go +++ b/internal/service/wafv2/rule_group.go @@ -18,6 +18,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" @@ -26,6 +27,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -98,9 +100,21 @@ func resourceRuleGroup() *schema.Resource { validation.StringMatch(regexache.MustCompile(`^[0-9A-Za-z_-]+$`), "must contain only alphanumeric hyphen and underscore characters"), ), }, + "rule_json": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{names.AttrRule}, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: verify.SuppressEquivalentJSONDiffs, + StateFunc: func(v any) string { + json, _ := structure.NormalizeJsonString(v) + return json + }, + }, names.AttrRule: { - Type: schema.TypeSet, - Optional: true, + Type: schema.TypeSet, + Optional: true, + ConflictsWith: []string{"rule_json"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ names.AttrAction: { @@ -155,12 +169,23 @@ func resourceRuleGroupCreate(ctx context.Context, d *schema.ResourceData, meta a input := &wafv2.CreateRuleGroupInput{ Capacity: aws.Int64(int64(d.Get("capacity").(int))), Name: aws.String(name), - Rules: expandRules(d.Get(names.AttrRule).(*schema.Set).List()), Scope: awstypes.Scope(d.Get(names.AttrScope).(string)), Tags: getTagsIn(ctx), VisibilityConfig: expandVisibilityConfig(d.Get("visibility_config").([]any)), } + if v, ok := d.GetOk(names.AttrRule); ok { + input.Rules = expandRules(v.(*schema.Set).List()) + } + + if v, ok := d.GetOk("rule_json"); ok { + rules, err := expandRuleGroupRulesJSON(v.(string)) + if err != nil { + return sdkdiag.AppendErrorf(diags, "setting rule: %s", err) + } + input.Rules = rules + } + if v, ok := d.GetOk("custom_response_body"); ok && v.(*schema.Set).Len() > 0 { input.CustomResponseBodies = expandCustomResponseBodies(v.(*schema.Set).List()) } @@ -212,8 +237,13 @@ func resourceRuleGroupRead(ctx context.Context, d *schema.ResourceData, meta any d.Set("lock_token", output.LockToken) d.Set(names.AttrName, ruleGroup.Name) d.Set(names.AttrNamePrefix, create.NamePrefixFromName(aws.ToString(ruleGroup.Name))) - if err := d.Set(names.AttrRule, flattenRules(ruleGroup.Rules)); err != nil { - return sdkdiag.AppendErrorf(diags, "setting rule: %s", err) + if _, ok := d.GetOk("rule_json"); !ok { + if err := d.Set(names.AttrRule, flattenRules(ruleGroup.Rules)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting rule: %s", err) + } + } else { + d.Set("rule_json", d.Get("rule_json")) + d.Set(names.AttrRule, nil) } if err := d.Set("visibility_config", flattenVisibilityConfig(ruleGroup.VisibilityConfig)); err != nil { return sdkdiag.AppendErrorf(diags, "setting visibility_config: %s", err) @@ -231,11 +261,22 @@ func resourceRuleGroupUpdate(ctx context.Context, d *schema.ResourceData, meta a Id: aws.String(d.Id()), LockToken: aws.String(d.Get("lock_token").(string)), Name: aws.String(d.Get(names.AttrName).(string)), - Rules: expandRules(d.Get(names.AttrRule).(*schema.Set).List()), Scope: awstypes.Scope(d.Get(names.AttrScope).(string)), VisibilityConfig: expandVisibilityConfig(d.Get("visibility_config").([]any)), } + if v, ok := d.GetOk(names.AttrRule); ok { + input.Rules = expandRules(v.(*schema.Set).List()) + } + + if v, ok := d.GetOk("rule_json"); ok { + rules, err := expandRuleGroupRulesJSON(v.(string)) + if err != nil { + return sdkdiag.AppendErrorf(diags, "expanding WAFv2 RuleGroup JSON rule (%s): %s", d.Id(), err) + } + input.Rules = rules + } + if v, ok := d.GetOk("custom_response_body"); ok && v.(*schema.Set).Len() > 0 { input.CustomResponseBodies = expandCustomResponseBodies(v.(*schema.Set).List()) } diff --git a/internal/service/wafv2/rule_group_test.go b/internal/service/wafv2/rule_group_test.go index c0de0d1bafed..1d129bf390d4 100644 --- a/internal/service/wafv2/rule_group_test.go +++ b/internal/service/wafv2/rule_group_test.go @@ -5701,3 +5701,75 @@ resource "aws_wafv2_rule_group" "test" { } `, rName) } +func TestAccWAFV2RuleGroup_ruleJSON(t *testing.T) { + ctx := acctest.Context(t) + var v awstypes.RuleGroup + ruleGroupName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheckScopeRegional(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.WAFV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckRuleGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccRuleGroupConfig_ruleJSON(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckRuleGroupExists(ctx, resourceName, &v), + acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "wafv2", regexache.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttrSet(resourceName, "rule_json"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"rule_json", names.AttrRule}, + ImportStateIdFunc: testAccRuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func testAccRuleGroupConfig_ruleJSON(rName string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 100 + name = %[1]q + scope = "REGIONAL" + + rule_json = jsonencode([{ + Name = "rule-1", + Priority = 1, + Action = { + Count = {} + }, + Statement = { + ByteMatchStatement = { + SearchString = "badbot", + FieldToMatch = { + UriPath = {} + }, + TextTransformations = [{ + Priority = 1, + Type = "NONE" + }], + PositionalConstraint = "CONTAINS" + } + }, + VisibilityConfig = { + CloudwatchMetricsEnabled = false, + MetricName = "friendly-rule-metric-name", + SampledRequestsEnabled = false, + }, + }]) + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, rName) +} diff --git a/website/docs/r/wafv2_rule_group.html.markdown b/website/docs/r/wafv2_rule_group.html.markdown index d55f35695add..cb6a82b2a1c6 100644 --- a/website/docs/r/wafv2_rule_group.html.markdown +++ b/website/docs/r/wafv2_rule_group.html.markdown @@ -312,6 +312,48 @@ resource "aws_wafv2_rule_group" "example" { } ``` +### Using rule_json + +```terraform +resource "aws_wafv2_rule_group" "example" { + name = "example-rule-group" + scope = "REGIONAL" + capacity = 100 + + rule_json = jsonencode([{ + Name = "rule-1" + Priority = 1 + Action = { + Count = {} + } + Statement = { + ByteMatchStatement = { + SearchString = "badbot" + FieldToMatch = { + UriPath = {} + } + TextTransformations = [{ + Priority = 1 + Type = "NONE" + }] + PositionalConstraint = "CONTAINS" + } + } + VisibilityConfig = { + CloudwatchMetricsEnabled = false + MetricName = "friendly-rule-metric-name" + SampledRequestsEnabled = false + } + }]) + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +``` + ## Argument Reference This resource supports the following arguments: @@ -323,6 +365,7 @@ This resource supports the following arguments: * `name` - (Required, Forces new resource) A friendly name of the rule group. * `name_prefix` - (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `name`. * `rule` - (Optional) The rule blocks used to identify the web requests that you want to `allow`, `block`, or `count`. See [Rules](#rules) below for details. +* `rule_json` - (Optional) Raw JSON string to allow more than three nested statements. Conflicts with `rule` attribute. This is for advanced use cases where more than 3 levels of nested statements are required. **There is no drift detection at this time**. If you use this attribute instead of `rule`, you will be foregoing drift detection. Additionally, importing an existing rule group into a configuration with `rule_json` set will result in a one time in-place update as the remote rule configuration is initially written to the `rule` attribute. See the AWS [documentation](https://docs.aws.amazon.com/waf/latest/APIReference/API_CreateRuleGroup.html) for the JSON structure. * `scope` - (Required, Forces new resource) Specifies whether this is for an AWS CloudFront distribution or for a regional application. Valid values are `CLOUDFRONT` or `REGIONAL`. To work with CloudFront, you must also specify the region `us-east-1` (N. Virginia) on the AWS provider. * `tags` - (Optional) An array of key:value pairs to associate with the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. * `visibility_config` - (Required) Defines and enables Amazon CloudWatch metrics and web request sample collection. See [Visibility Configuration](#visibility-configuration) below for details. From 67b75db6284a07b731e97863405f2ab300649d85 Mon Sep 17 00:00:00 2001 From: ThomasZalewski Date: Wed, 16 Jul 2025 00:50:53 -0700 Subject: [PATCH 2/8] formatting linter changes --- internal/service/wafv2/rule_group_test.go | 24 +++++++++---------- website/docs/r/wafv2_rule_group.html.markdown | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/service/wafv2/rule_group_test.go b/internal/service/wafv2/rule_group_test.go index 1d129bf390d4..dbcb1dc34a85 100644 --- a/internal/service/wafv2/rule_group_test.go +++ b/internal/service/wafv2/rule_group_test.go @@ -5740,29 +5740,29 @@ resource "aws_wafv2_rule_group" "test" { scope = "REGIONAL" rule_json = jsonencode([{ - Name = "rule-1", - Priority = 1, + Name = "rule-1" + Priority = 1 Action = { Count = {} - }, + } Statement = { ByteMatchStatement = { - SearchString = "badbot", + SearchString = "badbot" FieldToMatch = { UriPath = {} - }, + } TextTransformations = [{ - Priority = 1, + Priority = 1 Type = "NONE" - }], + }] PositionalConstraint = "CONTAINS" } - }, + } VisibilityConfig = { - CloudwatchMetricsEnabled = false, - MetricName = "friendly-rule-metric-name", - SampledRequestsEnabled = false, - }, + CloudwatchMetricsEnabled = false + MetricName = "friendly-rule-metric-name" + SampledRequestsEnabled = false + } }]) visibility_config { diff --git a/website/docs/r/wafv2_rule_group.html.markdown b/website/docs/r/wafv2_rule_group.html.markdown index cb6a82b2a1c6..3577dde09bbb 100644 --- a/website/docs/r/wafv2_rule_group.html.markdown +++ b/website/docs/r/wafv2_rule_group.html.markdown @@ -328,7 +328,7 @@ resource "aws_wafv2_rule_group" "example" { } Statement = { ByteMatchStatement = { - SearchString = "badbot" + SearchString = "badbot" FieldToMatch = { UriPath = {} } From 49f971133a551857c48f2623d3933d1628ae9889 Mon Sep 17 00:00:00 2001 From: ThomasZalewski Date: Wed, 16 Jul 2025 01:27:43 -0700 Subject: [PATCH 3/8] linting fix --- internal/service/wafv2/rule_group_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/wafv2/rule_group_test.go b/internal/service/wafv2/rule_group_test.go index dbcb1dc34a85..7ce035875735 100644 --- a/internal/service/wafv2/rule_group_test.go +++ b/internal/service/wafv2/rule_group_test.go @@ -5747,7 +5747,7 @@ resource "aws_wafv2_rule_group" "test" { } Statement = { ByteMatchStatement = { - SearchString = "badbot" + SearchString = "badbot" FieldToMatch = { UriPath = {} } From 5722d8e530f1b932fea0b058dab71c3e363c65d7 Mon Sep 17 00:00:00 2001 From: ThomasZalewski Date: Tue, 22 Jul 2025 10:29:17 -0700 Subject: [PATCH 4/8] changelog --- .changelog/433245.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/433245.txt diff --git a/.changelog/433245.txt b/.changelog/433245.txt new file mode 100644 index 000000000000..a0f27371acc3 --- /dev/null +++ b/.changelog/433245.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/wafv2_rule_group: Add `rules_json` attribute. +``` \ No newline at end of file From 173e476604d5e14385093124c8a0c73672f0c7c1 Mon Sep 17 00:00:00 2001 From: ThomasZalewski Date: Tue, 22 Jul 2025 12:09:34 -0700 Subject: [PATCH 5/8] Update .changelog/433245.txt Co-authored-by: Kit Ewbank --- .changelog/433245.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/433245.txt b/.changelog/433245.txt index a0f27371acc3..6a6caa32b05f 100644 --- a/.changelog/433245.txt +++ b/.changelog/433245.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/wafv2_rule_group: Add `rules_json` attribute. +resource/aws_wafv2_rule_group: Add `rules_json` argument ``` \ No newline at end of file From 59167629bc0ba3c86f3dad33d54ccdd561c3398a Mon Sep 17 00:00:00 2001 From: ThomasZalewski Date: Tue, 22 Jul 2025 13:58:59 -0700 Subject: [PATCH 6/8] rules->rule --- internal/service/wafv2/flex.go | 8 ++++---- internal/service/wafv2/rule_group.go | 12 ++++++------ internal/service/wafv2/rule_group_test.go | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/service/wafv2/flex.go b/internal/service/wafv2/flex.go index 8bba692a2668..1494e46215ea 100644 --- a/internal/service/wafv2/flex.go +++ b/internal/service/wafv2/flex.go @@ -1091,7 +1091,7 @@ func expandRuleGroupRulesJSON(rawRules string) ([]awstypes.Rule, error) { } for _, v := range temp { - walkRuleGroupJSON(reflect.ValueOf(v)) + walkRulesGroupJSON(reflect.ValueOf(v)) } out, err := tfjson.EncodeToBytes(temp) @@ -1160,7 +1160,7 @@ func walkWebACLJSON(v reflect.Value) { } } -func walkRuleGroupJSON(v reflect.Value) { +func walkRulesGroupJSON(v reflect.Value) { m := map[string][]struct { key string outputType any @@ -1196,12 +1196,12 @@ func walkRuleGroupJSON(v reflect.Value) { } } } else { - walkRuleGroupJSON(v.MapIndex(k)) + walkRulesGroupJSON(v.MapIndex(k)) } } case reflect.Array, reflect.Slice: for i := range v.Len() { - walkRuleGroupJSON(v.Index(i)) + walkRulesGroupJSON(v.Index(i)) } default: } diff --git a/internal/service/wafv2/rule_group.go b/internal/service/wafv2/rule_group.go index 92ec362ef4cf..87b98dbd3c5c 100644 --- a/internal/service/wafv2/rule_group.go +++ b/internal/service/wafv2/rule_group.go @@ -100,7 +100,7 @@ func resourceRuleGroup() *schema.Resource { validation.StringMatch(regexache.MustCompile(`^[0-9A-Za-z_-]+$`), "must contain only alphanumeric hyphen and underscore characters"), ), }, - "rule_json": { + "rules_json": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{names.AttrRule}, @@ -114,7 +114,7 @@ func resourceRuleGroup() *schema.Resource { names.AttrRule: { Type: schema.TypeSet, Optional: true, - ConflictsWith: []string{"rule_json"}, + ConflictsWith: []string{"rules_json"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ names.AttrAction: { @@ -178,7 +178,7 @@ func resourceRuleGroupCreate(ctx context.Context, d *schema.ResourceData, meta a input.Rules = expandRules(v.(*schema.Set).List()) } - if v, ok := d.GetOk("rule_json"); ok { + if v, ok := d.GetOk("rules_json"); ok { rules, err := expandRuleGroupRulesJSON(v.(string)) if err != nil { return sdkdiag.AppendErrorf(diags, "setting rule: %s", err) @@ -237,12 +237,12 @@ func resourceRuleGroupRead(ctx context.Context, d *schema.ResourceData, meta any d.Set("lock_token", output.LockToken) d.Set(names.AttrName, ruleGroup.Name) d.Set(names.AttrNamePrefix, create.NamePrefixFromName(aws.ToString(ruleGroup.Name))) - if _, ok := d.GetOk("rule_json"); !ok { + if _, ok := d.GetOk("rules_json"); !ok { if err := d.Set(names.AttrRule, flattenRules(ruleGroup.Rules)); err != nil { return sdkdiag.AppendErrorf(diags, "setting rule: %s", err) } } else { - d.Set("rule_json", d.Get("rule_json")) + d.Set("rules_json", d.Get("rules_json")) d.Set(names.AttrRule, nil) } if err := d.Set("visibility_config", flattenVisibilityConfig(ruleGroup.VisibilityConfig)); err != nil { @@ -269,7 +269,7 @@ func resourceRuleGroupUpdate(ctx context.Context, d *schema.ResourceData, meta a input.Rules = expandRules(v.(*schema.Set).List()) } - if v, ok := d.GetOk("rule_json"); ok { + if v, ok := d.GetOk("rules_json"); ok { rules, err := expandRuleGroupRulesJSON(v.(string)) if err != nil { return sdkdiag.AppendErrorf(diags, "expanding WAFv2 RuleGroup JSON rule (%s): %s", d.Id(), err) diff --git a/internal/service/wafv2/rule_group_test.go b/internal/service/wafv2/rule_group_test.go index 7ce035875735..2bd38eeb9de3 100644 --- a/internal/service/wafv2/rule_group_test.go +++ b/internal/service/wafv2/rule_group_test.go @@ -5718,14 +5718,14 @@ func TestAccWAFV2RuleGroup_ruleJSON(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckRuleGroupExists(ctx, resourceName, &v), acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "wafv2", regexache.MustCompile(`regional/rulegroup/.+$`)), - resource.TestCheckResourceAttrSet(resourceName, "rule_json"), + resource.TestCheckResourceAttrSet(resourceName, "rules_json"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"rule_json", names.AttrRule}, + ImportStateVerifyIgnore: []string{"rules_json", names.AttrRule}, ImportStateIdFunc: testAccRuleGroupImportStateIdFunc(resourceName), }, }, @@ -5739,7 +5739,7 @@ resource "aws_wafv2_rule_group" "test" { name = %[1]q scope = "REGIONAL" - rule_json = jsonencode([{ + rules_json = jsonencode([{ Name = "rule-1" Priority = 1 Action = { From 9fca0c47eebcedf519fae3bf5249d64f69a9af5c Mon Sep 17 00:00:00 2001 From: ThomasZalewski Date: Tue, 22 Jul 2025 14:38:15 -0700 Subject: [PATCH 7/8] rename test --- internal/service/wafv2/rule_group_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/wafv2/rule_group_test.go b/internal/service/wafv2/rule_group_test.go index 2bd38eeb9de3..046bafde7233 100644 --- a/internal/service/wafv2/rule_group_test.go +++ b/internal/service/wafv2/rule_group_test.go @@ -5701,7 +5701,7 @@ resource "aws_wafv2_rule_group" "test" { } `, rName) } -func TestAccWAFV2RuleGroup_ruleJSON(t *testing.T) { +func TestAccWAFV2RuleGroup_rulesJson(t *testing.T) { ctx := acctest.Context(t) var v awstypes.RuleGroup ruleGroupName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -5714,7 +5714,7 @@ func TestAccWAFV2RuleGroup_ruleJSON(t *testing.T) { CheckDestroy: testAccCheckRuleGroupDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRuleGroupConfig_ruleJSON(ruleGroupName), + Config: testAccRuleGroupConfig_rulesJson(ruleGroupName), Check: resource.ComposeTestCheckFunc( testAccCheckRuleGroupExists(ctx, resourceName, &v), acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "wafv2", regexache.MustCompile(`regional/rulegroup/.+$`)), @@ -5732,7 +5732,7 @@ func TestAccWAFV2RuleGroup_ruleJSON(t *testing.T) { }) } -func testAccRuleGroupConfig_ruleJSON(rName string) string { +func testAccRuleGroupConfig_rulesJson(rName string) string { return fmt.Sprintf(` resource "aws_wafv2_rule_group" "test" { capacity = 100 From c9b1704ec62a9ce8b6e0410b57efeeed656ed03e Mon Sep 17 00:00:00 2001 From: ThomasZalewski Date: Tue, 22 Jul 2025 15:59:07 -0700 Subject: [PATCH 8/8] caps.md --- internal/service/wafv2/rule_group_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/wafv2/rule_group_test.go b/internal/service/wafv2/rule_group_test.go index 046bafde7233..eefb718991d3 100644 --- a/internal/service/wafv2/rule_group_test.go +++ b/internal/service/wafv2/rule_group_test.go @@ -5701,7 +5701,7 @@ resource "aws_wafv2_rule_group" "test" { } `, rName) } -func TestAccWAFV2RuleGroup_rulesJson(t *testing.T) { +func TestAccWAFV2RuleGroup_rulesJSON(t *testing.T) { ctx := acctest.Context(t) var v awstypes.RuleGroup ruleGroupName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -5714,7 +5714,7 @@ func TestAccWAFV2RuleGroup_rulesJson(t *testing.T) { CheckDestroy: testAccCheckRuleGroupDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRuleGroupConfig_rulesJson(ruleGroupName), + Config: testAccRuleGroupConfig_rulesJSON(ruleGroupName), Check: resource.ComposeTestCheckFunc( testAccCheckRuleGroupExists(ctx, resourceName, &v), acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "wafv2", regexache.MustCompile(`regional/rulegroup/.+$`)), @@ -5732,7 +5732,7 @@ func TestAccWAFV2RuleGroup_rulesJson(t *testing.T) { }) } -func testAccRuleGroupConfig_rulesJson(rName string) string { +func testAccRuleGroupConfig_rulesJSON(rName string) string { return fmt.Sprintf(` resource "aws_wafv2_rule_group" "test" { capacity = 100