Skip to content

Commit 75bc40e

Browse files
authored
handle unknown values for rules (#60)
1 parent 0eec57e commit 75bc40e

File tree

4 files changed

+183
-24
lines changed

4 files changed

+183
-24
lines changed

internal/fim/rule_group.go

+97-18
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import (
1111
"github.com/crowdstrike/gofalcon/falcon/client/filevantage"
1212
"github.com/crowdstrike/gofalcon/falcon/models"
1313
"github.com/crowdstrike/terraform-provider-crowdstrike/internal/scopes"
14+
"github.com/crowdstrike/terraform-provider-crowdstrike/internal/utils"
1415
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
16+
"github.com/hashicorp/terraform-plugin-framework/attr"
1517
"github.com/hashicorp/terraform-plugin-framework/diag"
1618
"github.com/hashicorp/terraform-plugin-framework/path"
1719
"github.com/hashicorp/terraform-plugin-framework/resource"
@@ -56,7 +58,7 @@ type filevantageRuleGroupResourceModel struct {
5658
Name types.String `tfsdk:"name"`
5759
Type types.String `tfsdk:"type"`
5860
Description types.String `tfsdk:"description"`
59-
Rules []*fimRule `tfsdk:"rules"`
61+
Rules types.List `tfsdk:"rules"`
6062
LastUpdated types.String `tfsdk:"last_updated"`
6163
}
6264

@@ -102,6 +104,47 @@ type fimRule struct {
102104
WatchDeleteValueChanges types.Bool `tfsdk:"watch_key_value_delete_changes"`
103105
}
104106

107+
func (f fimRule) attrTypes() map[string]attr.Type {
108+
return map[string]attr.Type{
109+
"id": types.StringType,
110+
"description": types.StringType,
111+
"precedence": types.Int64Type,
112+
"path": types.StringType,
113+
"severity": types.StringType,
114+
"depth": types.StringType,
115+
"include": types.StringType,
116+
"exclude": types.StringType,
117+
"include_users": types.StringType,
118+
"include_processes": types.StringType,
119+
"exclude_users": types.StringType,
120+
"exclude_processes": types.StringType,
121+
"file_names": types.ListType{
122+
ElemType: types.StringType,
123+
},
124+
"registry_values": types.ListType{
125+
ElemType: types.StringType,
126+
},
127+
"enable_content_capture": types.BoolType,
128+
"watch_directory_delete_changes": types.BoolType,
129+
"watch_directory_create_changes": types.BoolType,
130+
"watch_directory_rename_changes": types.BoolType,
131+
"watch_directory_attribute_changes": types.BoolType,
132+
"watch_directory_permission_changes": types.BoolType,
133+
"watch_file_rename_changes": types.BoolType,
134+
"watch_file_write_changes": types.BoolType,
135+
"watch_file_create_changes": types.BoolType,
136+
"watch_file_delete_changes": types.BoolType,
137+
"watch_file_attribute_changes": types.BoolType,
138+
"watch_file_permission_changes": types.BoolType,
139+
"watch_key_create_changes": types.BoolType,
140+
"watch_key_delete_changes": types.BoolType,
141+
"watch_key_rename_changes": types.BoolType,
142+
"watch_key_permissions_changes": types.BoolType,
143+
"watch_key_value_set_changes": types.BoolType,
144+
"watch_key_value_delete_changes": types.BoolType,
145+
}
146+
}
147+
105148
// Configure adds the provider configured client to the resource.
106149
func (r *filevantageRuleGroupResource) Configure(
107150
ctx context.Context,
@@ -493,8 +536,13 @@ func (r *filevantageRuleGroupResource) Create(
493536
return
494537
}
495538

539+
rules := utils.ListTypeAs[*fimRule](ctx, plan.Rules, &resp.Diagnostics)
540+
if resp.Diagnostics.HasError() {
541+
return
542+
}
543+
496544
resp.Diagnostics.Append(
497-
r.syncRules(ctx, rgType, plan.Rules, []*fimRule{}, plan.ID.ValueString())...)
545+
r.syncRules(ctx, rgType, rules, []*fimRule{}, plan.ID.ValueString())...)
498546
if resp.Diagnostics.HasError() {
499547
return
500548
}
@@ -510,7 +558,16 @@ func (r *filevantageRuleGroupResource) Create(
510558
}
511559

512560
if len(rules) > 0 {
513-
plan.Rules = rules
561+
ruleList, diags := types.ListValueFrom(
562+
ctx,
563+
types.ObjectType{AttrTypes: fimRule{}.attrTypes()},
564+
rules,
565+
)
566+
resp.Diagnostics.Append(diags...)
567+
if resp.Diagnostics.HasError() {
568+
return
569+
}
570+
plan.Rules = ruleList
514571
}
515572

516573
resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
@@ -547,7 +604,6 @@ func (r *filevantageRuleGroupResource) Read(
547604
}
548605

549606
assignRuleGroup(res, &state)
550-
state.LastUpdated = types.StringValue(time.Now().Format(time.RFC850))
551607

552608
rules, diags := r.getRules(
553609
ctx,
@@ -560,7 +616,17 @@ func (r *filevantageRuleGroupResource) Read(
560616
}
561617

562618
if len(rules) > 0 {
563-
state.Rules = rules
619+
ruleList, diags := types.ListValueFrom(
620+
ctx,
621+
types.ObjectType{AttrTypes: fimRule{}.attrTypes()},
622+
&rules,
623+
)
624+
625+
resp.Diagnostics.Append(diags...)
626+
if resp.Diagnostics.HasError() {
627+
return
628+
}
629+
state.Rules = ruleList
564630
}
565631

566632
// Set refreshed state
@@ -615,12 +681,19 @@ func (r *filevantageRuleGroupResource) Update(
615681
assignRuleGroup(res, &plan)
616682
plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850))
617683

684+
planRules := utils.ListTypeAs[*fimRule](ctx, plan.Rules, &resp.Diagnostics)
685+
stateRules := utils.ListTypeAs[*fimRule](ctx, state.Rules, &resp.Diagnostics)
686+
687+
if resp.Diagnostics.HasError() {
688+
return
689+
}
690+
618691
resp.Diagnostics.Append(
619692
r.syncRules(
620693
ctx,
621694
plan.Type.ValueString(),
622-
plan.Rules,
623-
state.Rules,
695+
planRules,
696+
stateRules,
624697
plan.ID.ValueString(),
625698
)...)
626699
if resp.Diagnostics.HasError() {
@@ -638,7 +711,16 @@ func (r *filevantageRuleGroupResource) Update(
638711
}
639712

640713
if len(rules) > 0 {
641-
plan.Rules = rules
714+
ruleList, diags := types.ListValueFrom(
715+
ctx,
716+
types.ObjectType{AttrTypes: fimRule{}.attrTypes()},
717+
rules,
718+
)
719+
resp.Diagnostics.Append(diags...)
720+
if resp.Diagnostics.HasError() {
721+
return
722+
}
723+
plan.Rules = ruleList
642724
}
643725

644726
resp.Diagnostics.Append(
@@ -710,7 +792,13 @@ func (r *filevantageRuleGroupResource) ValidateConfig(
710792
return
711793
}
712794

713-
for i, rule := range config.Rules {
795+
rules := utils.ListTypeAs[*fimRule](ctx, config.Rules, &resp.Diagnostics)
796+
797+
if resp.Diagnostics.HasError() {
798+
return
799+
}
800+
801+
for i, rule := range rules {
714802
rPath := path.Root("rules").AtListIndex(i)
715803

716804
if rgType == LinuxFiles || rgType == MacFiles || rgType == WindowsFiles {
@@ -1060,15 +1148,6 @@ func (r *filevantageRuleGroupResource) syncRules(
10601148
}
10611149
}
10621150

1063-
// panic(
1064-
// fmt.Sprintf(
1065-
// "rulesToCreate: %v rulesToDelete %v rulesToUpdate %v",
1066-
// rulesToCreate,
1067-
// rulesToDelete,
1068-
// rulesToUpdate,
1069-
// ),
1070-
// )
1071-
10721151
diags.Append(r.createRules(ctx, ruleGroupType, rulesToCreate, ruleGroupID)...)
10731152
diags.Append(r.updateRules(ctx, ruleGroupType, rulesToUpdate, ruleGroupID)...)
10741153
diags.Append(r.deleteRules(ctx, rulesToDelete, ruleGroupID)...)

internal/fim/rule_group_test.go

+62-6
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,49 @@ import (
99
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
1010
)
1111

12-
func testAccFilevantageRuleGroup_basic(t *testing.T, rgType string) resource.TestCase {
12+
func testAccFilevantageRuleGroup_basic(
13+
t *testing.T,
14+
rgType string,
15+
paths []string,
16+
) resource.TestCase {
1317
rName := sdkacctest.RandomWithPrefix("tf-acceptance-test")
1418
rDescription := sdkacctest.RandString(20)
1519
config := acctest.ProviderConfig + fmt.Sprintf(`
20+
variable "base_rule" {
21+
type = list(object({
22+
name = string
23+
path = string
24+
}))
25+
default = [
26+
{
27+
name = "Path A"
28+
path = "%s"
29+
},
30+
{
31+
name = "Path B"
32+
path = "%s"
33+
}
34+
]
35+
}
36+
37+
1638
resource "crowdstrike_filevantage_rule_group" "test" {
1739
name = "%s"
1840
type = "%s"
1941
description = "%s"
42+
rules = [
43+
for i in var.base_rule :
44+
{
45+
description = "Monitoring ${i.name}"
46+
path = i.path
47+
severity = "High"
48+
depth = "ANY"
49+
exclude = ""
50+
}
51+
]
52+
2053
}
21-
`, rName, rgType, rDescription)
54+
`, paths[0], paths[1], rName, rgType, rDescription)
2255

2356
resourceName := "crowdstrike_filevantage_rule_group.test"
2457

@@ -47,17 +80,40 @@ resource "crowdstrike_filevantage_rule_group" "test" {
4780
}
4881

4982
func TestAccFilevantageRuleGroupResourceWindowsFiles(t *testing.T) {
50-
resource.ParallelTest(t, testAccFilevantageRuleGroup_basic(t, "WindowsFiles"))
83+
resource.ParallelTest(
84+
t,
85+
testAccFilevantageRuleGroup_basic(
86+
t,
87+
"WindowsFiles",
88+
[]string{"c:\\\\windows\\\\", "c:\\\\program files\\\\"},
89+
),
90+
)
5191
}
5292

5393
func TestAccFilevantageRuleGroupResourceWindowsRegistry(t *testing.T) {
54-
resource.ParallelTest(t, testAccFilevantageRuleGroup_basic(t, "WindowsRegistry"))
94+
resource.ParallelTest(
95+
t,
96+
testAccFilevantageRuleGroup_basic(
97+
t,
98+
"WindowsRegistry",
99+
[]string{
100+
"HKEY_LOCAL_MACHINE\\\\Software\\\\Microsoft\\\\Windows NT\\\\",
101+
"HKEY_LOCAL_MACHINE\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\",
102+
},
103+
),
104+
)
55105
}
56106

57107
func TestAccFilevantageRuleGroupResourceLinuxFiles(t *testing.T) {
58-
resource.ParallelTest(t, testAccFilevantageRuleGroup_basic(t, "LinuxFiles"))
108+
resource.ParallelTest(
109+
t,
110+
testAccFilevantageRuleGroup_basic(t, "LinuxFiles", []string{"/etc/", "/var/"}),
111+
)
59112
}
60113

61114
func TestAccFilevantageRuleGroupResourceMacFiles(t *testing.T) {
62-
resource.ParallelTest(t, testAccFilevantageRuleGroup_basic(t, "MacFiles"))
115+
resource.ParallelTest(
116+
t,
117+
testAccFilevantageRuleGroup_basic(t, "MacFiles", []string{"/etc/", "/var/"}),
118+
)
63119
}

internal/utils/schema.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package utils
2+
3+
import "github.com/hashicorp/terraform-plugin-framework/attr"
4+
5+
// IsKnown returns true if an attribute value is known and not null.
6+
func IsKnown(value attr.Value) bool {
7+
return !value.IsNull() && !value.IsUnknown()
8+
}

internal/utils/utils.go

+16
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,19 @@ func ListIDsToModify(
103103

104104
return
105105
}
106+
107+
// ListTypeAs converts a types.List into a known []T.
108+
func ListTypeAs[T any](
109+
ctx context.Context,
110+
list types.List,
111+
diags *diag.Diagnostics,
112+
) []T {
113+
if !IsKnown(list) {
114+
return nil
115+
}
116+
117+
var elements []T
118+
119+
diags.Append(list.ElementsAs(ctx, &elements, false)...)
120+
return elements
121+
}

0 commit comments

Comments
 (0)