diff --git a/sysdig/resource_sysdig_secure_custom_policy.go b/sysdig/resource_sysdig_secure_custom_policy.go index 44beeae5..1f89f8a7 100644 --- a/sysdig/resource_sysdig_secure_custom_policy.go +++ b/sysdig/resource_sysdig_secure_custom_policy.go @@ -123,14 +123,63 @@ func customPolicyToResourceData(policy *v2.Policy, d *schema.ResourceData) { _ = d.Set("type", "falco") } - rules := []map[string]interface{}{} + rules := getPolicyRulesFromResourceData(d) + newRules := []map[string]interface{}{} for _, rule := range policy.Rules { - rules = append(rules, map[string]interface{}{ + newRules = append(newRules, map[string]interface{}{ "name": rule.Name, "enabled": rule.Enabled, }) } - _ = d.Set("rules", rules) + currentRules := []map[string]interface{}{} + for _, rule := range rules { + currentRules = append(currentRules, map[string]interface{}{ + "name": rule.Name, + "enabled": rule.Enabled, + }) + } + + if !arePolicyRulesEquivalent(currentRules, newRules) { + _ = d.Set("rules", newRules) + } else { + _ = d.Set("rules", currentRules) + } +} + +func getPolicyRulesFromResourceData(d *schema.ResourceData) []*v2.PolicyRule { + rules := d.Get("rules").([]interface{}) + policyRules := make([]*v2.PolicyRule, len(rules)) + + for i, rule := range rules { + policyRules[i] = &v2.PolicyRule{ + Name: rule.(map[string]interface{})["name"].(string), + Enabled: rule.(map[string]interface{})["enabled"].(bool), + } + } + + return policyRules +} + +func arePolicyRulesEquivalent(newRules []map[string]interface{}, currentRules []map[string]interface{}) bool { + if len(newRules) != len(currentRules) { + return false + } + currentRulesMap := make(map[string]bool, 0) + for _, rule := range currentRules { + ruleName := rule["name"].(string) + enabled := rule["enabled"].(bool) + currentRulesMap[ruleName] = enabled + } + for _, rule := range newRules { + newRuleEnabled := rule["enabled"].(bool) + newRulesName := rule["name"].(string) + if enabled, ok := currentRulesMap[newRulesName]; !ok { + return false + } else if enabled != newRuleEnabled { + return false + } + } + return true } func resourceSysdigCustomPolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diff --git a/sysdig/resource_sysdig_secure_custom_policy_test.go b/sysdig/resource_sysdig_secure_custom_policy_test.go index 16cde99d..37e70020 100644 --- a/sysdig/resource_sysdig_secure_custom_policy_test.go +++ b/sysdig/resource_sysdig_secure_custom_policy_test.go @@ -15,7 +15,7 @@ import ( func TestAccCustomPolicy(t *testing.T) { rText := func() string { return acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) } - + policy1 := rText() resource.ParallelTest(t, resource.TestCase{ PreCheck: preCheckAnyEnv(t, SysdigSecureApiTokenEnv), ProviderFactories: map[string]func() (*schema.Provider, error){ @@ -25,13 +25,16 @@ func TestAccCustomPolicy(t *testing.T) { }, Steps: []resource.TestStep{ { - Config: customPolicyWithName(rText()), + Config: customPolicyWithName(policy1), }, { ResourceName: "sysdig_secure_custom_policy.sample", ImportState: true, ImportStateVerify: true, }, + { + Config: customPolicyWithRulesOrderChange(policy1), + }, { Config: customPolicyWithoutActions(rText()), }, @@ -75,6 +78,10 @@ resource "sysdig_secure_custom_policy" "sample" { scope = "container.id != \"\"" runbook = "https://sysdig.com" + rules { + name = "Write below etc" + enabled = true + } rules { name = sysdig_secure_rule_falco.terminal_shell.name enabled = true @@ -94,6 +101,41 @@ resource "sysdig_secure_custom_policy" "sample" { `, secureNotificationChannelEmailWithName(name), ruleFalcoTerminalShell(name), name, name) } +func customPolicyWithRulesOrderChange(name string) string { + return fmt.Sprintf(` +%s +%s +resource "sysdig_secure_custom_policy" "sample" { + name = "TERRAFORM TEST 1 %s" + description = "TERRAFORM TEST %s" + enabled = true + severity = 4 + scope = "container.id != \"\"" + runbook = "https://sysdig.com" + + rules { + name = sysdig_secure_rule_falco.terminal_shell.name + enabled = true + } + rules { + name = "Write below etc" + enabled = true + } + + actions { + container = "stop" + capture { + seconds_before_event = 5 + seconds_after_event = 10 + name = "testcapture" + } + } + + notification_channels = [sysdig_secure_notification_channel_email.sample_email.id] +} +`, secureNotificationChannelEmailWithName(name), ruleFalcoTerminalShell(name), name, name) +} + func customPolicyWithoutActions(name string) string { return fmt.Sprintf(` %s