From f6e6a7890a350cdc2ec1857af88fe1227ecc0584 Mon Sep 17 00:00:00 2001 From: Konstantin Nechaev Date: Wed, 4 Dec 2024 14:13:41 +0200 Subject: [PATCH] vpatch --- wallarm/resource_rule_disable_attack_type.go | 2 +- wallarm/resource_rule_vpatch.go | 184 ++++++++----------- 2 files changed, 80 insertions(+), 106 deletions(-) diff --git a/wallarm/resource_rule_disable_attack_type.go b/wallarm/resource_rule_disable_attack_type.go index 2de1c90..4b898da 100644 --- a/wallarm/resource_rule_disable_attack_type.go +++ b/wallarm/resource_rule_disable_attack_type.go @@ -62,7 +62,7 @@ func resourceWallarmDisableAttackType() *schema.Resource { "attack_type": { Type: schema.TypeString, Required: true, - ValidateFunc: validation.StringInSlice([]string{"sqli", "xss", "rce", "ptrav", "crlf", "nosqli", "xxe", "ldapi", "scanner", "ssti", "ssi", "mail_injection", "vpatch"}, false), + ValidateFunc: validation.StringInSlice([]string{"sqli", "xss", "rce", "ptrav", "crlf", "nosqli", "xxe", "ldapi", "scanner", "ssti", "ssi", "mail_injection"}, false), ForceNew: true, }, diff --git a/wallarm/resource_rule_vpatch.go b/wallarm/resource_rule_vpatch.go index 7770046..a67a79d 100644 --- a/wallarm/resource_rule_vpatch.go +++ b/wallarm/resource_rule_vpatch.go @@ -31,9 +31,8 @@ func resourceWallarmVpatch() *schema.Resource { Schema: map[string]*schema.Schema{ "rule_id": { - Type: schema.TypeList, + Type: schema.TypeInt, Computed: true, - Elem: &schema.Schema{Type: schema.TypeInt}, }, "action_id": { @@ -67,12 +66,11 @@ func resourceWallarmVpatch() *schema.Resource { }, "attack_type": { - Type: schema.TypeList, + Type: schema.TypeString, Required: true, ForceNew: true, Description: `Possible values: "any", "sqli", "rce", "crlf", "nosqli", "ptrav", "xxe", "ptrav", "xss", "scanner", "redir", "ldapi"`, - Elem: &schema.Schema{Type: schema.TypeString}, }, "action": { @@ -198,11 +196,7 @@ func resourceWallarmVpatchCreate(d *schema.ResourceData, m interface{}) error { client := m.(wallarm.API) clientID := retrieveClientID(d, client) comment := d.Get("comment").(string) - attackType := d.Get("attack_type").([]interface{}) - var attacks []string - for _, attack := range attackType { - attacks = append(attacks, attack.(string)) - } + attackType := d.Get("attack_type").(string) ps := d.Get("point").([]interface{}) if err := d.Set("point", ps); err != nil { @@ -220,50 +214,32 @@ func resourceWallarmVpatchCreate(d *schema.ResourceData, m interface{}) error { return err } - ruleIDs := make([]int, len(attacks)) - attackTypes := make([]string, len(attacks)) - for i, attack := range attacks { - vp := &wallarm.ActionCreate{ - Type: "vpatch", - AttackType: attack, - Clientid: clientID, - Action: &action, - Point: points, - Validated: false, - Comment: comment, - VariativityDisabled: true, - } - - actionResp, err := client.HintCreate(vp) - if err != nil { - return err - } - - if err := d.Set("action_id", actionResp.Body.ActionID); err != nil { - return err - } - - if err := d.Set("rule_type", actionResp.Body.Type); err != nil { - return err - } - - ruleIDs[i] = actionResp.Body.ID - attackTypes[i] = actionResp.Body.AttackType - - d.SetId(actionResp.Body.Type) + vp := &wallarm.ActionCreate{ + Type: "vpatch", + AttackType: attackType, + Clientid: clientID, + Action: &action, + Point: points, + Validated: false, + Comment: comment, + VariativityDisabled: true, } - if err := d.Set("rule_id", ruleIDs); err != nil { - return err - } - - if err := d.Set("attack_type", attackTypes); err != nil { + actionResp, err := client.HintCreate(vp) + if err != nil { return err } + d.Set("rule_id", actionResp.Body.ID) + d.Set("action_id", actionResp.Body.ActionID) + d.Set("rule_type", actionResp.Body.Type) + d.Set("attack_type", actionResp.Body.AttackType) d.Set("client_id", clientID) - return nil + resID := fmt.Sprintf("%d/%d/%d", clientID, actionResp.Body.ActionID, actionResp.Body.ID) + d.SetId(resID) + + return resourceWallarmVpatchRead(d, m) } func resourceWallarmVpatchRead(d *schema.ResourceData, m interface{}) error { @@ -272,31 +248,7 @@ func resourceWallarmVpatchRead(d *schema.ResourceData, m interface{}) error { actionID := d.Get("action_id").(int) ruleID := d.Get("rule_id").(int) - var attackType []interface{} - if v, ok := d.GetOk("attack_type"); ok { - attackType = v.([]interface{}) - } else { - return nil - } - var attacks []string - for _, attack := range attackType { - attacks = append(attacks, attack.(string)) - } - - var ruleIDInterface []interface{} - if v, ok := d.GetOk("rule_id"); ok { - ruleIDInterface = v.([]interface{}) - } else { - return nil - } - ruleIDs := expandInterfaceToIntList(ruleIDInterface) - - var ps []interface{} - if v, ok := d.GetOk("point"); ok { - ps = v.([]interface{}) - } else { - return nil - } + ps := d.Get("point").([]interface{}) var points []interface{} for _, point := range ps { p := point.([]interface{}) @@ -309,6 +261,17 @@ func resourceWallarmVpatchRead(d *schema.ResourceData, m interface{}) error { return err } + var actsSlice []interface{} + for _, a := range action { + acts, err := actionDetailsToMap(a) + if err != nil { + return err + } + actsSlice = append(actsSlice, acts) + } + + actionsSet := schema.NewSet(hashResponseActionDetails, actsSlice) + hint := &wallarm.HintRead{ Limit: 1000, Offset: 0, @@ -317,6 +280,7 @@ func resourceWallarmVpatchRead(d *schema.ResourceData, m interface{}) error { Filter: &wallarm.HintFilter{ Clientid: []int{clientID}, ID: []int{ruleID}, + Type: []string{"vpatch"}, }, } actionHints, err := client.HintRead(hint) @@ -324,29 +288,22 @@ func resourceWallarmVpatchRead(d *schema.ResourceData, m interface{}) error { return err } - // This is mandatory to fill in the default values in order to compare structs deeply. + // This is mandatory to fill in the default values in order to compare them deeply. // Assign new values to the old struct slice. fillInDefaultValues(&action) - var expectedRules []wallarm.ActionBody - for _, attack := range attacks { - r := wallarm.ActionBody{ - ActionID: actionID, - Type: "vpatch", - Point: points, - AttackType: attack, - } - expectedRules = append(expectedRules, r) + expectedRule := wallarm.ActionBody{ + ActionID: actionID, + Type: "vpatch", + Point: points, } var notFoundRules []int - var updatedRuleIDs []int -out: + var updatedRuleID int for _, rule := range *actionHints.Body { - // Check straight right by ID. The specific rule should be found. - if wallarm.Contains(ruleIDs, rule.ID) { - updatedRuleIDs = append(updatedRuleIDs, rule.ID) + if ruleID == rule.ID { + updatedRuleID = rule.ID continue } @@ -355,30 +312,35 @@ out: alignedPoints := alignPointScheme(rule.Point) actualRule := &wallarm.ActionBody{ - ActionID: rule.ActionID, - Type: rule.Type, - Point: alignedPoints, - AttackType: rule.AttackType, + ActionID: rule.ActionID, + Type: rule.Type, + Point: alignedPoints, } - for _, expectedRule := range expectedRules { - if cmp.Equal(expectedRule, *actualRule) && equalWithoutOrder(action, rule.Action) { - updatedRuleIDs = append(updatedRuleIDs, rule.ID) - continue out - } + if cmp.Equal(expectedRule, *actualRule) && equalWithoutOrder(action, rule.Action) { + updatedRuleID = rule.ID + continue } notFoundRules = append(notFoundRules, rule.ID) } - if err := d.Set("rule_id", updatedRuleIDs); err != nil { + if err := d.Set("rule_id", updatedRuleID); err != nil { return err } d.Set("client_id", clientID) - if len(updatedRuleIDs) == 0 { - log.Printf("[WARN] these rule IDs: %v have been found under the action ID: %d. But they aren't in the Terraform Plan.", notFoundRules, actionID) + if actionsSet.Len() != 0 { + if err := d.Set("action", &actionsSet); err != nil { + return err + } + } else { + log.Printf("[WARN] action was empty so it either doesn't exist or it is a default branch which has no conditions. Actions: %v", &actionsSet) + } + + if updatedRuleID == 0 { + log.Printf("[WARN] these rule IDs: %v have been found under the action ID: %d. But it isn't in the Terraform Plan.", notFoundRules, actionID) d.SetId("") } @@ -388,16 +350,28 @@ out: func resourceWallarmVpatchDelete(d *schema.ResourceData, m interface{}) error { client := m.(wallarm.API) clientID := retrieveClientID(d, client) + actionID := d.Get("action_id").(int) - var ruleIDInterface []interface{} - if v, ok := d.GetOk("rule_id"); ok { - ruleIDInterface = v.([]interface{}) - } else { - return nil + rule := &wallarm.ActionRead{ + Filter: &wallarm.ActionFilter{ + HintType: []string{"vpatch"}, + Clientid: []int{clientID}, + ID: []int{actionID}, + }, + Limit: 1000, + Offset: 0, + } + respRules, err := client.RuleRead(rule) + if err != nil { + return err } - ruleIDs := expandInterfaceToIntList(ruleIDInterface) - for _, ruleID := range ruleIDs { + if len(respRules.Body) == 1 && respRules.Body[0].Hints == 1 && respRules.Body[0].GroupedHintsCount == 1 { + if err := client.RuleDelete(actionID); err != nil { + return err + } + } else { + ruleID := d.Get("rule_id").(int) h := &wallarm.HintDelete{ Filter: &wallarm.HintDeleteFilter{ Clientid: []int{clientID},