Skip to content

Commit fcab004

Browse files
committed
Add model_<type> for all rule types
1 parent f5ea9a2 commit fcab004

File tree

9 files changed

+3016
-2916
lines changed

9 files changed

+3016
-2916
lines changed

internal/kibana/security_detection_rule/models.go

Lines changed: 84 additions & 2916 deletions
Large diffs are not rendered by default.
Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
package security_detection_rule
2+
3+
import (
4+
"context"
5+
6+
"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
7+
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
8+
"github.com/elastic/terraform-provider-elasticstack/internal/utils"
9+
"github.com/google/uuid"
10+
"github.com/hashicorp/terraform-plugin-framework/attr"
11+
"github.com/hashicorp/terraform-plugin-framework/diag"
12+
"github.com/hashicorp/terraform-plugin-framework/path"
13+
"github.com/hashicorp/terraform-plugin-framework/types"
14+
)
15+
16+
func (d SecurityDetectionRuleData) toEqlRuleCreateProps(ctx context.Context) (kbapi.SecurityDetectionsAPIRuleCreateProps, diag.Diagnostics) {
17+
var diags diag.Diagnostics
18+
var createProps kbapi.SecurityDetectionsAPIRuleCreateProps
19+
20+
eqlRule := kbapi.SecurityDetectionsAPIEqlRuleCreateProps{
21+
Name: kbapi.SecurityDetectionsAPIRuleName(d.Name.ValueString()),
22+
Description: kbapi.SecurityDetectionsAPIRuleDescription(d.Description.ValueString()),
23+
Type: kbapi.SecurityDetectionsAPIEqlRuleCreatePropsType("eql"),
24+
Query: kbapi.SecurityDetectionsAPIRuleQuery(d.Query.ValueString()),
25+
Language: kbapi.SecurityDetectionsAPIEqlQueryLanguage("eql"),
26+
RiskScore: kbapi.SecurityDetectionsAPIRiskScore(d.RiskScore.ValueInt64()),
27+
Severity: kbapi.SecurityDetectionsAPISeverity(d.Severity.ValueString()),
28+
}
29+
30+
d.setCommonCreateProps(ctx, &CommonCreateProps{
31+
Actions: &eqlRule.Actions,
32+
ResponseActions: &eqlRule.ResponseActions,
33+
RuleId: &eqlRule.RuleId,
34+
Enabled: &eqlRule.Enabled,
35+
From: &eqlRule.From,
36+
To: &eqlRule.To,
37+
Interval: &eqlRule.Interval,
38+
Index: &eqlRule.Index,
39+
Author: &eqlRule.Author,
40+
Tags: &eqlRule.Tags,
41+
FalsePositives: &eqlRule.FalsePositives,
42+
References: &eqlRule.References,
43+
License: &eqlRule.License,
44+
Note: &eqlRule.Note,
45+
Setup: &eqlRule.Setup,
46+
MaxSignals: &eqlRule.MaxSignals,
47+
Version: &eqlRule.Version,
48+
ExceptionsList: &eqlRule.ExceptionsList,
49+
AlertSuppression: &eqlRule.AlertSuppression,
50+
RiskScoreMapping: &eqlRule.RiskScoreMapping,
51+
SeverityMapping: &eqlRule.SeverityMapping,
52+
RelatedIntegrations: &eqlRule.RelatedIntegrations,
53+
RequiredFields: &eqlRule.RequiredFields,
54+
BuildingBlockType: &eqlRule.BuildingBlockType,
55+
DataViewId: &eqlRule.DataViewId,
56+
Namespace: &eqlRule.Namespace,
57+
RuleNameOverride: &eqlRule.RuleNameOverride,
58+
TimestampOverride: &eqlRule.TimestampOverride,
59+
TimestampOverrideFallbackDisabled: &eqlRule.TimestampOverrideFallbackDisabled,
60+
InvestigationFields: &eqlRule.InvestigationFields,
61+
Meta: &eqlRule.Meta,
62+
Filters: &eqlRule.Filters,
63+
}, &diags)
64+
65+
// Set EQL-specific fields
66+
if utils.IsKnown(d.TiebreakerField) {
67+
tiebreakerField := kbapi.SecurityDetectionsAPITiebreakerField(d.TiebreakerField.ValueString())
68+
eqlRule.TiebreakerField = &tiebreakerField
69+
}
70+
71+
// Convert to union type
72+
err := createProps.FromSecurityDetectionsAPIEqlRuleCreateProps(eqlRule)
73+
if err != nil {
74+
diags.AddError(
75+
"Error building create properties",
76+
"Could not convert EQL rule properties: "+err.Error(),
77+
)
78+
}
79+
80+
return createProps, diags
81+
}
82+
func (d SecurityDetectionRuleData) toEqlRuleUpdateProps(ctx context.Context) (kbapi.SecurityDetectionsAPIRuleUpdateProps, diag.Diagnostics) {
83+
var diags diag.Diagnostics
84+
var updateProps kbapi.SecurityDetectionsAPIRuleUpdateProps
85+
86+
// Parse ID to get space_id and rule_id
87+
compId, resourceIdDiags := clients.CompositeIdFromStrFw(d.Id.ValueString())
88+
diags.Append(resourceIdDiags...)
89+
90+
uid, err := uuid.Parse(compId.ResourceId)
91+
if err != nil {
92+
diags.AddError("ID was not a valid UUID", err.Error())
93+
return updateProps, diags
94+
}
95+
var id = kbapi.SecurityDetectionsAPIRuleObjectId(uid)
96+
97+
eqlRule := kbapi.SecurityDetectionsAPIEqlRuleUpdateProps{
98+
Id: &id,
99+
Name: kbapi.SecurityDetectionsAPIRuleName(d.Name.ValueString()),
100+
Description: kbapi.SecurityDetectionsAPIRuleDescription(d.Description.ValueString()),
101+
Type: kbapi.SecurityDetectionsAPIEqlRuleUpdatePropsType("eql"),
102+
Query: kbapi.SecurityDetectionsAPIRuleQuery(d.Query.ValueString()),
103+
Language: kbapi.SecurityDetectionsAPIEqlQueryLanguage("eql"),
104+
RiskScore: kbapi.SecurityDetectionsAPIRiskScore(d.RiskScore.ValueInt64()),
105+
Severity: kbapi.SecurityDetectionsAPISeverity(d.Severity.ValueString()),
106+
}
107+
108+
// For updates, we need to include the rule_id if it's set
109+
if utils.IsKnown(d.RuleId) {
110+
ruleId := kbapi.SecurityDetectionsAPIRuleSignatureId(d.RuleId.ValueString())
111+
eqlRule.RuleId = &ruleId
112+
eqlRule.Id = nil // if rule_id is set, we cant send id
113+
}
114+
115+
d.setCommonUpdateProps(ctx, &CommonUpdateProps{
116+
Actions: &eqlRule.Actions,
117+
ResponseActions: &eqlRule.ResponseActions,
118+
RuleId: &eqlRule.RuleId,
119+
Enabled: &eqlRule.Enabled,
120+
From: &eqlRule.From,
121+
To: &eqlRule.To,
122+
Interval: &eqlRule.Interval,
123+
Index: &eqlRule.Index,
124+
Author: &eqlRule.Author,
125+
Tags: &eqlRule.Tags,
126+
FalsePositives: &eqlRule.FalsePositives,
127+
References: &eqlRule.References,
128+
License: &eqlRule.License,
129+
Note: &eqlRule.Note,
130+
Setup: &eqlRule.Setup,
131+
MaxSignals: &eqlRule.MaxSignals,
132+
Version: &eqlRule.Version,
133+
ExceptionsList: &eqlRule.ExceptionsList,
134+
AlertSuppression: &eqlRule.AlertSuppression,
135+
RiskScoreMapping: &eqlRule.RiskScoreMapping,
136+
SeverityMapping: &eqlRule.SeverityMapping,
137+
RelatedIntegrations: &eqlRule.RelatedIntegrations,
138+
RequiredFields: &eqlRule.RequiredFields,
139+
BuildingBlockType: &eqlRule.BuildingBlockType,
140+
DataViewId: &eqlRule.DataViewId,
141+
Namespace: &eqlRule.Namespace,
142+
RuleNameOverride: &eqlRule.RuleNameOverride,
143+
TimestampOverride: &eqlRule.TimestampOverride,
144+
TimestampOverrideFallbackDisabled: &eqlRule.TimestampOverrideFallbackDisabled,
145+
InvestigationFields: &eqlRule.InvestigationFields,
146+
Meta: &eqlRule.Meta,
147+
Filters: &eqlRule.Filters,
148+
}, &diags)
149+
150+
// Set EQL-specific fields
151+
if utils.IsKnown(d.TiebreakerField) {
152+
tiebreakerField := kbapi.SecurityDetectionsAPITiebreakerField(d.TiebreakerField.ValueString())
153+
eqlRule.TiebreakerField = &tiebreakerField
154+
}
155+
156+
// Convert to union type
157+
err = updateProps.FromSecurityDetectionsAPIEqlRuleUpdateProps(eqlRule)
158+
if err != nil {
159+
diags.AddError(
160+
"Error building update properties",
161+
"Could not convert EQL rule properties: "+err.Error(),
162+
)
163+
}
164+
165+
return updateProps, diags
166+
}
167+
func (d *SecurityDetectionRuleData) updateFromEqlRule(ctx context.Context, rule *kbapi.SecurityDetectionsAPIEqlRule) diag.Diagnostics {
168+
var diags diag.Diagnostics
169+
170+
compId := clients.CompositeId{
171+
ClusterId: d.SpaceId.ValueString(),
172+
ResourceId: rule.Id.String(),
173+
}
174+
d.Id = types.StringValue(compId.String())
175+
176+
d.RuleId = types.StringValue(string(rule.RuleId))
177+
d.Name = types.StringValue(string(rule.Name))
178+
d.Type = types.StringValue(string(rule.Type))
179+
180+
// Update common fields
181+
if rule.DataViewId != nil {
182+
d.DataViewId = types.StringValue(string(*rule.DataViewId))
183+
} else {
184+
d.DataViewId = types.StringNull()
185+
}
186+
187+
if rule.Namespace != nil {
188+
d.Namespace = types.StringValue(string(*rule.Namespace))
189+
} else {
190+
d.Namespace = types.StringNull()
191+
}
192+
193+
if rule.RuleNameOverride != nil {
194+
d.RuleNameOverride = types.StringValue(string(*rule.RuleNameOverride))
195+
} else {
196+
d.RuleNameOverride = types.StringNull()
197+
}
198+
199+
if rule.TimestampOverride != nil {
200+
d.TimestampOverride = types.StringValue(string(*rule.TimestampOverride))
201+
} else {
202+
d.TimestampOverride = types.StringNull()
203+
}
204+
205+
if rule.TimestampOverrideFallbackDisabled != nil {
206+
d.TimestampOverrideFallbackDisabled = types.BoolValue(bool(*rule.TimestampOverrideFallbackDisabled))
207+
} else {
208+
d.TimestampOverrideFallbackDisabled = types.BoolNull()
209+
}
210+
211+
d.Query = types.StringValue(rule.Query)
212+
d.Language = types.StringValue(string(rule.Language))
213+
d.Enabled = types.BoolValue(bool(rule.Enabled))
214+
d.From = types.StringValue(string(rule.From))
215+
d.To = types.StringValue(string(rule.To))
216+
d.Interval = types.StringValue(string(rule.Interval))
217+
d.Description = types.StringValue(string(rule.Description))
218+
d.RiskScore = types.Int64Value(int64(rule.RiskScore))
219+
d.Severity = types.StringValue(string(rule.Severity))
220+
d.MaxSignals = types.Int64Value(int64(rule.MaxSignals))
221+
d.Version = types.Int64Value(int64(rule.Version))
222+
223+
// Update building block type
224+
if rule.BuildingBlockType != nil {
225+
d.BuildingBlockType = types.StringValue(string(*rule.BuildingBlockType))
226+
} else {
227+
d.BuildingBlockType = types.StringNull()
228+
}
229+
230+
// Update read-only fields
231+
d.CreatedAt = utils.TimeToStringValue(rule.CreatedAt)
232+
d.CreatedBy = types.StringValue(rule.CreatedBy)
233+
d.UpdatedAt = utils.TimeToStringValue(rule.UpdatedAt)
234+
d.UpdatedBy = types.StringValue(rule.UpdatedBy)
235+
d.Revision = types.Int64Value(int64(rule.Revision))
236+
237+
// Update index patterns
238+
if rule.Index != nil && len(*rule.Index) > 0 {
239+
d.Index = utils.ListValueFrom(ctx, *rule.Index, types.StringType, path.Root("index"), &diags)
240+
} else {
241+
d.Index = types.ListValueMust(types.StringType, []attr.Value{})
242+
}
243+
244+
// Update author
245+
if len(rule.Author) > 0 {
246+
d.Author = utils.ListValueFrom(ctx, rule.Author, types.StringType, path.Root("author"), &diags)
247+
} else {
248+
d.Author = types.ListValueMust(types.StringType, []attr.Value{})
249+
}
250+
251+
// Update tags
252+
if len(rule.Tags) > 0 {
253+
d.Tags = utils.ListValueFrom(ctx, rule.Tags, types.StringType, path.Root("tags"), &diags)
254+
} else {
255+
d.Tags = types.ListValueMust(types.StringType, []attr.Value{})
256+
}
257+
258+
// Update false positives
259+
if len(rule.FalsePositives) > 0 {
260+
d.FalsePositives = utils.ListValueFrom(ctx, rule.FalsePositives, types.StringType, path.Root("false_positives"), &diags)
261+
} else {
262+
d.FalsePositives = types.ListValueMust(types.StringType, []attr.Value{})
263+
}
264+
265+
// Update references
266+
if len(rule.References) > 0 {
267+
d.References = utils.ListValueFrom(ctx, rule.References, types.StringType, path.Root("references"), &diags)
268+
} else {
269+
d.References = types.ListValueMust(types.StringType, []attr.Value{})
270+
}
271+
272+
// Update optional string fields
273+
if rule.License != nil {
274+
d.License = types.StringValue(string(*rule.License))
275+
} else {
276+
d.License = types.StringNull()
277+
}
278+
279+
if rule.Note != nil {
280+
d.Note = types.StringValue(string(*rule.Note))
281+
} else {
282+
d.Note = types.StringNull()
283+
}
284+
285+
// Handle setup field - if empty, set to null to maintain consistency with optional schema
286+
if string(rule.Setup) != "" {
287+
d.Setup = types.StringValue(string(rule.Setup))
288+
} else {
289+
d.Setup = types.StringNull()
290+
}
291+
292+
// EQL-specific fields
293+
if rule.TiebreakerField != nil {
294+
d.TiebreakerField = types.StringValue(string(*rule.TiebreakerField))
295+
} else {
296+
d.TiebreakerField = types.StringNull()
297+
}
298+
299+
// Update actions
300+
actionDiags := d.updateActionsFromApi(ctx, rule.Actions)
301+
diags.Append(actionDiags...)
302+
303+
// Update exceptions list
304+
exceptionsListDiags := d.updateExceptionsListFromApi(ctx, rule.ExceptionsList)
305+
diags.Append(exceptionsListDiags...)
306+
307+
// Update risk score mapping
308+
riskScoreMappingDiags := d.updateRiskScoreMappingFromApi(ctx, rule.RiskScoreMapping)
309+
diags.Append(riskScoreMappingDiags...)
310+
311+
// Update investigation fields
312+
investigationFieldsDiags := d.updateInvestigationFieldsFromApi(ctx, rule.InvestigationFields)
313+
diags.Append(investigationFieldsDiags...)
314+
315+
// Update meta field
316+
metaDiags := d.updateMetaFromApi(ctx, rule.Meta)
317+
diags.Append(metaDiags...)
318+
319+
// Update filters field
320+
filtersDiags := d.updateFiltersFromApi(ctx, rule.Filters)
321+
diags.Append(filtersDiags...)
322+
323+
// Update severity mapping
324+
severityMappingDiags := d.updateSeverityMappingFromApi(ctx, &rule.SeverityMapping)
325+
diags.Append(severityMappingDiags...)
326+
327+
// Update related integrations
328+
relatedIntegrationsDiags := d.updateRelatedIntegrationsFromApi(ctx, &rule.RelatedIntegrations)
329+
diags.Append(relatedIntegrationsDiags...)
330+
331+
// Update required fields
332+
requiredFieldsDiags := d.updateRequiredFieldsFromApi(ctx, &rule.RequiredFields)
333+
diags.Append(requiredFieldsDiags...)
334+
335+
// Update alert suppression
336+
alertSuppressionDiags := d.updateAlertSuppressionFromApi(ctx, rule.AlertSuppression)
337+
diags.Append(alertSuppressionDiags...)
338+
339+
// Update response actions
340+
responseActionsDiags := d.updateResponseActionsFromApi(ctx, rule.ResponseActions)
341+
diags.Append(responseActionsDiags...)
342+
343+
return diags
344+
}

0 commit comments

Comments
 (0)