Skip to content

Commit 828ef7a

Browse files
Copilotnick-benoit
andcommitted
Refactor security detection rule implementation based on code review feedback
Co-authored-by: nick-benoit <[email protected]>
1 parent b31762b commit 828ef7a

File tree

5 files changed

+433
-501
lines changed

5 files changed

+433
-501
lines changed

internal/kibana/security_detection_rule/create.go

Lines changed: 19 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import (
44
"context"
55
"fmt"
66

7-
"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
8-
"github.com/hashicorp/terraform-plugin-framework/diag"
7+
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
98
"github.com/hashicorp/terraform-plugin-framework/resource"
9+
"github.com/hashicorp/terraform-plugin-framework/types"
1010
)
1111

1212
func (r *securityDetectionRuleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
@@ -28,7 +28,7 @@ func (r *securityDetectionRuleResource) Create(ctx context.Context, req resource
2828
}
2929

3030
// Build the create request
31-
createProps, diags := r.buildCreateProps(ctx, data)
31+
createProps, diags := data.toCreateProps(ctx)
3232
resp.Diagnostics.Append(diags...)
3333
if resp.Diagnostics.HasError() {
3434
return
@@ -52,187 +52,32 @@ func (r *securityDetectionRuleResource) Create(ctx context.Context, req resource
5252
return
5353
}
5454

55-
// Parse the response
55+
// Parse the response to get the ID, then use Read logic for consistency
5656
ruleResponse, diags := r.parseRuleResponse(ctx, response.JSON200)
5757
resp.Diagnostics.Append(diags...)
5858
if resp.Diagnostics.HasError() {
5959
return
6060
}
6161

62-
// Update the data with response values
63-
diags = r.updateDataFromRule(ctx, &data, ruleResponse)
64-
resp.Diagnostics.Append(diags...)
65-
if resp.Diagnostics.HasError() {
66-
return
67-
}
68-
69-
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
70-
}
71-
72-
func (r *securityDetectionRuleResource) buildCreateProps(ctx context.Context, data SecurityDetectionRuleData) (kbapi.SecurityDetectionsAPIRuleCreateProps, diag.Diagnostics) {
73-
var diags diag.Diagnostics
74-
var createProps kbapi.SecurityDetectionsAPIRuleCreateProps
75-
76-
queryRuleQuery := kbapi.SecurityDetectionsAPIRuleQuery(data.Query.ValueString())
77-
// Convert data to QueryRuleCreateProps since we're only supporting query rules initially
78-
queryRule := kbapi.SecurityDetectionsAPIQueryRuleCreateProps{
79-
Name: kbapi.SecurityDetectionsAPIRuleName(data.Name.ValueString()),
80-
Description: kbapi.SecurityDetectionsAPIRuleDescription(data.Description.ValueString()),
81-
Type: kbapi.SecurityDetectionsAPIQueryRuleCreatePropsType("query"),
82-
Query: &queryRuleQuery,
83-
RiskScore: kbapi.SecurityDetectionsAPIRiskScore(data.RiskScore.ValueInt64()),
84-
Severity: kbapi.SecurityDetectionsAPISeverity(data.Severity.ValueString()),
85-
}
86-
87-
// Set optional rule_id if provided
88-
if !data.RuleId.IsNull() && !data.RuleId.IsUnknown() {
89-
ruleId := kbapi.SecurityDetectionsAPIRuleSignatureId(data.RuleId.ValueString())
90-
queryRule.RuleId = &ruleId
91-
}
92-
93-
// Set enabled status
94-
if !data.Enabled.IsNull() {
95-
enabled := kbapi.SecurityDetectionsAPIIsRuleEnabled(data.Enabled.ValueBool())
96-
queryRule.Enabled = &enabled
97-
}
98-
99-
// Set query language
100-
if !data.Language.IsNull() {
101-
var language kbapi.SecurityDetectionsAPIKqlQueryLanguage
102-
switch data.Language.ValueString() {
103-
case "kuery":
104-
language = "kuery"
105-
case "lucene":
106-
language = "lucene"
107-
default:
108-
language = "kuery"
109-
}
110-
queryRule.Language = &language
111-
}
112-
113-
// Set time range
114-
if !data.From.IsNull() {
115-
from := kbapi.SecurityDetectionsAPIRuleIntervalFrom(data.From.ValueString())
116-
queryRule.From = &from
117-
}
118-
119-
if !data.To.IsNull() {
120-
to := kbapi.SecurityDetectionsAPIRuleIntervalTo(data.To.ValueString())
121-
queryRule.To = &to
122-
}
123-
124-
// Set interval
125-
if !data.Interval.IsNull() {
126-
interval := kbapi.SecurityDetectionsAPIRuleInterval(data.Interval.ValueString())
127-
queryRule.Interval = &interval
128-
}
129-
130-
// Set index patterns
131-
if !data.Index.IsNull() && !data.Index.IsUnknown() {
132-
var indexList []string
133-
diags.Append(data.Index.ElementsAs(ctx, &indexList, false)...)
134-
if !diags.HasError() && len(indexList) > 0 {
135-
indexPatterns := make(kbapi.SecurityDetectionsAPIIndexPatternArray, len(indexList))
136-
//nolint:staticcheck // Type conversion required, can't use copy()
137-
for i, idx := range indexList {
138-
indexPatterns[i] = idx
139-
}
140-
queryRule.Index = &indexPatterns
141-
}
142-
}
143-
144-
// Set author
145-
if !data.Author.IsNull() && !data.Author.IsUnknown() {
146-
var authorList []string
147-
diags.Append(data.Author.ElementsAs(ctx, &authorList, false)...)
148-
if !diags.HasError() && len(authorList) > 0 {
149-
authorArray := make(kbapi.SecurityDetectionsAPIRuleAuthorArray, len(authorList))
150-
//nolint:staticcheck // Type conversion required, can't use copy()
151-
for i, author := range authorList {
152-
authorArray[i] = author
153-
}
154-
queryRule.Author = &authorArray
155-
}
156-
}
157-
158-
// Set tags
159-
if !data.Tags.IsNull() && !data.Tags.IsUnknown() {
160-
var tagsList []string
161-
diags.Append(data.Tags.ElementsAs(ctx, &tagsList, false)...)
162-
if !diags.HasError() && len(tagsList) > 0 {
163-
tagsArray := make(kbapi.SecurityDetectionsAPIRuleTagArray, len(tagsList))
164-
//nolint:staticcheck // Type conversion required, can't use copy()
165-
for i, tag := range tagsList {
166-
tagsArray[i] = tag
167-
}
168-
queryRule.Tags = &tagsArray
169-
}
170-
}
171-
172-
// Set false positives
173-
if !data.FalsePositives.IsNull() && !data.FalsePositives.IsUnknown() {
174-
var fpList []string
175-
diags.Append(data.FalsePositives.ElementsAs(ctx, &fpList, false)...)
176-
if !diags.HasError() && len(fpList) > 0 {
177-
fpArray := make(kbapi.SecurityDetectionsAPIRuleFalsePositiveArray, len(fpList))
178-
//nolint:staticcheck // Type conversion required, can't use copy()
179-
for i, fp := range fpList {
180-
fpArray[i] = fp
181-
}
182-
queryRule.FalsePositives = &fpArray
183-
}
184-
}
185-
186-
// Set references
187-
if !data.References.IsNull() && !data.References.IsUnknown() {
188-
var refList []string
189-
diags.Append(data.References.ElementsAs(ctx, &refList, false)...)
190-
if !diags.HasError() && len(refList) > 0 {
191-
refArray := make(kbapi.SecurityDetectionsAPIRuleReferenceArray, len(refList))
192-
//nolint:staticcheck // Type conversion required, can't use copy()
193-
for i, ref := range refList {
194-
refArray[i] = ref
195-
}
196-
queryRule.References = &refArray
197-
}
198-
}
199-
200-
// Set optional string fields
201-
if !data.License.IsNull() {
202-
license := kbapi.SecurityDetectionsAPIRuleLicense(data.License.ValueString())
203-
queryRule.License = &license
62+
// Set the ID based on the created rule
63+
compId := clients.CompositeId{
64+
ClusterId: data.SpaceId.ValueString(),
65+
ResourceId: ruleResponse.Id.String(),
20466
}
67+
data.Id = types.StringValue(compId.String())
20568

206-
if !data.Note.IsNull() {
207-
note := kbapi.SecurityDetectionsAPIInvestigationGuide(data.Note.ValueString())
208-
queryRule.Note = &note
69+
// Use Read logic to populate the state with fresh data from the API
70+
readReq := resource.ReadRequest{
71+
State: resp.State,
20972
}
73+
var readResp resource.ReadResponse
74+
readReq.State.Set(ctx, &data)
75+
r.Read(ctx, readReq, &readResp)
21076

211-
if !data.Setup.IsNull() {
212-
setup := kbapi.SecurityDetectionsAPISetupGuide(data.Setup.ValueString())
213-
queryRule.Setup = &setup
214-
}
215-
216-
// Set max signals
217-
if !data.MaxSignals.IsNull() {
218-
maxSignals := kbapi.SecurityDetectionsAPIMaxSignals(data.MaxSignals.ValueInt64())
219-
queryRule.MaxSignals = &maxSignals
220-
}
221-
222-
// Set version
223-
if !data.Version.IsNull() {
224-
version := kbapi.SecurityDetectionsAPIRuleVersion(data.Version.ValueInt64())
225-
queryRule.Version = &version
226-
}
227-
228-
// Convert to union type
229-
err := createProps.FromSecurityDetectionsAPIQueryRuleCreateProps(queryRule)
230-
if err != nil {
231-
diags.AddError(
232-
"Error building create properties",
233-
"Could not convert rule properties: "+err.Error(),
234-
)
77+
resp.Diagnostics.Append(readResp.Diagnostics...)
78+
if resp.Diagnostics.HasError() {
79+
return
23580
}
23681

237-
return createProps, diags
82+
resp.State = readResp.State
23883
}

internal/kibana/security_detection_rule/delete.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66

77
"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
8+
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
89
"github.com/google/uuid"
910
"github.com/hashicorp/terraform-plugin-framework/resource"
1011
)
@@ -18,7 +19,7 @@ func (r *securityDetectionRuleResource) Delete(ctx context.Context, req resource
1819
}
1920

2021
// Parse ID to get space_id and rule_id
21-
_, ruleId, diags := r.parseResourceId(data.Id.ValueString())
22+
compId, diags := clients.CompositeIdFromStrFw(data.Id.ValueString())
2223
resp.Diagnostics.Append(diags...)
2324
if resp.Diagnostics.HasError() {
2425
return
@@ -35,7 +36,12 @@ func (r *securityDetectionRuleResource) Delete(ctx context.Context, req resource
3536
}
3637

3738
// Delete the rule
38-
ruleObjectId := kbapi.SecurityDetectionsAPIRuleObjectId(uuid.MustParse(ruleId))
39+
uid, err := uuid.Parse(compId.ResourceId)
40+
if err != nil {
41+
resp.Diagnostics.AddError("ID was not a valid UUID", err.Error())
42+
return
43+
}
44+
ruleObjectId := kbapi.SecurityDetectionsAPIRuleObjectId(uid)
3945
params := &kbapi.DeleteRuleParams{
4046
Id: &ruleObjectId,
4147
}

0 commit comments

Comments
 (0)