From bfd68f86eb47ca48973570590b434e9162a2950a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:23:22 +0000 Subject: [PATCH 01/21] Initial plan From 8815af28b8c9220a89ac9220b8227f6bf5c79b15 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:46:21 +0000 Subject: [PATCH 02/21] Add exception_list and exception_item resources with CRUD operations Co-authored-by: nick-benoit <163016768+nick-benoit@users.noreply.github.com> --- .../kibana_security_exception_item.md | 102 +++++++ .../kibana_security_exception_list.md | 69 +++++ internal/clients/kibana_oapi/exceptions.go | 138 +++++++++ .../kibana/security/exception_item/create.go | 262 ++++++++++++++++++ .../kibana/security/exception_item/delete.go | 34 +++ .../kibana/security/exception_item/models.go | 31 +++ .../kibana/security/exception_item/read.go | 52 ++++ .../exception_item/resource-description.md | 27 ++ .../security/exception_item/resource.go | 40 +++ .../kibana/security/exception_item/schema.go | 137 +++++++++ .../kibana/security/exception_item/update.go | 144 ++++++++++ .../kibana/security/exception_list/create.go | 184 ++++++++++++ .../kibana/security/exception_list/delete.go | 34 +++ .../kibana/security/exception_list/models.go | 24 ++ .../kibana/security/exception_list/read.go | 52 ++++ .../exception_list/resource-description.md | 17 ++ .../security/exception_list/resource.go | 40 +++ .../kibana/security/exception_list/schema.go | 119 ++++++++ .../kibana/security/exception_list/update.go | 104 +++++++ provider/plugin_framework.go | 4 + 20 files changed, 1614 insertions(+) create mode 100644 docs/resources/kibana_security_exception_item.md create mode 100644 docs/resources/kibana_security_exception_list.md create mode 100644 internal/clients/kibana_oapi/exceptions.go create mode 100644 internal/kibana/security/exception_item/create.go create mode 100644 internal/kibana/security/exception_item/delete.go create mode 100644 internal/kibana/security/exception_item/models.go create mode 100644 internal/kibana/security/exception_item/read.go create mode 100644 internal/kibana/security/exception_item/resource-description.md create mode 100644 internal/kibana/security/exception_item/resource.go create mode 100644 internal/kibana/security/exception_item/schema.go create mode 100644 internal/kibana/security/exception_item/update.go create mode 100644 internal/kibana/security/exception_list/create.go create mode 100644 internal/kibana/security/exception_list/delete.go create mode 100644 internal/kibana/security/exception_list/models.go create mode 100644 internal/kibana/security/exception_list/read.go create mode 100644 internal/kibana/security/exception_list/resource-description.md create mode 100644 internal/kibana/security/exception_list/resource.go create mode 100644 internal/kibana/security/exception_list/schema.go create mode 100644 internal/kibana/security/exception_list/update.go diff --git a/docs/resources/kibana_security_exception_item.md b/docs/resources/kibana_security_exception_item.md new file mode 100644 index 000000000..9cf8a9c8c --- /dev/null +++ b/docs/resources/kibana_security_exception_item.md @@ -0,0 +1,102 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "elasticstack_kibana_security_exception_item Resource - terraform-provider-elasticstack" +subcategory: "Kibana" +description: |- + Manages a Kibana Exception Item. Exception items define the specific query conditions used to prevent rules from generating alerts. + See the Kibana Exceptions API documentation https://www.elastic.co/docs/api/doc/kibana/group/endpoint-security-exceptions-api for more details. + Example Usage + + resource "elasticstack_kibana_security_exception_item" "example" { + list_id = elasticstack_kibana_security_exception_list.example.list_id + item_id = "my-exception-item" + name = "My Exception Item" + description = "Exclude specific processes from alerts" + type = "simple" + namespace_type = "single" + + entries = jsonencode([ + { + field = "process.name" + operator = "included" + type = "match" + value = "my-process" + } + ]) + + tags = ["tag1", "tag2"] + } +--- + +# elasticstack_kibana_security_exception_item (Resource) + +Manages a Kibana Exception Item. Exception items define the specific query conditions used to prevent rules from generating alerts. + +See the [Kibana Exceptions API documentation](https://www.elastic.co/docs/api/doc/kibana/group/endpoint-security-exceptions-api) for more details. + +## Example Usage + +```terraform +resource "elasticstack_kibana_security_exception_item" "example" { + list_id = elasticstack_kibana_security_exception_list.example.list_id + item_id = "my-exception-item" + name = "My Exception Item" + description = "Exclude specific processes from alerts" + type = "simple" + namespace_type = "single" + + entries = jsonencode([ + { + field = "process.name" + operator = "included" + type = "match" + value = "my-process" + } + ]) + + tags = ["tag1", "tag2"] +} +``` + + + + +## Schema + +### Required + +- `description` (String) Describes the exception item. +- `entries` (String) The exception item entries as JSON string. This defines the conditions under which the exception applies. +- `list_id` (String) The exception list's identifier that this item belongs to. +- `name` (String) The name of the exception item. +- `type` (String) The type of exception item. Must be `simple`. + +### Optional + +- `comments` (Attributes List) Array of comments about the exception item. (see [below for nested schema](#nestedatt--comments)) +- `expire_time` (String) The exception item's expiration date in ISO format. This field is only available for regular exception items, not endpoint exceptions. +- `item_id` (String) The exception item's human readable string identifier. +- `meta` (String) Placeholder for metadata about the exception item as JSON string. +- `namespace_type` (String) Determines whether the exception item is available in all Kibana spaces or just the space in which it is created. Can be `single` (default) or `agnostic`. +- `os_types` (List of String) Array of OS types for which the exceptions apply. Valid values: `linux`, `macos`, `windows`. +- `tags` (List of String) String array containing words and phrases to help categorize exception items. + +### Read-Only + +- `created_at` (String) The timestamp of when the exception item was created. +- `created_by` (String) The user who created the exception item. +- `id` (String) The unique identifier of the exception item (auto-generated by Kibana). +- `tie_breaker_id` (String) Field used in search to ensure all items are sorted and returned correctly. +- `updated_at` (String) The timestamp of when the exception item was last updated. +- `updated_by` (String) The user who last updated the exception item. + + +### Nested Schema for `comments` + +Required: + +- `comment` (String) The comment text. + +Read-Only: + +- `id` (String) The unique identifier of the comment (auto-generated by Kibana). diff --git a/docs/resources/kibana_security_exception_list.md b/docs/resources/kibana_security_exception_list.md new file mode 100644 index 000000000..01319e4f1 --- /dev/null +++ b/docs/resources/kibana_security_exception_list.md @@ -0,0 +1,69 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "elasticstack_kibana_security_exception_list Resource - terraform-provider-elasticstack" +subcategory: "Kibana" +description: |- + Manages a Kibana Exception List. Exception lists are containers for exception items used to prevent security rules from generating alerts. + See the Kibana Exceptions API documentation https://www.elastic.co/docs/api/doc/kibana/group/endpoint-security-exceptions-api for more details. + Example Usage + + resource "elasticstack_kibana_security_exception_list" "example" { + list_id = "my-exception-list" + name = "My Exception List" + description = "List of exceptions for security rules" + type = "detection" + namespace_type = "single" + + tags = ["tag1", "tag2"] + } +--- + +# elasticstack_kibana_security_exception_list (Resource) + +Manages a Kibana Exception List. Exception lists are containers for exception items used to prevent security rules from generating alerts. + +See the [Kibana Exceptions API documentation](https://www.elastic.co/docs/api/doc/kibana/group/endpoint-security-exceptions-api) for more details. + +## Example Usage + +```terraform +resource "elasticstack_kibana_security_exception_list" "example" { + list_id = "my-exception-list" + name = "My Exception List" + description = "List of exceptions for security rules" + type = "detection" + namespace_type = "single" + + tags = ["tag1", "tag2"] +} +``` + + + + +## Schema + +### Required + +- `description` (String) Describes the exception list. +- `list_id` (String) The exception list's human readable string identifier. +- `name` (String) The name of the exception list. +- `type` (String) The type of exception list. Can be one of: `detection`, `endpoint`, `endpoint_trusted_apps`, `endpoint_events`, `endpoint_host_isolation_exceptions`, `endpoint_blocklists`. + +### Optional + +- `meta` (String) Placeholder for metadata about the list container as JSON string. +- `namespace_type` (String) Determines whether the exception list is available in all Kibana spaces or just the space in which it is created. Can be `single` (default) or `agnostic`. +- `os_types` (List of String) Array of OS types for which the exceptions apply. Valid values: `linux`, `macos`, `windows`. +- `tags` (List of String) String array containing words and phrases to help categorize exception containers. + +### Read-Only + +- `created_at` (String) The timestamp of when the exception list was created. +- `created_by` (String) The user who created the exception list. +- `id` (String) The unique identifier of the exception list (auto-generated by Kibana). +- `immutable` (Boolean) Whether the exception list is immutable. +- `tie_breaker_id` (String) Field used in search to ensure all containers are sorted and returned correctly. +- `updated_at` (String) The timestamp of when the exception list was last updated. +- `updated_by` (String) The user who last updated the exception list. +- `version` (Number) The version of the exception list. diff --git a/internal/clients/kibana_oapi/exceptions.go b/internal/clients/kibana_oapi/exceptions.go new file mode 100644 index 000000000..188b83826 --- /dev/null +++ b/internal/clients/kibana_oapi/exceptions.go @@ -0,0 +1,138 @@ +package kibana_oapi + +import ( + "context" + "net/http" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/diagutil" + "github.com/hashicorp/terraform-plugin-framework/diag" +) + +// GetExceptionList reads an exception list from the API by ID or list_id +func GetExceptionList(ctx context.Context, client *Client, params *kbapi.ReadExceptionListParams) (*kbapi.ReadExceptionListResponse, diag.Diagnostics) { + resp, err := client.API.ReadExceptionListWithResponse(ctx, params) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + case http.StatusNotFound: + return nil, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// CreateExceptionList creates a new exception list. +func CreateExceptionList(ctx context.Context, client *Client, body kbapi.CreateExceptionListJSONRequestBody) (*kbapi.CreateExceptionListResponse, diag.Diagnostics) { + resp, err := client.API.CreateExceptionListWithResponse(ctx, body) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// UpdateExceptionList updates an existing exception list. +func UpdateExceptionList(ctx context.Context, client *Client, body kbapi.UpdateExceptionListJSONRequestBody) (*kbapi.UpdateExceptionListResponse, diag.Diagnostics) { + resp, err := client.API.UpdateExceptionListWithResponse(ctx, body) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// DeleteExceptionList deletes an existing exception list. +func DeleteExceptionList(ctx context.Context, client *Client, params *kbapi.DeleteExceptionListParams) diag.Diagnostics { + resp, err := client.API.DeleteExceptionListWithResponse(ctx, params) + if err != nil { + return diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return nil + case http.StatusNotFound: + return nil + default: + return reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// GetExceptionListItem reads an exception list item from the API by ID or item_id +func GetExceptionListItem(ctx context.Context, client *Client, params *kbapi.ReadExceptionListItemParams) (*kbapi.ReadExceptionListItemResponse, diag.Diagnostics) { + resp, err := client.API.ReadExceptionListItemWithResponse(ctx, params) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + case http.StatusNotFound: + return nil, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// CreateExceptionListItem creates a new exception list item. +func CreateExceptionListItem(ctx context.Context, client *Client, body kbapi.CreateExceptionListItemJSONRequestBody) (*kbapi.CreateExceptionListItemResponse, diag.Diagnostics) { + resp, err := client.API.CreateExceptionListItemWithResponse(ctx, body) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// UpdateExceptionListItem updates an existing exception list item. +func UpdateExceptionListItem(ctx context.Context, client *Client, body kbapi.UpdateExceptionListItemJSONRequestBody) (*kbapi.UpdateExceptionListItemResponse, diag.Diagnostics) { + resp, err := client.API.UpdateExceptionListItemWithResponse(ctx, body) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// DeleteExceptionListItem deletes an existing exception list item. +func DeleteExceptionListItem(ctx context.Context, client *Client, params *kbapi.DeleteExceptionListItemParams) diag.Diagnostics { + resp, err := client.API.DeleteExceptionListItemWithResponse(ctx, params) + if err != nil { + return diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return nil + case http.StatusNotFound: + return nil + default: + return reportUnknownError(resp.StatusCode(), resp.Body) + } +} diff --git a/internal/kibana/security/exception_item/create.go b/internal/kibana/security/exception_item/create.go new file mode 100644 index 000000000..c93d4b669 --- /dev/null +++ b/internal/kibana/security/exception_item/create.go @@ -0,0 +1,262 @@ +package exception_item + +import ( + "context" + "encoding/json" + "time" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func (r *ExceptionItemResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan ExceptionItemModel + + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Parse entries JSON + var entries kbapi.SecurityExceptionsAPIExceptionListItemEntryArray + if err := json.Unmarshal([]byte(plan.Entries.ValueString()), &entries); err != nil { + resp.Diagnostics.AddError("Failed to parse entries JSON", err.Error()) + return + } + + // Build the request body + body := kbapi.CreateExceptionListItemJSONRequestBody{ + ListId: kbapi.SecurityExceptionsAPIExceptionListHumanId(plan.ListID.ValueString()), + Name: kbapi.SecurityExceptionsAPIExceptionListItemName(plan.Name.ValueString()), + Description: kbapi.SecurityExceptionsAPIExceptionListItemDescription(plan.Description.ValueString()), + Type: kbapi.SecurityExceptionsAPIExceptionListItemType(plan.Type.ValueString()), + Entries: entries, + } + + // Set optional item_id + if utils.IsKnown(plan.ItemID) && !plan.ItemID.IsNull() { + itemID := kbapi.SecurityExceptionsAPIExceptionListItemHumanId(plan.ItemID.ValueString()) + body.ItemId = &itemID + } + + // Set optional namespace_type + if utils.IsKnown(plan.NamespaceType) { + nsType := kbapi.SecurityExceptionsAPIExceptionNamespaceType(plan.NamespaceType.ValueString()) + body.NamespaceType = &nsType + } + + // Set optional os_types + if utils.IsKnown(plan.OsTypes) && !plan.OsTypes.IsNull() { + var osTypes []string + diags := plan.OsTypes.ElementsAs(ctx, &osTypes, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if len(osTypes) > 0 { + osTypesArray := make(kbapi.SecurityExceptionsAPIExceptionListItemOsTypeArray, len(osTypes)) + for i, osType := range osTypes { + osTypesArray[i] = kbapi.SecurityExceptionsAPIExceptionListOsType(osType) + } + body.OsTypes = &osTypesArray + } + } + + // Set optional tags + if utils.IsKnown(plan.Tags) && !plan.Tags.IsNull() { + var tags []string + diags := plan.Tags.ElementsAs(ctx, &tags, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if len(tags) > 0 { + tagsArray := kbapi.SecurityExceptionsAPIExceptionListItemTags(tags) + body.Tags = &tagsArray + } + } + + // Set optional meta + if utils.IsKnown(plan.Meta) && !plan.Meta.IsNull() { + var meta kbapi.SecurityExceptionsAPIExceptionListItemMeta + if err := json.Unmarshal([]byte(plan.Meta.ValueString()), &meta); err != nil { + resp.Diagnostics.AddError("Failed to parse meta JSON", err.Error()) + return + } + body.Meta = &meta + } + + // Set optional comments + if utils.IsKnown(plan.Comments) && !plan.Comments.IsNull() { + var comments []CommentModel + diags := plan.Comments.ElementsAs(ctx, &comments, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if len(comments) > 0 { + commentsArray := make(kbapi.SecurityExceptionsAPICreateExceptionListItemCommentArray, len(comments)) + for i, comment := range comments { + commentsArray[i] = kbapi.SecurityExceptionsAPICreateExceptionListItemComment{ + Comment: kbapi.SecurityExceptionsAPINonEmptyString(comment.Comment.ValueString()), + } + } + body.Comments = &commentsArray + } + } + + // Set optional expire_time + if utils.IsKnown(plan.ExpireTime) && !plan.ExpireTime.IsNull() { + expireTime, err := time.Parse(time.RFC3339, plan.ExpireTime.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Failed to parse expire_time", err.Error()) + return + } + expireTimeAPI := kbapi.SecurityExceptionsAPIExceptionListItemExpireTime(expireTime) + body.ExpireTime = &expireTimeAPI + } + + // Create the exception item + createResp, diags := kibana_oapi.CreateExceptionListItem(ctx, client, body) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if createResp == nil || createResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to create exception item", "API returned empty response") + return + } + + // Read back the created resource to get computed fields + readParams := &kbapi.ReadExceptionListItemParams{ + Id: (*kbapi.SecurityExceptionsAPIExceptionListItemId)(&createResp.JSON200.Id), + } + + readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, readParams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to read created exception item", "API returned empty response") + return + } + + // Update state with response + diags = r.updateStateFromAPIResponse(ctx, &plan, readResp.JSON200) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) +} + +func (r *ExceptionItemResource) updateStateFromAPIResponse(ctx context.Context, model *ExceptionItemModel, apiResp *kbapi.SecurityExceptionsAPIExceptionListItem) diag.Diagnostics { + var diags diag.Diagnostics + + model.ID = types.StringValue(string(apiResp.Id)) + model.ItemID = types.StringValue(string(apiResp.ItemId)) + model.ListID = types.StringValue(string(apiResp.ListId)) + model.Name = types.StringValue(string(apiResp.Name)) + model.Description = types.StringValue(string(apiResp.Description)) + model.Type = types.StringValue(string(apiResp.Type)) + model.NamespaceType = types.StringValue(string(apiResp.NamespaceType)) + model.CreatedAt = types.StringValue(apiResp.CreatedAt.Format("2006-01-02T15:04:05.000Z")) + model.CreatedBy = types.StringValue(apiResp.CreatedBy) + model.UpdatedAt = types.StringValue(apiResp.UpdatedAt.Format("2006-01-02T15:04:05.000Z")) + model.UpdatedBy = types.StringValue(apiResp.UpdatedBy) + model.TieBreakerID = types.StringValue(apiResp.TieBreakerId) + + // Set optional expire_time + if apiResp.ExpireTime != nil { + model.ExpireTime = types.StringValue(time.Time(*apiResp.ExpireTime).Format(time.RFC3339)) + } else { + model.ExpireTime = types.StringNull() + } + + // Set optional os_types + if apiResp.OsTypes != nil && len(*apiResp.OsTypes) > 0 { + osTypes := make([]string, len(*apiResp.OsTypes)) + for i, osType := range *apiResp.OsTypes { + osTypes[i] = string(osType) + } + list, d := types.ListValueFrom(ctx, types.StringType, osTypes) + diags.Append(d...) + model.OsTypes = list + } else { + model.OsTypes = types.ListNull(types.StringType) + } + + // Set optional tags + if apiResp.Tags != nil && len(*apiResp.Tags) > 0 { + list, d := types.ListValueFrom(ctx, types.StringType, *apiResp.Tags) + diags.Append(d...) + model.Tags = list + } else { + model.Tags = types.ListNull(types.StringType) + } + + // Set optional meta + if apiResp.Meta != nil { + metaJSON, err := json.Marshal(apiResp.Meta) + if err != nil { + diags.AddError("Failed to serialize meta", err.Error()) + return diags + } + model.Meta = types.StringValue(string(metaJSON)) + } else { + model.Meta = types.StringNull() + } + + // Set entries (convert back to JSON) + entriesJSON, err := json.Marshal(apiResp.Entries) + if err != nil { + diags.AddError("Failed to serialize entries", err.Error()) + return diags + } + model.Entries = types.StringValue(string(entriesJSON)) + + // Set optional comments + if len(apiResp.Comments) > 0 { + comments := make([]CommentModel, len(apiResp.Comments)) + for i, comment := range apiResp.Comments { + comments[i] = CommentModel{ + ID: types.StringValue(string(comment.Id)), + Comment: types.StringValue(string(comment.Comment)), + } + } + list, d := types.ListValueFrom(ctx, types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "id": types.StringType, + "comment": types.StringType, + }, + }, comments) + diags.Append(d...) + model.Comments = list + } else { + model.Comments = types.ListNull(types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "id": types.StringType, + "comment": types.StringType, + }, + }) + } + + return diags +} diff --git a/internal/kibana/security/exception_item/delete.go b/internal/kibana/security/exception_item/delete.go new file mode 100644 index 000000000..4edb4d4c9 --- /dev/null +++ b/internal/kibana/security/exception_item/delete.go @@ -0,0 +1,34 @@ +package exception_item + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *ExceptionItemResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state ExceptionItemModel + + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Delete by ID + id := kbapi.SecurityExceptionsAPIExceptionListItemId(state.ID.ValueString()) + params := &kbapi.DeleteExceptionListItemParams{ + Id: &id, + } + + diags = kibana_oapi.DeleteExceptionListItem(ctx, client, params) + resp.Diagnostics.Append(diags...) +} diff --git a/internal/kibana/security/exception_item/models.go b/internal/kibana/security/exception_item/models.go new file mode 100644 index 000000000..16735a13b --- /dev/null +++ b/internal/kibana/security/exception_item/models.go @@ -0,0 +1,31 @@ +package exception_item + +import ( + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ExceptionItemModel struct { + ID types.String `tfsdk:"id"` + ItemID types.String `tfsdk:"item_id"` + ListID types.String `tfsdk:"list_id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Type types.String `tfsdk:"type"` + NamespaceType types.String `tfsdk:"namespace_type"` + OsTypes types.List `tfsdk:"os_types"` + Tags types.List `tfsdk:"tags"` + Meta types.String `tfsdk:"meta"` + Entries types.String `tfsdk:"entries"` + Comments types.List `tfsdk:"comments"` + ExpireTime types.String `tfsdk:"expire_time"` + CreatedAt types.String `tfsdk:"created_at"` + CreatedBy types.String `tfsdk:"created_by"` + UpdatedAt types.String `tfsdk:"updated_at"` + UpdatedBy types.String `tfsdk:"updated_by"` + TieBreakerID types.String `tfsdk:"tie_breaker_id"` +} + +type CommentModel struct { + ID types.String `tfsdk:"id"` + Comment types.String `tfsdk:"comment"` +} diff --git a/internal/kibana/security/exception_item/read.go b/internal/kibana/security/exception_item/read.go new file mode 100644 index 000000000..ba9d3fd41 --- /dev/null +++ b/internal/kibana/security/exception_item/read.go @@ -0,0 +1,52 @@ +package exception_item + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *ExceptionItemResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state ExceptionItemModel + + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Read by ID + id := kbapi.SecurityExceptionsAPIExceptionListItemId(state.ID.ValueString()) + params := &kbapi.ReadExceptionListItemParams{ + Id: &id, + } + + readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, params) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Update state with response + diags = r.updateStateFromAPIResponse(ctx, &state, readResp.JSON200) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, state) + resp.Diagnostics.Append(diags...) +} diff --git a/internal/kibana/security/exception_item/resource-description.md b/internal/kibana/security/exception_item/resource-description.md new file mode 100644 index 000000000..8aa5b436a --- /dev/null +++ b/internal/kibana/security/exception_item/resource-description.md @@ -0,0 +1,27 @@ +Manages a Kibana Exception Item. Exception items define the specific query conditions used to prevent rules from generating alerts. + +See the [Kibana Exceptions API documentation](https://www.elastic.co/docs/api/doc/kibana/group/endpoint-security-exceptions-api) for more details. + +## Example Usage + +```terraform +resource "elasticstack_kibana_security_exception_item" "example" { + list_id = elasticstack_kibana_security_exception_list.example.list_id + item_id = "my-exception-item" + name = "My Exception Item" + description = "Exclude specific processes from alerts" + type = "simple" + namespace_type = "single" + + entries = jsonencode([ + { + field = "process.name" + operator = "included" + type = "match" + value = "my-process" + } + ]) + + tags = ["tag1", "tag2"] +} +``` diff --git a/internal/kibana/security/exception_item/resource.go b/internal/kibana/security/exception_item/resource.go new file mode 100644 index 000000000..5eea3137e --- /dev/null +++ b/internal/kibana/security/exception_item/resource.go @@ -0,0 +1,40 @@ +package exception_item + +import ( + "context" + "fmt" + + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var ( + _ resource.Resource = &ExceptionItemResource{} + _ resource.ResourceWithConfigure = &ExceptionItemResource{} + _ resource.ResourceWithImportState = &ExceptionItemResource{} +) + +// NewResource is a helper function to simplify the provider implementation. +func NewResource() resource.Resource { + return &ExceptionItemResource{} +} + +type ExceptionItemResource struct { + client *clients.ApiClient +} + +func (r *ExceptionItemResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + client, diags := clients.ConvertProviderData(req.ProviderData) + resp.Diagnostics.Append(diags...) + r.client = client +} + +// Metadata returns the provider type name. +func (r *ExceptionItemResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = fmt.Sprintf("%s_%s", req.ProviderTypeName, "kibana_security_exception_item") +} + +func (r *ExceptionItemResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response) +} diff --git a/internal/kibana/security/exception_item/schema.go b/internal/kibana/security/exception_item/schema.go new file mode 100644 index 000000000..1c904023b --- /dev/null +++ b/internal/kibana/security/exception_item/schema.go @@ -0,0 +1,137 @@ +package exception_item + +import ( + "context" + _ "embed" + + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +//go:embed resource-description.md +var exceptionItemResourceDescription string + +func (r *ExceptionItemResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: exceptionItemResourceDescription, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The unique identifier of the exception item (auto-generated by Kibana).", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "item_id": schema.StringAttribute{ + MarkdownDescription: "The exception item's human readable string identifier.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), + }, + }, + "list_id": schema.StringAttribute{ + MarkdownDescription: "The exception list's identifier that this item belongs to.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "The name of the exception item.", + Required: true, + }, + "description": schema.StringAttribute{ + MarkdownDescription: "Describes the exception item.", + Required: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "The type of exception item. Must be `simple`.", + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf("simple"), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "namespace_type": schema.StringAttribute{ + MarkdownDescription: "Determines whether the exception item is available in all Kibana spaces or just the space in which it is created. Can be `single` (default) or `agnostic`.", + Optional: true, + Computed: true, + Default: stringdefault.StaticString("single"), + Validators: []validator.String{ + stringvalidator.OneOf("single", "agnostic"), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "os_types": schema.ListAttribute{ + MarkdownDescription: "Array of OS types for which the exceptions apply. Valid values: `linux`, `macos`, `windows`.", + Optional: true, + ElementType: types.StringType, + }, + "tags": schema.ListAttribute{ + MarkdownDescription: "String array containing words and phrases to help categorize exception items.", + Optional: true, + ElementType: types.StringType, + }, + "meta": schema.StringAttribute{ + MarkdownDescription: "Placeholder for metadata about the exception item as JSON string.", + Optional: true, + }, + "entries": schema.StringAttribute{ + MarkdownDescription: "The exception item entries as JSON string. This defines the conditions under which the exception applies.", + Required: true, + }, + "comments": schema.ListNestedAttribute{ + MarkdownDescription: "Array of comments about the exception item.", + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The unique identifier of the comment (auto-generated by Kibana).", + Computed: true, + }, + "comment": schema.StringAttribute{ + MarkdownDescription: "The comment text.", + Required: true, + }, + }, + }, + }, + "expire_time": schema.StringAttribute{ + MarkdownDescription: "The exception item's expiration date in ISO format. This field is only available for regular exception items, not endpoint exceptions.", + Optional: true, + }, + "created_at": schema.StringAttribute{ + MarkdownDescription: "The timestamp of when the exception item was created.", + Computed: true, + }, + "created_by": schema.StringAttribute{ + MarkdownDescription: "The user who created the exception item.", + Computed: true, + }, + "updated_at": schema.StringAttribute{ + MarkdownDescription: "The timestamp of when the exception item was last updated.", + Computed: true, + }, + "updated_by": schema.StringAttribute{ + MarkdownDescription: "The user who last updated the exception item.", + Computed: true, + }, + "tie_breaker_id": schema.StringAttribute{ + MarkdownDescription: "Field used in search to ensure all items are sorted and returned correctly.", + Computed: true, + }, + }, + } +} diff --git a/internal/kibana/security/exception_item/update.go b/internal/kibana/security/exception_item/update.go new file mode 100644 index 000000000..22cdaa0a6 --- /dev/null +++ b/internal/kibana/security/exception_item/update.go @@ -0,0 +1,144 @@ +package exception_item + +import ( + "context" + "encoding/json" + "time" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *ExceptionItemResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan ExceptionItemModel + + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Parse entries JSON + var entries kbapi.SecurityExceptionsAPIExceptionListItemEntryArray + if err := json.Unmarshal([]byte(plan.Entries.ValueString()), &entries); err != nil { + resp.Diagnostics.AddError("Failed to parse entries JSON", err.Error()) + return + } + + // Build the update request body + id := kbapi.SecurityExceptionsAPIExceptionListItemId(plan.ID.ValueString()) + body := kbapi.UpdateExceptionListItemJSONRequestBody{ + Id: &id, + Name: kbapi.SecurityExceptionsAPIExceptionListItemName(plan.Name.ValueString()), + Description: kbapi.SecurityExceptionsAPIExceptionListItemDescription(plan.Description.ValueString()), + Type: kbapi.SecurityExceptionsAPIExceptionListItemType(plan.Type.ValueString()), + Entries: entries, + } + + // Set optional namespace_type + if utils.IsKnown(plan.NamespaceType) { + nsType := kbapi.SecurityExceptionsAPIExceptionNamespaceType(plan.NamespaceType.ValueString()) + body.NamespaceType = &nsType + } + + // Set optional os_types + if utils.IsKnown(plan.OsTypes) && !plan.OsTypes.IsNull() { + var osTypes []string + diags := plan.OsTypes.ElementsAs(ctx, &osTypes, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if len(osTypes) > 0 { + osTypesArray := make(kbapi.SecurityExceptionsAPIExceptionListItemOsTypeArray, len(osTypes)) + for i, osType := range osTypes { + osTypesArray[i] = kbapi.SecurityExceptionsAPIExceptionListOsType(osType) + } + body.OsTypes = &osTypesArray + } + } + + // Set optional tags + if utils.IsKnown(plan.Tags) && !plan.Tags.IsNull() { + var tags []string + diags := plan.Tags.ElementsAs(ctx, &tags, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if len(tags) > 0 { + tagsArray := kbapi.SecurityExceptionsAPIExceptionListItemTags(tags) + body.Tags = &tagsArray + } + } + + // Set optional meta + if utils.IsKnown(plan.Meta) && !plan.Meta.IsNull() { + var meta kbapi.SecurityExceptionsAPIExceptionListItemMeta + if err := json.Unmarshal([]byte(plan.Meta.ValueString()), &meta); err != nil { + resp.Diagnostics.AddError("Failed to parse meta JSON", err.Error()) + return + } + body.Meta = &meta + } + + // Set optional comments + if utils.IsKnown(plan.Comments) && !plan.Comments.IsNull() { + var comments []CommentModel + diags := plan.Comments.ElementsAs(ctx, &comments, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if len(comments) > 0 { + commentsArray := make(kbapi.SecurityExceptionsAPIUpdateExceptionListItemCommentArray, len(comments)) + for i, comment := range comments { + commentsArray[i] = kbapi.SecurityExceptionsAPIUpdateExceptionListItemComment{ + Comment: kbapi.SecurityExceptionsAPINonEmptyString(comment.Comment.ValueString()), + } + } + body.Comments = &commentsArray + } + } + + // Set optional expire_time + if utils.IsKnown(plan.ExpireTime) && !plan.ExpireTime.IsNull() { + expireTime, err := time.Parse(time.RFC3339, plan.ExpireTime.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Failed to parse expire_time", err.Error()) + return + } + expireTimeAPI := kbapi.SecurityExceptionsAPIExceptionListItemExpireTime(expireTime) + body.ExpireTime = &expireTimeAPI + } + + // Update the exception item + updateResp, diags := kibana_oapi.UpdateExceptionListItem(ctx, client, body) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if updateResp == nil || updateResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to update exception item", "API returned empty response") + return + } + + // Update state with response + diags = r.updateStateFromAPIResponse(ctx, &plan, updateResp.JSON200) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) +} diff --git a/internal/kibana/security/exception_list/create.go b/internal/kibana/security/exception_list/create.go new file mode 100644 index 000000000..174b80409 --- /dev/null +++ b/internal/kibana/security/exception_list/create.go @@ -0,0 +1,184 @@ +package exception_list + +import ( + "context" + "encoding/json" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func (r *ExceptionListResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan ExceptionListModel + + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Build the request body + body := kbapi.CreateExceptionListJSONRequestBody{ + ListId: (*kbapi.SecurityExceptionsAPIExceptionListHumanId)(plan.ListID.ValueStringPointer()), + Name: kbapi.SecurityExceptionsAPIExceptionListName(plan.Name.ValueString()), + Description: kbapi.SecurityExceptionsAPIExceptionListDescription(plan.Description.ValueString()), + Type: kbapi.SecurityExceptionsAPIExceptionListType(plan.Type.ValueString()), + } + + // Set optional namespace_type + if utils.IsKnown(plan.NamespaceType) { + nsType := kbapi.SecurityExceptionsAPIExceptionNamespaceType(plan.NamespaceType.ValueString()) + body.NamespaceType = &nsType + } + + // Set optional os_types + if utils.IsKnown(plan.OsTypes) && !plan.OsTypes.IsNull() { + var osTypes []string + diags := plan.OsTypes.ElementsAs(ctx, &osTypes, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if len(osTypes) > 0 { + osTypesArray := make(kbapi.SecurityExceptionsAPIExceptionListOsTypeArray, len(osTypes)) + for i, osType := range osTypes { + osTypesArray[i] = kbapi.SecurityExceptionsAPIExceptionListOsType(osType) + } + body.OsTypes = &osTypesArray + } + } + + // Set optional tags + if utils.IsKnown(plan.Tags) && !plan.Tags.IsNull() { + var tags []string + diags := plan.Tags.ElementsAs(ctx, &tags, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if len(tags) > 0 { + tagsArray := kbapi.SecurityExceptionsAPIExceptionListTags(tags) + body.Tags = &tagsArray + } + } + + // Set optional meta + if utils.IsKnown(plan.Meta) && !plan.Meta.IsNull() { + var meta kbapi.SecurityExceptionsAPIExceptionListMeta + if err := json.Unmarshal([]byte(plan.Meta.ValueString()), &meta); err != nil { + resp.Diagnostics.AddError("Failed to parse meta JSON", err.Error()) + return + } + body.Meta = &meta + } + + // Create the exception list + createResp, diags := kibana_oapi.CreateExceptionList(ctx, client, body) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if createResp == nil || createResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to create exception list", "API returned empty response") + return + } + + // Read back the created resource to get computed fields + readParams := &kbapi.ReadExceptionListParams{ + Id: (*kbapi.SecurityExceptionsAPIExceptionListId)(&createResp.JSON200.Id), + } + + readResp, diags := kibana_oapi.GetExceptionList(ctx, client, readParams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to read created exception list", "API returned empty response") + return + } + + // Update state with response + diags = r.updateStateFromAPIResponse(ctx, &plan, readResp.JSON200) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) +} + +func (r *ExceptionListResource) updateStateFromAPIResponse(ctx context.Context, model *ExceptionListModel, apiResp *kbapi.SecurityExceptionsAPIExceptionList) diag.Diagnostics { + var diags diag.Diagnostics + + model.ID = types.StringValue(string(apiResp.Id)) + model.ListID = types.StringValue(string(apiResp.ListId)) + model.Name = types.StringValue(string(apiResp.Name)) + model.Description = types.StringValue(string(apiResp.Description)) + model.Type = types.StringValue(string(apiResp.Type)) + model.NamespaceType = types.StringValue(string(apiResp.NamespaceType)) + model.CreatedAt = types.StringValue(apiResp.CreatedAt.Format("2006-01-02T15:04:05.000Z")) + model.CreatedBy = types.StringValue(apiResp.CreatedBy) + model.UpdatedAt = types.StringValue(apiResp.UpdatedAt.Format("2006-01-02T15:04:05.000Z")) + model.UpdatedBy = types.StringValue(apiResp.UpdatedBy) + model.Immutable = types.BoolValue(apiResp.Immutable) + model.TieBreakerID = types.StringValue(apiResp.TieBreakerId) + + // Set version if present + if apiResp.UnderscoreVersion != nil { + // Parse version string to int64 + var version int64 + model.Version = types.Int64Value(version) + } else { + model.Version = types.Int64Null() + } + + // Set optional os_types + if apiResp.OsTypes != nil && len(*apiResp.OsTypes) > 0 { + osTypes := make([]string, len(*apiResp.OsTypes)) + for i, osType := range *apiResp.OsTypes { + osTypes[i] = string(osType) + } + list, d := types.ListValueFrom(ctx, types.StringType, osTypes) + diags.Append(d...) + model.OsTypes = list + } else { + model.OsTypes = types.ListNull(types.StringType) + } + + // Set optional tags + if apiResp.Tags != nil && len(*apiResp.Tags) > 0 { + list, d := types.ListValueFrom(ctx, types.StringType, *apiResp.Tags) + diags.Append(d...) + model.Tags = list + } else { + model.Tags = types.ListNull(types.StringType) + } + + // Set optional meta + if apiResp.Meta != nil { + metaJSON, err := json.Marshal(apiResp.Meta) + if err != nil { + diags.AddError("Failed to serialize meta", err.Error()) + return diags + } + model.Meta = types.StringValue(string(metaJSON)) + } else { + model.Meta = types.StringNull() + } + + return diags +} diff --git a/internal/kibana/security/exception_list/delete.go b/internal/kibana/security/exception_list/delete.go new file mode 100644 index 000000000..a52571c68 --- /dev/null +++ b/internal/kibana/security/exception_list/delete.go @@ -0,0 +1,34 @@ +package exception_list + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *ExceptionListResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state ExceptionListModel + + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Delete by ID + id := kbapi.SecurityExceptionsAPIExceptionListId(state.ID.ValueString()) + params := &kbapi.DeleteExceptionListParams{ + Id: &id, + } + + diags = kibana_oapi.DeleteExceptionList(ctx, client, params) + resp.Diagnostics.Append(diags...) +} diff --git a/internal/kibana/security/exception_list/models.go b/internal/kibana/security/exception_list/models.go new file mode 100644 index 000000000..68e2d7e7a --- /dev/null +++ b/internal/kibana/security/exception_list/models.go @@ -0,0 +1,24 @@ +package exception_list + +import ( + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ExceptionListModel struct { + ID types.String `tfsdk:"id"` + ListID types.String `tfsdk:"list_id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Type types.String `tfsdk:"type"` + NamespaceType types.String `tfsdk:"namespace_type"` + OsTypes types.List `tfsdk:"os_types"` + Tags types.List `tfsdk:"tags"` + Meta types.String `tfsdk:"meta"` + Version types.Int64 `tfsdk:"version"` + CreatedAt types.String `tfsdk:"created_at"` + CreatedBy types.String `tfsdk:"created_by"` + UpdatedAt types.String `tfsdk:"updated_at"` + UpdatedBy types.String `tfsdk:"updated_by"` + Immutable types.Bool `tfsdk:"immutable"` + TieBreakerID types.String `tfsdk:"tie_breaker_id"` +} diff --git a/internal/kibana/security/exception_list/read.go b/internal/kibana/security/exception_list/read.go new file mode 100644 index 000000000..e62b45fbd --- /dev/null +++ b/internal/kibana/security/exception_list/read.go @@ -0,0 +1,52 @@ +package exception_list + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *ExceptionListResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state ExceptionListModel + + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Read by ID + id := kbapi.SecurityExceptionsAPIExceptionListId(state.ID.ValueString()) + params := &kbapi.ReadExceptionListParams{ + Id: &id, + } + + readResp, diags := kibana_oapi.GetExceptionList(ctx, client, params) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Update state with response + diags = r.updateStateFromAPIResponse(ctx, &state, readResp.JSON200) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, state) + resp.Diagnostics.Append(diags...) +} diff --git a/internal/kibana/security/exception_list/resource-description.md b/internal/kibana/security/exception_list/resource-description.md new file mode 100644 index 000000000..2f3251c68 --- /dev/null +++ b/internal/kibana/security/exception_list/resource-description.md @@ -0,0 +1,17 @@ +Manages a Kibana Exception List. Exception lists are containers for exception items used to prevent security rules from generating alerts. + +See the [Kibana Exceptions API documentation](https://www.elastic.co/docs/api/doc/kibana/group/endpoint-security-exceptions-api) for more details. + +## Example Usage + +```terraform +resource "elasticstack_kibana_security_exception_list" "example" { + list_id = "my-exception-list" + name = "My Exception List" + description = "List of exceptions for security rules" + type = "detection" + namespace_type = "single" + + tags = ["tag1", "tag2"] +} +``` diff --git a/internal/kibana/security/exception_list/resource.go b/internal/kibana/security/exception_list/resource.go new file mode 100644 index 000000000..2ed91ad91 --- /dev/null +++ b/internal/kibana/security/exception_list/resource.go @@ -0,0 +1,40 @@ +package exception_list + +import ( + "context" + "fmt" + + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var ( + _ resource.Resource = &ExceptionListResource{} + _ resource.ResourceWithConfigure = &ExceptionListResource{} + _ resource.ResourceWithImportState = &ExceptionListResource{} +) + +// NewResource is a helper function to simplify the provider implementation. +func NewResource() resource.Resource { + return &ExceptionListResource{} +} + +type ExceptionListResource struct { + client *clients.ApiClient +} + +func (r *ExceptionListResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + client, diags := clients.ConvertProviderData(req.ProviderData) + resp.Diagnostics.Append(diags...) + r.client = client +} + +// Metadata returns the provider type name. +func (r *ExceptionListResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = fmt.Sprintf("%s_%s", req.ProviderTypeName, "kibana_security_exception_list") +} + +func (r *ExceptionListResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response) +} diff --git a/internal/kibana/security/exception_list/schema.go b/internal/kibana/security/exception_list/schema.go new file mode 100644 index 000000000..16b49997e --- /dev/null +++ b/internal/kibana/security/exception_list/schema.go @@ -0,0 +1,119 @@ +package exception_list + +import ( + "context" + _ "embed" + + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +//go:embed resource-description.md +var exceptionListResourceDescription string + +func (r *ExceptionListResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: exceptionListResourceDescription, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The unique identifier of the exception list (auto-generated by Kibana).", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "list_id": schema.StringAttribute{ + MarkdownDescription: "The exception list's human readable string identifier.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "The name of the exception list.", + Required: true, + }, + "description": schema.StringAttribute{ + MarkdownDescription: "Describes the exception list.", + Required: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "The type of exception list. Can be one of: `detection`, `endpoint`, `endpoint_trusted_apps`, `endpoint_events`, `endpoint_host_isolation_exceptions`, `endpoint_blocklists`.", + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf( + "detection", + "endpoint", + "endpoint_trusted_apps", + "endpoint_events", + "endpoint_host_isolation_exceptions", + "endpoint_blocklists", + ), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "namespace_type": schema.StringAttribute{ + MarkdownDescription: "Determines whether the exception list is available in all Kibana spaces or just the space in which it is created. Can be `single` (default) or `agnostic`.", + Optional: true, + Computed: true, + Default: stringdefault.StaticString("single"), + Validators: []validator.String{ + stringvalidator.OneOf("single", "agnostic"), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "os_types": schema.ListAttribute{ + MarkdownDescription: "Array of OS types for which the exceptions apply. Valid values: `linux`, `macos`, `windows`.", + Optional: true, + ElementType: types.StringType, + }, + "tags": schema.ListAttribute{ + MarkdownDescription: "String array containing words and phrases to help categorize exception containers.", + Optional: true, + ElementType: types.StringType, + }, + "meta": schema.StringAttribute{ + MarkdownDescription: "Placeholder for metadata about the list container as JSON string.", + Optional: true, + }, + "version": schema.Int64Attribute{ + MarkdownDescription: "The version of the exception list.", + Computed: true, + }, + "created_at": schema.StringAttribute{ + MarkdownDescription: "The timestamp of when the exception list was created.", + Computed: true, + }, + "created_by": schema.StringAttribute{ + MarkdownDescription: "The user who created the exception list.", + Computed: true, + }, + "updated_at": schema.StringAttribute{ + MarkdownDescription: "The timestamp of when the exception list was last updated.", + Computed: true, + }, + "updated_by": schema.StringAttribute{ + MarkdownDescription: "The user who last updated the exception list.", + Computed: true, + }, + "immutable": schema.BoolAttribute{ + MarkdownDescription: "Whether the exception list is immutable.", + Computed: true, + }, + "tie_breaker_id": schema.StringAttribute{ + MarkdownDescription: "Field used in search to ensure all containers are sorted and returned correctly.", + Computed: true, + }, + }, + } +} diff --git a/internal/kibana/security/exception_list/update.go b/internal/kibana/security/exception_list/update.go new file mode 100644 index 000000000..224753739 --- /dev/null +++ b/internal/kibana/security/exception_list/update.go @@ -0,0 +1,104 @@ +package exception_list + +import ( + "context" + "encoding/json" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *ExceptionListResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan ExceptionListModel + + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Build the update request body + id := kbapi.SecurityExceptionsAPIExceptionListId(plan.ID.ValueString()) + body := kbapi.UpdateExceptionListJSONRequestBody{ + Id: &id, + Name: kbapi.SecurityExceptionsAPIExceptionListName(plan.Name.ValueString()), + Description: kbapi.SecurityExceptionsAPIExceptionListDescription(plan.Description.ValueString()), + } + + // Set optional namespace_type (should not change, but include it) + if utils.IsKnown(plan.NamespaceType) { + nsType := kbapi.SecurityExceptionsAPIExceptionNamespaceType(plan.NamespaceType.ValueString()) + body.NamespaceType = &nsType + } + + // Set optional os_types + if utils.IsKnown(plan.OsTypes) && !plan.OsTypes.IsNull() { + var osTypes []string + diags := plan.OsTypes.ElementsAs(ctx, &osTypes, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if len(osTypes) > 0 { + osTypesArray := make(kbapi.SecurityExceptionsAPIExceptionListOsTypeArray, len(osTypes)) + for i, osType := range osTypes { + osTypesArray[i] = kbapi.SecurityExceptionsAPIExceptionListOsType(osType) + } + body.OsTypes = &osTypesArray + } + } + + // Set optional tags + if utils.IsKnown(plan.Tags) && !plan.Tags.IsNull() { + var tags []string + diags := plan.Tags.ElementsAs(ctx, &tags, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if len(tags) > 0 { + tagsArray := kbapi.SecurityExceptionsAPIExceptionListTags(tags) + body.Tags = &tagsArray + } + } + + // Set optional meta + if utils.IsKnown(plan.Meta) && !plan.Meta.IsNull() { + var meta kbapi.SecurityExceptionsAPIExceptionListMeta + if err := json.Unmarshal([]byte(plan.Meta.ValueString()), &meta); err != nil { + resp.Diagnostics.AddError("Failed to parse meta JSON", err.Error()) + return + } + body.Meta = &meta + } + + // Update the exception list + updateResp, diags := kibana_oapi.UpdateExceptionList(ctx, client, body) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if updateResp == nil || updateResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to update exception list", "API returned empty response") + return + } + + // Update state with response + diags = r.updateStateFromAPIResponse(ctx, &plan, updateResp.JSON200) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) +} diff --git a/provider/plugin_framework.go b/provider/plugin_framework.go index 14a0d9939..ba48ece74 100644 --- a/provider/plugin_framework.go +++ b/provider/plugin_framework.go @@ -29,6 +29,8 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/kibana/export_saved_objects" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/import_saved_objects" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/maintenance_window" + "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/exception_item" + "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/exception_list" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security_detection_rule" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/spaces" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/synthetics/monitor" @@ -127,6 +129,8 @@ func (p *Provider) Resources(ctx context.Context) []func() resource.Resource { datafeed.NewDatafeedResource, anomaly_detection_job.NewAnomalyDetectionJobResource, security_detection_rule.NewSecurityDetectionRuleResource, + exception_list.NewResource, + exception_item.NewResource, job_state.NewMLJobStateResource, } } From 2d7850b815de7363eccb84afd9e3c4e5bd2f4380 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:50:42 +0000 Subject: [PATCH 03/21] Add examples, documentation templates, and acceptance tests for exception resources Co-authored-by: nick-benoit <163016768+nick-benoit@users.noreply.github.com> --- .../kibana_security_exception_item.md | 74 +++++++++++ .../kibana_security_exception_list.md | 29 +++++ .../resource.tf | 29 +++++ .../resource_complex.tf | 35 ++++++ .../resource.tf | 9 ++ .../resource_endpoint.tf | 10 ++ .../security/exception_item/acc_test.go | 117 ++++++++++++++++++ .../security/exception_list/acc_test.go | 80 ++++++++++++ .../kibana_security_exception_item.md.tmpl | 49 ++++++++ .../kibana_security_exception_list.md.tmpl | 49 ++++++++ 10 files changed, 481 insertions(+) create mode 100644 examples/resources/elasticstack_kibana_security_exception_item/resource.tf create mode 100644 examples/resources/elasticstack_kibana_security_exception_item/resource_complex.tf create mode 100644 examples/resources/elasticstack_kibana_security_exception_list/resource.tf create mode 100644 examples/resources/elasticstack_kibana_security_exception_list/resource_endpoint.tf create mode 100644 internal/kibana/security/exception_item/acc_test.go create mode 100644 internal/kibana/security/exception_list/acc_test.go create mode 100644 templates/resources/kibana_security_exception_item.md.tmpl create mode 100644 templates/resources/kibana_security_exception_list.md.tmpl diff --git a/docs/resources/kibana_security_exception_item.md b/docs/resources/kibana_security_exception_item.md index 9cf8a9c8c..0070bf7e7 100644 --- a/docs/resources/kibana_security_exception_item.md +++ b/docs/resources/kibana_security_exception_item.md @@ -58,7 +58,81 @@ resource "elasticstack_kibana_security_exception_item" "example" { } ``` +## Example Usage + +### Basic exception item + +```terraform +resource "elasticstack_kibana_security_exception_list" "example" { + list_id = "my-exception-list" + name = "My Exception List" + description = "List of exceptions for security rules" + type = "detection" + namespace_type = "single" + + tags = ["security", "detections"] +} + +resource "elasticstack_kibana_security_exception_item" "example" { + list_id = elasticstack_kibana_security_exception_list.example.list_id + item_id = "my-exception-item" + name = "My Exception Item" + description = "Exclude specific processes from alerts" + type = "simple" + namespace_type = "single" + entries = jsonencode([ + { + field = "process.name" + operator = "included" + type = "match" + value = "trusted-process" + } + ]) + + tags = ["trusted", "whitelisted"] +} +``` + +### Complex exception item with multiple entries + +```terraform +resource "elasticstack_kibana_security_exception_list" "example" { + list_id = "my-exception-list" + name = "My Exception List" + description = "List of exceptions" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "complex_entry" { + list_id = elasticstack_kibana_security_exception_list.example.list_id + item_id = "complex-exception" + name = "Complex Exception with Multiple Entries" + description = "Exception with multiple conditions" + type = "simple" + namespace_type = "single" + + # Multiple entries with different operators + entries = jsonencode([ + { + field = "host.name" + operator = "included" + type = "match" + value = "trusted-host" + }, + { + field = "user.name" + operator = "excluded" + type = "match_any" + value = ["admin", "root"] + } + ]) + + os_types = ["linux"] + tags = ["complex", "multi-condition"] +} +``` ## Schema diff --git a/docs/resources/kibana_security_exception_list.md b/docs/resources/kibana_security_exception_list.md index 01319e4f1..7f9bfe4f9 100644 --- a/docs/resources/kibana_security_exception_list.md +++ b/docs/resources/kibana_security_exception_list.md @@ -38,7 +38,36 @@ resource "elasticstack_kibana_security_exception_list" "example" { } ``` +## Example Usage + +### Basic exception list + +```terraform +resource "elasticstack_kibana_security_exception_list" "example" { + list_id = "my-detection-exception-list" + name = "My Detection Exception List" + description = "List of exceptions for security detection rules" + type = "detection" + namespace_type = "single" + + tags = ["security", "detections"] +} +``` +### Endpoint exception list with OS types + +```terraform +resource "elasticstack_kibana_security_exception_list" "endpoint" { + list_id = "my-endpoint-exception-list" + name = "My Endpoint Exception List" + description = "List of endpoint exceptions" + type = "endpoint" + namespace_type = "agnostic" + + os_types = ["linux", "windows", "macos"] + tags = ["endpoint", "security"] +} +``` ## Schema diff --git a/examples/resources/elasticstack_kibana_security_exception_item/resource.tf b/examples/resources/elasticstack_kibana_security_exception_item/resource.tf new file mode 100644 index 000000000..f336342f0 --- /dev/null +++ b/examples/resources/elasticstack_kibana_security_exception_item/resource.tf @@ -0,0 +1,29 @@ +resource "elasticstack_kibana_security_exception_list" "example" { + list_id = "my-exception-list" + name = "My Exception List" + description = "List of exceptions for security rules" + type = "detection" + namespace_type = "single" + + tags = ["security", "detections"] +} + +resource "elasticstack_kibana_security_exception_item" "example" { + list_id = elasticstack_kibana_security_exception_list.example.list_id + item_id = "my-exception-item" + name = "My Exception Item" + description = "Exclude specific processes from alerts" + type = "simple" + namespace_type = "single" + + entries = jsonencode([ + { + field = "process.name" + operator = "included" + type = "match" + value = "trusted-process" + } + ]) + + tags = ["trusted", "whitelisted"] +} diff --git a/examples/resources/elasticstack_kibana_security_exception_item/resource_complex.tf b/examples/resources/elasticstack_kibana_security_exception_item/resource_complex.tf new file mode 100644 index 000000000..d66717a51 --- /dev/null +++ b/examples/resources/elasticstack_kibana_security_exception_item/resource_complex.tf @@ -0,0 +1,35 @@ +resource "elasticstack_kibana_security_exception_list" "example" { + list_id = "my-exception-list" + name = "My Exception List" + description = "List of exceptions" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "complex_entry" { + list_id = elasticstack_kibana_security_exception_list.example.list_id + item_id = "complex-exception" + name = "Complex Exception with Multiple Entries" + description = "Exception with multiple conditions" + type = "simple" + namespace_type = "single" + + # Multiple entries with different operators + entries = jsonencode([ + { + field = "host.name" + operator = "included" + type = "match" + value = "trusted-host" + }, + { + field = "user.name" + operator = "excluded" + type = "match_any" + value = ["admin", "root"] + } + ]) + + os_types = ["linux"] + tags = ["complex", "multi-condition"] +} diff --git a/examples/resources/elasticstack_kibana_security_exception_list/resource.tf b/examples/resources/elasticstack_kibana_security_exception_list/resource.tf new file mode 100644 index 000000000..70c9805f0 --- /dev/null +++ b/examples/resources/elasticstack_kibana_security_exception_list/resource.tf @@ -0,0 +1,9 @@ +resource "elasticstack_kibana_security_exception_list" "example" { + list_id = "my-detection-exception-list" + name = "My Detection Exception List" + description = "List of exceptions for security detection rules" + type = "detection" + namespace_type = "single" + + tags = ["security", "detections"] +} diff --git a/examples/resources/elasticstack_kibana_security_exception_list/resource_endpoint.tf b/examples/resources/elasticstack_kibana_security_exception_list/resource_endpoint.tf new file mode 100644 index 000000000..2aaa604f3 --- /dev/null +++ b/examples/resources/elasticstack_kibana_security_exception_list/resource_endpoint.tf @@ -0,0 +1,10 @@ +resource "elasticstack_kibana_security_exception_list" "endpoint" { + list_id = "my-endpoint-exception-list" + name = "My Endpoint Exception List" + description = "List of endpoint exceptions" + type = "endpoint" + namespace_type = "agnostic" + + os_types = ["linux", "windows", "macos"] + tags = ["endpoint", "security"] +} diff --git a/internal/kibana/security/exception_item/acc_test.go b/internal/kibana/security/exception_item/acc_test.go new file mode 100644 index 000000000..2538e7012 --- /dev/null +++ b/internal/kibana/security/exception_item/acc_test.go @@ -0,0 +1,117 @@ +package exception_item_test + +import ( + "testing" + + "github.com/elastic/terraform-provider-elasticstack/internal/acctest" + "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" + "github.com/hashicorp/go-version" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +var minExceptionItemAPISupport = version.Must(version.NewVersion("7.9.0")) + +func TestAccResourceExceptionItem(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + Config: testAccResourceExceptionItemCreate, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "item_id", "test-exception-item"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "name", "Test Exception Item"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "description", "Test exception item for acceptance tests"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "type", "simple"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "namespace_type", "single"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "tags.0", "test"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_item.test", "id"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_item.test", "entries"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_item.test", "created_at"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_item.test", "created_by"), + ), + }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + Config: testAccResourceExceptionItemUpdate, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "name", "Test Exception Item Updated"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "description", "Updated description"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "tags.0", "test"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "tags.1", "updated"), + ), + }, + }, + }) +} + +const testAccResourceExceptionItemCreate = ` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = "test-exception-list-for-item" + name = "Test Exception List for Item" + description = "Test exception list" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = "test-exception-item" + name = "Test Exception Item" + description = "Test exception item for acceptance tests" + type = "simple" + namespace_type = "single" + + entries = jsonencode([ + { + field = "process.name" + operator = "included" + type = "match" + value = "test-process" + } + ]) + + tags = ["test"] +} +` + +const testAccResourceExceptionItemUpdate = ` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = "test-exception-list-for-item" + name = "Test Exception List for Item" + description = "Test exception list" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = "test-exception-item" + name = "Test Exception Item Updated" + description = "Updated description" + type = "simple" + namespace_type = "single" + + entries = jsonencode([ + { + field = "process.name" + operator = "included" + type = "match" + value = "test-process-updated" + } + ]) + + tags = ["test", "updated"] +} +` diff --git a/internal/kibana/security/exception_list/acc_test.go b/internal/kibana/security/exception_list/acc_test.go new file mode 100644 index 000000000..7d3027b9e --- /dev/null +++ b/internal/kibana/security/exception_list/acc_test.go @@ -0,0 +1,80 @@ +package exception_list_test + +import ( + "testing" + + "github.com/elastic/terraform-provider-elasticstack/internal/acctest" + "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" + "github.com/hashicorp/go-version" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +var minExceptionListAPISupport = version.Must(version.NewVersion("7.9.0")) + +func TestAccResourceExceptionList(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionListAPISupport), + Config: testAccResourceExceptionListCreate, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "list_id", "test-exception-list"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "name", "Test Exception List"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "description", "Test exception list for acceptance tests"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "type", "detection"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "namespace_type", "single"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "tags.0", "test"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_list.test", "id"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_list.test", "created_at"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_list.test", "created_by"), + ), + }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionListAPISupport), + Config: testAccResourceExceptionListUpdate, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "name", "Test Exception List Updated"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "description", "Updated description"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "tags.0", "test"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "tags.1", "updated"), + ), + }, + }, + }) +} + +const testAccResourceExceptionListCreate = ` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = "test-exception-list" + name = "Test Exception List" + description = "Test exception list for acceptance tests" + type = "detection" + namespace_type = "single" + + tags = ["test"] +} +` + +const testAccResourceExceptionListUpdate = ` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = "test-exception-list" + name = "Test Exception List Updated" + description = "Updated description" + type = "detection" + namespace_type = "single" + + tags = ["test", "updated"] +} +` diff --git a/templates/resources/kibana_security_exception_item.md.tmpl b/templates/resources/kibana_security_exception_item.md.tmpl new file mode 100644 index 000000000..a8ad6b6c0 --- /dev/null +++ b/templates/resources/kibana_security_exception_item.md.tmpl @@ -0,0 +1,49 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" +subcategory: "Kibana" +description: |- +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +### Basic exception item + +{{ tffile "examples/resources/elasticstack_kibana_security_exception_item/resource.tf" }} + +### Complex exception item with multiple entries + +{{ tffile "examples/resources/elasticstack_kibana_security_exception_item/resource_complex.tf" }} + +{{ .SchemaMarkdown | trimspace }} +{{- if or .HasImport .HasImportIDConfig .HasImportIdentityConfig }} + +## Import + +Import is supported using the following syntax: +{{- end }} +{{- if .HasImportIdentityConfig }} + +In Terraform v1.12.0 and later, the [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used with the `identity` attribute, for example: + +{{tffile .ImportIdentityConfigFile }} + +{{ .IdentitySchemaMarkdown | trimspace }} +{{- end }} +{{- if .HasImportIDConfig }} + +In Terraform v1.5.0 and later, the [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used with the `id` attribute, for example: + +{{tffile .ImportIDConfigFile }} +{{- end }} +{{- if .HasImport }} + +The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example: + +{{codefile "shell" .ImportFile }} +{{- end }} diff --git a/templates/resources/kibana_security_exception_list.md.tmpl b/templates/resources/kibana_security_exception_list.md.tmpl new file mode 100644 index 000000000..c6b737823 --- /dev/null +++ b/templates/resources/kibana_security_exception_list.md.tmpl @@ -0,0 +1,49 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" +subcategory: "Kibana" +description: |- +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +### Basic exception list + +{{ tffile "examples/resources/elasticstack_kibana_security_exception_list/resource.tf" }} + +### Endpoint exception list with OS types + +{{ tffile "examples/resources/elasticstack_kibana_security_exception_list/resource_endpoint.tf" }} + +{{ .SchemaMarkdown | trimspace }} +{{- if or .HasImport .HasImportIDConfig .HasImportIdentityConfig }} + +## Import + +Import is supported using the following syntax: +{{- end }} +{{- if .HasImportIdentityConfig }} + +In Terraform v1.12.0 and later, the [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used with the `identity` attribute, for example: + +{{tffile .ImportIdentityConfigFile }} + +{{ .IdentitySchemaMarkdown | trimspace }} +{{- end }} +{{- if .HasImportIDConfig }} + +In Terraform v1.5.0 and later, the [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used with the `id` attribute, for example: + +{{tffile .ImportIDConfigFile }} +{{- end }} +{{- if .HasImport }} + +The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example: + +{{codefile "shell" .ImportFile }} +{{- end }} From 2aa87dbf4e151e093d1326ee510f6c6363745da4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:55:58 +0000 Subject: [PATCH 04/21] Remove version field from exception_list as it's not in API response Co-authored-by: nick-benoit <163016768+nick-benoit@users.noreply.github.com> --- docs/resources/kibana_security_exception_list.md | 1 - internal/kibana/security/exception_list/create.go | 9 --------- internal/kibana/security/exception_list/models.go | 1 - internal/kibana/security/exception_list/schema.go | 4 ---- 4 files changed, 15 deletions(-) diff --git a/docs/resources/kibana_security_exception_list.md b/docs/resources/kibana_security_exception_list.md index 7f9bfe4f9..5e597712f 100644 --- a/docs/resources/kibana_security_exception_list.md +++ b/docs/resources/kibana_security_exception_list.md @@ -95,4 +95,3 @@ resource "elasticstack_kibana_security_exception_list" "endpoint" { - `tie_breaker_id` (String) Field used in search to ensure all containers are sorted and returned correctly. - `updated_at` (String) The timestamp of when the exception list was last updated. - `updated_by` (String) The user who last updated the exception list. -- `version` (Number) The version of the exception list. diff --git a/internal/kibana/security/exception_list/create.go b/internal/kibana/security/exception_list/create.go index 174b80409..d45ce7f8e 100644 --- a/internal/kibana/security/exception_list/create.go +++ b/internal/kibana/security/exception_list/create.go @@ -137,15 +137,6 @@ func (r *ExceptionListResource) updateStateFromAPIResponse(ctx context.Context, model.Immutable = types.BoolValue(apiResp.Immutable) model.TieBreakerID = types.StringValue(apiResp.TieBreakerId) - // Set version if present - if apiResp.UnderscoreVersion != nil { - // Parse version string to int64 - var version int64 - model.Version = types.Int64Value(version) - } else { - model.Version = types.Int64Null() - } - // Set optional os_types if apiResp.OsTypes != nil && len(*apiResp.OsTypes) > 0 { osTypes := make([]string, len(*apiResp.OsTypes)) diff --git a/internal/kibana/security/exception_list/models.go b/internal/kibana/security/exception_list/models.go index 68e2d7e7a..a0f8925f0 100644 --- a/internal/kibana/security/exception_list/models.go +++ b/internal/kibana/security/exception_list/models.go @@ -14,7 +14,6 @@ type ExceptionListModel struct { OsTypes types.List `tfsdk:"os_types"` Tags types.List `tfsdk:"tags"` Meta types.String `tfsdk:"meta"` - Version types.Int64 `tfsdk:"version"` CreatedAt types.String `tfsdk:"created_at"` CreatedBy types.String `tfsdk:"created_by"` UpdatedAt types.String `tfsdk:"updated_at"` diff --git a/internal/kibana/security/exception_list/schema.go b/internal/kibana/security/exception_list/schema.go index 16b49997e..041756cb1 100644 --- a/internal/kibana/security/exception_list/schema.go +++ b/internal/kibana/security/exception_list/schema.go @@ -86,10 +86,6 @@ func (r *ExceptionListResource) Schema(_ context.Context, _ resource.SchemaReque MarkdownDescription: "Placeholder for metadata about the list container as JSON string.", Optional: true, }, - "version": schema.Int64Attribute{ - MarkdownDescription: "The version of the exception list.", - Computed: true, - }, "created_at": schema.StringAttribute{ MarkdownDescription: "The timestamp of when the exception list was created.", Computed: true, From c84195fca608ed2d451fac78756d6765d886aba7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:59:31 +0000 Subject: [PATCH 05/21] Remove duplicate examples from resource descriptions to fix doc duplication Co-authored-by: nick-benoit <163016768+nick-benoit@users.noreply.github.com> --- .../kibana_security_exception_item.md | 45 ------------------- .../kibana_security_exception_list.md | 25 ----------- .../exception_item/resource-description.md | 24 ---------- .../exception_list/resource-description.md | 14 ------ 4 files changed, 108 deletions(-) diff --git a/docs/resources/kibana_security_exception_item.md b/docs/resources/kibana_security_exception_item.md index 0070bf7e7..4dd0ab786 100644 --- a/docs/resources/kibana_security_exception_item.md +++ b/docs/resources/kibana_security_exception_item.md @@ -5,27 +5,6 @@ subcategory: "Kibana" description: |- Manages a Kibana Exception Item. Exception items define the specific query conditions used to prevent rules from generating alerts. See the Kibana Exceptions API documentation https://www.elastic.co/docs/api/doc/kibana/group/endpoint-security-exceptions-api for more details. - Example Usage - - resource "elasticstack_kibana_security_exception_item" "example" { - list_id = elasticstack_kibana_security_exception_list.example.list_id - item_id = "my-exception-item" - name = "My Exception Item" - description = "Exclude specific processes from alerts" - type = "simple" - namespace_type = "single" - - entries = jsonencode([ - { - field = "process.name" - operator = "included" - type = "match" - value = "my-process" - } - ]) - - tags = ["tag1", "tag2"] - } --- # elasticstack_kibana_security_exception_item (Resource) @@ -36,30 +15,6 @@ See the [Kibana Exceptions API documentation](https://www.elastic.co/docs/api/do ## Example Usage -```terraform -resource "elasticstack_kibana_security_exception_item" "example" { - list_id = elasticstack_kibana_security_exception_list.example.list_id - item_id = "my-exception-item" - name = "My Exception Item" - description = "Exclude specific processes from alerts" - type = "simple" - namespace_type = "single" - - entries = jsonencode([ - { - field = "process.name" - operator = "included" - type = "match" - value = "my-process" - } - ]) - - tags = ["tag1", "tag2"] -} -``` - -## Example Usage - ### Basic exception item ```terraform diff --git a/docs/resources/kibana_security_exception_list.md b/docs/resources/kibana_security_exception_list.md index 5e597712f..c29101c93 100644 --- a/docs/resources/kibana_security_exception_list.md +++ b/docs/resources/kibana_security_exception_list.md @@ -5,17 +5,6 @@ subcategory: "Kibana" description: |- Manages a Kibana Exception List. Exception lists are containers for exception items used to prevent security rules from generating alerts. See the Kibana Exceptions API documentation https://www.elastic.co/docs/api/doc/kibana/group/endpoint-security-exceptions-api for more details. - Example Usage - - resource "elasticstack_kibana_security_exception_list" "example" { - list_id = "my-exception-list" - name = "My Exception List" - description = "List of exceptions for security rules" - type = "detection" - namespace_type = "single" - - tags = ["tag1", "tag2"] - } --- # elasticstack_kibana_security_exception_list (Resource) @@ -26,20 +15,6 @@ See the [Kibana Exceptions API documentation](https://www.elastic.co/docs/api/do ## Example Usage -```terraform -resource "elasticstack_kibana_security_exception_list" "example" { - list_id = "my-exception-list" - name = "My Exception List" - description = "List of exceptions for security rules" - type = "detection" - namespace_type = "single" - - tags = ["tag1", "tag2"] -} -``` - -## Example Usage - ### Basic exception list ```terraform diff --git a/internal/kibana/security/exception_item/resource-description.md b/internal/kibana/security/exception_item/resource-description.md index 8aa5b436a..7ad7c0a47 100644 --- a/internal/kibana/security/exception_item/resource-description.md +++ b/internal/kibana/security/exception_item/resource-description.md @@ -1,27 +1,3 @@ Manages a Kibana Exception Item. Exception items define the specific query conditions used to prevent rules from generating alerts. See the [Kibana Exceptions API documentation](https://www.elastic.co/docs/api/doc/kibana/group/endpoint-security-exceptions-api) for more details. - -## Example Usage - -```terraform -resource "elasticstack_kibana_security_exception_item" "example" { - list_id = elasticstack_kibana_security_exception_list.example.list_id - item_id = "my-exception-item" - name = "My Exception Item" - description = "Exclude specific processes from alerts" - type = "simple" - namespace_type = "single" - - entries = jsonencode([ - { - field = "process.name" - operator = "included" - type = "match" - value = "my-process" - } - ]) - - tags = ["tag1", "tag2"] -} -``` diff --git a/internal/kibana/security/exception_list/resource-description.md b/internal/kibana/security/exception_list/resource-description.md index 2f3251c68..d773a038b 100644 --- a/internal/kibana/security/exception_list/resource-description.md +++ b/internal/kibana/security/exception_list/resource-description.md @@ -1,17 +1,3 @@ Manages a Kibana Exception List. Exception lists are containers for exception items used to prevent security rules from generating alerts. See the [Kibana Exceptions API documentation](https://www.elastic.co/docs/api/doc/kibana/group/endpoint-security-exceptions-api) for more details. - -## Example Usage - -```terraform -resource "elasticstack_kibana_security_exception_list" "example" { - list_id = "my-exception-list" - name = "My Exception List" - description = "List of exceptions for security rules" - type = "detection" - namespace_type = "single" - - tags = ["tag1", "tag2"] -} -``` From 216089e203eae193d7c275ef6fb36b7b21be5a62 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 19:52:33 +0000 Subject: [PATCH 06/21] Fix acceptance test failures: add Type field to update and use jsontypes.Normalized for entries - Add missing Type field to exception_list update operation - Change entries field to use jsontypes.Normalized to handle JSON key ordering differences - This fixes the "received ''" error and "inconsistent result" errors in acceptance tests Co-authored-by: nick-benoit <163016768+nick-benoit@users.noreply.github.com> --- .../kibana/security/exception_item/create.go | 5 ++- .../kibana/security/exception_item/models.go | 37 ++++++++++--------- .../kibana/security/exception_item/schema.go | 2 + .../kibana/security/exception_list/update.go | 1 + 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/internal/kibana/security/exception_item/create.go b/internal/kibana/security/exception_item/create.go index c93d4b669..e52f9e6f6 100644 --- a/internal/kibana/security/exception_item/create.go +++ b/internal/kibana/security/exception_item/create.go @@ -8,6 +8,7 @@ import ( "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -224,13 +225,13 @@ func (r *ExceptionItemResource) updateStateFromAPIResponse(ctx context.Context, model.Meta = types.StringNull() } - // Set entries (convert back to JSON) + // Set entries (convert back to JSON and normalize) entriesJSON, err := json.Marshal(apiResp.Entries) if err != nil { diags.AddError("Failed to serialize entries", err.Error()) return diags } - model.Entries = types.StringValue(string(entriesJSON)) + model.Entries = jsontypes.NewNormalizedValue(string(entriesJSON)) // Set optional comments if len(apiResp.Comments) > 0 { diff --git a/internal/kibana/security/exception_item/models.go b/internal/kibana/security/exception_item/models.go index 16735a13b..4152fa484 100644 --- a/internal/kibana/security/exception_item/models.go +++ b/internal/kibana/security/exception_item/models.go @@ -1,28 +1,29 @@ package exception_item import ( + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework/types" ) type ExceptionItemModel struct { - ID types.String `tfsdk:"id"` - ItemID types.String `tfsdk:"item_id"` - ListID types.String `tfsdk:"list_id"` - Name types.String `tfsdk:"name"` - Description types.String `tfsdk:"description"` - Type types.String `tfsdk:"type"` - NamespaceType types.String `tfsdk:"namespace_type"` - OsTypes types.List `tfsdk:"os_types"` - Tags types.List `tfsdk:"tags"` - Meta types.String `tfsdk:"meta"` - Entries types.String `tfsdk:"entries"` - Comments types.List `tfsdk:"comments"` - ExpireTime types.String `tfsdk:"expire_time"` - CreatedAt types.String `tfsdk:"created_at"` - CreatedBy types.String `tfsdk:"created_by"` - UpdatedAt types.String `tfsdk:"updated_at"` - UpdatedBy types.String `tfsdk:"updated_by"` - TieBreakerID types.String `tfsdk:"tie_breaker_id"` + ID types.String `tfsdk:"id"` + ItemID types.String `tfsdk:"item_id"` + ListID types.String `tfsdk:"list_id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Type types.String `tfsdk:"type"` + NamespaceType types.String `tfsdk:"namespace_type"` + OsTypes types.List `tfsdk:"os_types"` + Tags types.List `tfsdk:"tags"` + Meta types.String `tfsdk:"meta"` + Entries jsontypes.Normalized `tfsdk:"entries"` + Comments types.List `tfsdk:"comments"` + ExpireTime types.String `tfsdk:"expire_time"` + CreatedAt types.String `tfsdk:"created_at"` + CreatedBy types.String `tfsdk:"created_by"` + UpdatedAt types.String `tfsdk:"updated_at"` + UpdatedBy types.String `tfsdk:"updated_by"` + TieBreakerID types.String `tfsdk:"tie_breaker_id"` } type CommentModel struct { diff --git a/internal/kibana/security/exception_item/schema.go b/internal/kibana/security/exception_item/schema.go index 1c904023b..891eb7465 100644 --- a/internal/kibana/security/exception_item/schema.go +++ b/internal/kibana/security/exception_item/schema.go @@ -4,6 +4,7 @@ import ( "context" _ "embed" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -91,6 +92,7 @@ func (r *ExceptionItemResource) Schema(_ context.Context, _ resource.SchemaReque "entries": schema.StringAttribute{ MarkdownDescription: "The exception item entries as JSON string. This defines the conditions under which the exception applies.", Required: true, + CustomType: jsontypes.NormalizedType{}, }, "comments": schema.ListNestedAttribute{ MarkdownDescription: "Array of comments about the exception item.", diff --git a/internal/kibana/security/exception_list/update.go b/internal/kibana/security/exception_list/update.go index 224753739..25456795c 100644 --- a/internal/kibana/security/exception_list/update.go +++ b/internal/kibana/security/exception_list/update.go @@ -31,6 +31,7 @@ func (r *ExceptionListResource) Update(ctx context.Context, req resource.UpdateR Id: &id, Name: kbapi.SecurityExceptionsAPIExceptionListName(plan.Name.ValueString()), Description: kbapi.SecurityExceptionsAPIExceptionListDescription(plan.Description.ValueString()), + Type: kbapi.SecurityExceptionsAPIExceptionListType(plan.Type.ValueString()), } // Set optional namespace_type (should not change, but include it) From 06bcdaf1072522f3d63c852efa70a9d450f8ed81 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 21:18:35 +0000 Subject: [PATCH 07/21] Address code review feedback - Fix expire_time description to specify RFC3339 format instead of ISO format - Remove unnecessary read-back after create operations (use create response directly) - Add comment explaining why Type field is required in update despite RequiresReplace - All fields from generated client are now verified to be supported Co-authored-by: nick-benoit <163016768+nick-benoit@users.noreply.github.com> --- .../kibana_security_exception_item.md | 2 +- .../kibana/security/exception_item/create.go | 20 ++----------------- .../kibana/security/exception_item/schema.go | 2 +- .../kibana/security/exception_list/create.go | 20 ++----------------- .../kibana/security/exception_list/update.go | 4 +++- 5 files changed, 9 insertions(+), 39 deletions(-) diff --git a/docs/resources/kibana_security_exception_item.md b/docs/resources/kibana_security_exception_item.md index 4dd0ab786..9614d6d3d 100644 --- a/docs/resources/kibana_security_exception_item.md +++ b/docs/resources/kibana_security_exception_item.md @@ -103,7 +103,7 @@ resource "elasticstack_kibana_security_exception_item" "complex_entry" { ### Optional - `comments` (Attributes List) Array of comments about the exception item. (see [below for nested schema](#nestedatt--comments)) -- `expire_time` (String) The exception item's expiration date in ISO format. This field is only available for regular exception items, not endpoint exceptions. +- `expire_time` (String) The exception item's expiration date in RFC3339 format. This field is only available for regular exception items, not endpoint exceptions. - `item_id` (String) The exception item's human readable string identifier. - `meta` (String) Placeholder for metadata about the exception item as JSON string. - `namespace_type` (String) Determines whether the exception item is available in all Kibana spaces or just the space in which it is created. Can be `single` (default) or `agnostic`. diff --git a/internal/kibana/security/exception_item/create.go b/internal/kibana/security/exception_item/create.go index e52f9e6f6..90469dec8 100644 --- a/internal/kibana/security/exception_item/create.go +++ b/internal/kibana/security/exception_item/create.go @@ -141,24 +141,8 @@ func (r *ExceptionItemResource) Create(ctx context.Context, req resource.CreateR return } - // Read back the created resource to get computed fields - readParams := &kbapi.ReadExceptionListItemParams{ - Id: (*kbapi.SecurityExceptionsAPIExceptionListItemId)(&createResp.JSON200.Id), - } - - readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, readParams) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - - if readResp == nil || readResp.JSON200 == nil { - resp.Diagnostics.AddError("Failed to read created exception item", "API returned empty response") - return - } - - // Update state with response - diags = r.updateStateFromAPIResponse(ctx, &plan, readResp.JSON200) + // Update state with create response + diags = r.updateStateFromAPIResponse(ctx, &plan, createResp.JSON200) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return diff --git a/internal/kibana/security/exception_item/schema.go b/internal/kibana/security/exception_item/schema.go index 891eb7465..9bf1c33ae 100644 --- a/internal/kibana/security/exception_item/schema.go +++ b/internal/kibana/security/exception_item/schema.go @@ -111,7 +111,7 @@ func (r *ExceptionItemResource) Schema(_ context.Context, _ resource.SchemaReque }, }, "expire_time": schema.StringAttribute{ - MarkdownDescription: "The exception item's expiration date in ISO format. This field is only available for regular exception items, not endpoint exceptions.", + MarkdownDescription: "The exception item's expiration date in RFC3339 format. This field is only available for regular exception items, not endpoint exceptions.", Optional: true, }, "created_at": schema.StringAttribute{ diff --git a/internal/kibana/security/exception_list/create.go b/internal/kibana/security/exception_list/create.go index d45ce7f8e..b21529489 100644 --- a/internal/kibana/security/exception_list/create.go +++ b/internal/kibana/security/exception_list/create.go @@ -94,24 +94,8 @@ func (r *ExceptionListResource) Create(ctx context.Context, req resource.CreateR return } - // Read back the created resource to get computed fields - readParams := &kbapi.ReadExceptionListParams{ - Id: (*kbapi.SecurityExceptionsAPIExceptionListId)(&createResp.JSON200.Id), - } - - readResp, diags := kibana_oapi.GetExceptionList(ctx, client, readParams) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - - if readResp == nil || readResp.JSON200 == nil { - resp.Diagnostics.AddError("Failed to read created exception list", "API returned empty response") - return - } - - // Update state with response - diags = r.updateStateFromAPIResponse(ctx, &plan, readResp.JSON200) + // Update state with create response + diags = r.updateStateFromAPIResponse(ctx, &plan, createResp.JSON200) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return diff --git a/internal/kibana/security/exception_list/update.go b/internal/kibana/security/exception_list/update.go index 25456795c..e41e88d2f 100644 --- a/internal/kibana/security/exception_list/update.go +++ b/internal/kibana/security/exception_list/update.go @@ -31,7 +31,9 @@ func (r *ExceptionListResource) Update(ctx context.Context, req resource.UpdateR Id: &id, Name: kbapi.SecurityExceptionsAPIExceptionListName(plan.Name.ValueString()), Description: kbapi.SecurityExceptionsAPIExceptionListDescription(plan.Description.ValueString()), - Type: kbapi.SecurityExceptionsAPIExceptionListType(plan.Type.ValueString()), + // Type is required by the API even though it has RequiresReplace in the schema + // The API will reject updates without this field, even though the value cannot change + Type: kbapi.SecurityExceptionsAPIExceptionListType(plan.Type.ValueString()), } // Set optional namespace_type (should not change, but include it) From 21e6522d38b291dac025bbda93ce31e8c8419864 Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Thu, 20 Nov 2025 08:34:34 -0700 Subject: [PATCH 08/21] Add specification to get state from read requests to coding standareds --- CODING_STANDARDS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CODING_STANDARDS.md b/CODING_STANDARDS.md index df402caf2..c863aa64f 100644 --- a/CODING_STANDARDS.md +++ b/CODING_STANDARDS.md @@ -36,6 +36,7 @@ This document outlines the coding standards and conventions used in the terrafor - Prefer using existing util functions over longer form, duplicated code: - `utils.IsKnown(val)` instead of `!val.IsNull() && !val.IsUnknown()` - `utils.ListTypeAs` instead of `val.ElementsAs` or similar for other collection types +- The final state for a resource should be derived from a read request following a mutative request (eg create or update). We should not use the response from a mutative request to build the final resource state. ## Schema Definitions From 8d1a2b88827cd006bf4eeee7054edee52990ed1c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:45:32 +0000 Subject: [PATCH 09/21] Follow CODING_STANDARDS: read resource state after create/update operations Per CODING_STANDARDS.md line 39, the final state should be derived from a read request following a mutative request. Updated both exception_list and exception_item resources to perform a read after create and update operations, using the read response to build the final state rather than the mutative response. This ensures state consistency and avoids dirty plans after apply. Co-authored-by: nick-benoit <163016768+nick-benoit@users.noreply.github.com> --- .../kibana/security/exception_item/create.go | 24 +++++++++++++++++-- .../kibana/security/exception_item/update.go | 24 +++++++++++++++++-- .../kibana/security/exception_list/create.go | 24 +++++++++++++++++-- .../kibana/security/exception_list/update.go | 24 +++++++++++++++++-- 4 files changed, 88 insertions(+), 8 deletions(-) diff --git a/internal/kibana/security/exception_item/create.go b/internal/kibana/security/exception_item/create.go index 90469dec8..49ca87c7c 100644 --- a/internal/kibana/security/exception_item/create.go +++ b/internal/kibana/security/exception_item/create.go @@ -141,8 +141,28 @@ func (r *ExceptionItemResource) Create(ctx context.Context, req resource.CreateR return } - // Update state with create response - diags = r.updateStateFromAPIResponse(ctx, &plan, createResp.JSON200) + /* + * In create/update paths we typically follow the write operation with a read, and then set the state from the read. + * We want to avoid a dirty plan immediately after an apply. + */ + // Read back the created resource to get the final state + readParams := &kbapi.ReadExceptionListItemParams{ + Id: (*kbapi.SecurityExceptionsAPIExceptionListItemId)(&createResp.JSON200.Id), + } + + readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, readParams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Update state with read response + diags = r.updateStateFromAPIResponse(ctx, &plan, readResp.JSON200) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return diff --git a/internal/kibana/security/exception_item/update.go b/internal/kibana/security/exception_item/update.go index 22cdaa0a6..7891cf957 100644 --- a/internal/kibana/security/exception_item/update.go +++ b/internal/kibana/security/exception_item/update.go @@ -132,8 +132,28 @@ func (r *ExceptionItemResource) Update(ctx context.Context, req resource.UpdateR return } - // Update state with response - diags = r.updateStateFromAPIResponse(ctx, &plan, updateResp.JSON200) + /* + * In create/update paths we typically follow the write operation with a read, and then set the state from the read. + * We want to avoid a dirty plan immediately after an apply. + */ + // Read back the updated resource to get the final state + readParams := &kbapi.ReadExceptionListItemParams{ + Id: (*kbapi.SecurityExceptionsAPIExceptionListItemId)(&updateResp.JSON200.Id), + } + + readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, readParams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Update state with read response + diags = r.updateStateFromAPIResponse(ctx, &plan, readResp.JSON200) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return diff --git a/internal/kibana/security/exception_list/create.go b/internal/kibana/security/exception_list/create.go index b21529489..96d78180a 100644 --- a/internal/kibana/security/exception_list/create.go +++ b/internal/kibana/security/exception_list/create.go @@ -94,8 +94,28 @@ func (r *ExceptionListResource) Create(ctx context.Context, req resource.CreateR return } - // Update state with create response - diags = r.updateStateFromAPIResponse(ctx, &plan, createResp.JSON200) + /* + * In create/update paths we typically follow the write operation with a read, and then set the state from the read. + * We want to avoid a dirty plan immediately after an apply. + */ + // Read back the created resource to get the final state + readParams := &kbapi.ReadExceptionListParams{ + Id: (*kbapi.SecurityExceptionsAPIExceptionListId)(&createResp.JSON200.Id), + } + + readResp, diags := kibana_oapi.GetExceptionList(ctx, client, readParams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Update state with read response + diags = r.updateStateFromAPIResponse(ctx, &plan, readResp.JSON200) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return diff --git a/internal/kibana/security/exception_list/update.go b/internal/kibana/security/exception_list/update.go index e41e88d2f..c7f9b5196 100644 --- a/internal/kibana/security/exception_list/update.go +++ b/internal/kibana/security/exception_list/update.go @@ -95,8 +95,28 @@ func (r *ExceptionListResource) Update(ctx context.Context, req resource.UpdateR return } - // Update state with response - diags = r.updateStateFromAPIResponse(ctx, &plan, updateResp.JSON200) + /* + * In create/update paths we typically follow the write operation with a read, and then set the state from the read. + * We want to avoid a dirty plan immediately after an apply. + */ + // Read back the updated resource to get the final state + readParams := &kbapi.ReadExceptionListParams{ + Id: (*kbapi.SecurityExceptionsAPIExceptionListId)(&updateResp.JSON200.Id), + } + + readResp, diags := kibana_oapi.GetExceptionList(ctx, client, readParams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Update state with read response + diags = r.updateStateFromAPIResponse(ctx, &plan, readResp.JSON200) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return From 87c067629120369d40f91f41aad26a10c0325821 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:10:07 +0000 Subject: [PATCH 10/21] Refactor acceptance tests to use testdata directory structure Following the pattern in system_user/acc_test.go, refactored both exception_list and exception_item acceptance tests to: - Use separate testdata directories for each test case - Store Terraform configurations in .tf files instead of inline strings - Use ConfigDirectory and ConfigVariables instead of inline Config - Maintain the _test package suffix This improves test maintainability and consistency with other tests in the repository. Co-authored-by: nick-benoit <163016768+nick-benoit@users.noreply.github.com> --- .../security/exception_item/acc_test.go | 107 +++++------------- .../create/exception_item.tf | 63 +++++++++++ .../update/exception_item.tf | 63 +++++++++++ .../security/exception_list/acc_test.go | 64 ++++------- .../create/exception_list.tf | 43 +++++++ .../update/exception_list.tf | 43 +++++++ 6 files changed, 267 insertions(+), 116 deletions(-) create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf create mode 100644 internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/create/exception_list.tf create mode 100644 internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/update/exception_list.tf diff --git a/internal/kibana/security/exception_item/acc_test.go b/internal/kibana/security/exception_item/acc_test.go index 2538e7012..ae564a599 100644 --- a/internal/kibana/security/exception_item/acc_test.go +++ b/internal/kibana/security/exception_item/acc_test.go @@ -6,19 +6,33 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/acctest" "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" "github.com/hashicorp/go-version" + "github.com/hashicorp/terraform-plugin-testing/config" "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) var minExceptionItemAPISupport = version.Must(version.NewVersion("7.9.0")) func TestAccResourceExceptionItem(t *testing.T) { + entriesCreate := `[{"field":"process.name","operator":"included","type":"match","value":"test-process"}]` + entriesUpdate := `[{"field":"process.name","operator":"included","type":"match","value":"test-process-updated"}]` + resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.Providers, + PreCheck: func() { acctest.PreCheck(t) }, Steps: []resource.TestStep{ { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), - Config: testAccResourceExceptionItemCreate, + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("create"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable("test-exception-list-for-item"), + "item_id": config.StringVariable("test-exception-item"), + "name": config.StringVariable("Test Exception Item"), + "description": config.StringVariable("Test exception item for acceptance tests"), + "type": config.StringVariable("simple"), + "namespace_type": config.StringVariable("single"), + "entries": config.StringVariable(entriesCreate), + "tags": config.ListVariable(config.StringVariable("test")), + }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "item_id", "test-exception-item"), resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "name", "Test Exception Item"), @@ -33,8 +47,19 @@ func TestAccResourceExceptionItem(t *testing.T) { ), }, { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), - Config: testAccResourceExceptionItemUpdate, + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("update"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable("test-exception-list-for-item"), + "item_id": config.StringVariable("test-exception-item"), + "name": config.StringVariable("Test Exception Item Updated"), + "description": config.StringVariable("Updated description"), + "type": config.StringVariable("simple"), + "namespace_type": config.StringVariable("single"), + "entries": config.StringVariable(entriesUpdate), + "tags": config.ListVariable(config.StringVariable("test"), config.StringVariable("updated")), + }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "name", "Test Exception Item Updated"), resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "description", "Updated description"), @@ -45,73 +70,3 @@ func TestAccResourceExceptionItem(t *testing.T) { }, }) } - -const testAccResourceExceptionItemCreate = ` -provider "elasticstack" { - elasticsearch {} - kibana {} -} - -resource "elasticstack_kibana_security_exception_list" "test" { - list_id = "test-exception-list-for-item" - name = "Test Exception List for Item" - description = "Test exception list" - type = "detection" - namespace_type = "single" -} - -resource "elasticstack_kibana_security_exception_item" "test" { - list_id = elasticstack_kibana_security_exception_list.test.list_id - item_id = "test-exception-item" - name = "Test Exception Item" - description = "Test exception item for acceptance tests" - type = "simple" - namespace_type = "single" - - entries = jsonencode([ - { - field = "process.name" - operator = "included" - type = "match" - value = "test-process" - } - ]) - - tags = ["test"] -} -` - -const testAccResourceExceptionItemUpdate = ` -provider "elasticstack" { - elasticsearch {} - kibana {} -} - -resource "elasticstack_kibana_security_exception_list" "test" { - list_id = "test-exception-list-for-item" - name = "Test Exception List for Item" - description = "Test exception list" - type = "detection" - namespace_type = "single" -} - -resource "elasticstack_kibana_security_exception_item" "test" { - list_id = elasticstack_kibana_security_exception_list.test.list_id - item_id = "test-exception-item" - name = "Test Exception Item Updated" - description = "Updated description" - type = "simple" - namespace_type = "single" - - entries = jsonencode([ - { - field = "process.name" - operator = "included" - type = "match" - value = "test-process-updated" - } - ]) - - tags = ["test", "updated"] -} -` diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf new file mode 100644 index 000000000..7cc2cad13 --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf @@ -0,0 +1,63 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +variable "name" { + description = "The exception item name" + type = string +} + +variable "description" { + description = "The exception item description" + type = string +} + +variable "type" { + description = "The exception item type" + type = string +} + +variable "namespace_type" { + description = "The namespace type" + type = string +} + +variable "entries" { + description = "The entries JSON" + type = string +} + +variable "tags" { + description = "Tags for the exception item" + type = list(string) +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List for Item" + description = "Test exception list" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = var.name + description = var.description + type = var.type + namespace_type = var.namespace_type + entries = var.entries + tags = var.tags +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf new file mode 100644 index 000000000..7cc2cad13 --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf @@ -0,0 +1,63 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +variable "name" { + description = "The exception item name" + type = string +} + +variable "description" { + description = "The exception item description" + type = string +} + +variable "type" { + description = "The exception item type" + type = string +} + +variable "namespace_type" { + description = "The namespace type" + type = string +} + +variable "entries" { + description = "The entries JSON" + type = string +} + +variable "tags" { + description = "Tags for the exception item" + type = list(string) +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List for Item" + description = "Test exception list" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = var.name + description = var.description + type = var.type + namespace_type = var.namespace_type + entries = var.entries + tags = var.tags +} diff --git a/internal/kibana/security/exception_list/acc_test.go b/internal/kibana/security/exception_list/acc_test.go index 7d3027b9e..1db3764f2 100644 --- a/internal/kibana/security/exception_list/acc_test.go +++ b/internal/kibana/security/exception_list/acc_test.go @@ -6,6 +6,7 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/acctest" "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" "github.com/hashicorp/go-version" + "github.com/hashicorp/terraform-plugin-testing/config" "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) @@ -13,12 +14,20 @@ var minExceptionListAPISupport = version.Must(version.NewVersion("7.9.0")) func TestAccResourceExceptionList(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.Providers, + PreCheck: func() { acctest.PreCheck(t) }, Steps: []resource.TestStep{ { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionListAPISupport), - Config: testAccResourceExceptionListCreate, + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionListAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("create"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable("test-exception-list"), + "name": config.StringVariable("Test Exception List"), + "description": config.StringVariable("Test exception list for acceptance tests"), + "type": config.StringVariable("detection"), + "namespace_type": config.StringVariable("single"), + "tags": config.ListVariable(config.StringVariable("test")), + }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "list_id", "test-exception-list"), resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "name", "Test Exception List"), @@ -32,8 +41,17 @@ func TestAccResourceExceptionList(t *testing.T) { ), }, { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionListAPISupport), - Config: testAccResourceExceptionListUpdate, + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionListAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("update"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable("test-exception-list"), + "name": config.StringVariable("Test Exception List Updated"), + "description": config.StringVariable("Updated description"), + "type": config.StringVariable("detection"), + "namespace_type": config.StringVariable("single"), + "tags": config.ListVariable(config.StringVariable("test"), config.StringVariable("updated")), + }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "name", "Test Exception List Updated"), resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_list.test", "description", "Updated description"), @@ -44,37 +62,3 @@ func TestAccResourceExceptionList(t *testing.T) { }, }) } - -const testAccResourceExceptionListCreate = ` -provider "elasticstack" { - elasticsearch {} - kibana {} -} - -resource "elasticstack_kibana_security_exception_list" "test" { - list_id = "test-exception-list" - name = "Test Exception List" - description = "Test exception list for acceptance tests" - type = "detection" - namespace_type = "single" - - tags = ["test"] -} -` - -const testAccResourceExceptionListUpdate = ` -provider "elasticstack" { - elasticsearch {} - kibana {} -} - -resource "elasticstack_kibana_security_exception_list" "test" { - list_id = "test-exception-list" - name = "Test Exception List Updated" - description = "Updated description" - type = "detection" - namespace_type = "single" - - tags = ["test", "updated"] -} -` diff --git a/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/create/exception_list.tf b/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/create/exception_list.tf new file mode 100644 index 000000000..06adaccef --- /dev/null +++ b/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/create/exception_list.tf @@ -0,0 +1,43 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "name" { + description = "The exception list name" + type = string +} + +variable "description" { + description = "The exception list description" + type = string +} + +variable "type" { + description = "The exception list type" + type = string +} + +variable "namespace_type" { + description = "The namespace type" + type = string +} + +variable "tags" { + description = "Tags for the exception list" + type = list(string) +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = var.name + description = var.description + type = var.type + namespace_type = var.namespace_type + tags = var.tags +} diff --git a/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/update/exception_list.tf b/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/update/exception_list.tf new file mode 100644 index 000000000..06adaccef --- /dev/null +++ b/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/update/exception_list.tf @@ -0,0 +1,43 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "name" { + description = "The exception list name" + type = string +} + +variable "description" { + description = "The exception list description" + type = string +} + +variable "type" { + description = "The exception list type" + type = string +} + +variable "namespace_type" { + description = "The namespace type" + type = string +} + +variable "tags" { + description = "Tags for the exception list" + type = list(string) +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = var.name + description = var.description + type = var.type + namespace_type = var.namespace_type + tags = var.tags +} From ad4d39edca4bafcd6d8a7e020ff868e7a7140f8c Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Thu, 20 Nov 2025 10:56:04 -0700 Subject: [PATCH 11/21] Support spaces --- generated/kbapi/kibana.gen.go | 3518 +++++++++-------- generated/kbapi/transform_schema.go | 2 + internal/clients/kibana_oapi/exceptions.go | 32 +- .../security/exception_item/acc_test.go | 79 + .../kibana/security/exception_item/create.go | 4 +- .../kibana/security/exception_item/delete.go | 2 +- .../kibana/security/exception_item/models.go | 1 + .../kibana/security/exception_item/read.go | 2 +- .../kibana/security/exception_item/schema.go | 9 + .../create/exception_item.tf | 71 + .../update/exception_item.tf | 71 + .../kibana/security/exception_item/update.go | 4 +- .../security/exception_list/acc_test.go | 72 + .../kibana/security/exception_list/create.go | 15 +- .../kibana/security/exception_list/delete.go | 2 +- .../kibana/security/exception_list/models.go | 1 + .../kibana/security/exception_list/read.go | 2 +- .../kibana/security/exception_list/schema.go | 9 + .../create/exception_list.tf | 50 + .../update/exception_list.tf | 50 + .../kibana/security/exception_list/update.go | 4 +- 21 files changed, 2236 insertions(+), 1764 deletions(-) create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf create mode 100644 internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/create/exception_list.tf create mode 100644 internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/update/exception_list.tf diff --git a/generated/kbapi/kibana.gen.go b/generated/kbapi/kibana.gen.go index 57dd6b0b3..4f5949154 100644 --- a/generated/kbapi/kibana.gen.go +++ b/generated/kbapi/kibana.gen.go @@ -28988,100 +28988,6 @@ type GetEntityStoreStatusParams struct { IncludeComponents *bool `form:"include_components,omitempty" json:"include_components,omitempty"` } -// DeleteExceptionListParams defines parameters for DeleteExceptionList. -type DeleteExceptionListParams struct { - // Id Exception list's identifier. Either `id` or `list_id` must be specified. - Id *SecurityExceptionsAPIExceptionListId `form:"id,omitempty" json:"id,omitempty"` - - // ListId Human readable exception list string identifier, e.g. `trusted-linux-processes`. Either `id` or `list_id` must be specified. - ListId *SecurityExceptionsAPIExceptionListHumanId `form:"list_id,omitempty" json:"list_id,omitempty"` - NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `form:"namespace_type,omitempty" json:"namespace_type,omitempty"` -} - -// ReadExceptionListParams defines parameters for ReadExceptionList. -type ReadExceptionListParams struct { - // Id Exception list's identifier. Either `id` or `list_id` must be specified. - Id *SecurityExceptionsAPIExceptionListId `form:"id,omitempty" json:"id,omitempty"` - - // ListId Human readable exception list string identifier, e.g. `trusted-linux-processes`. Either `id` or `list_id` must be specified. - ListId *SecurityExceptionsAPIExceptionListHumanId `form:"list_id,omitempty" json:"list_id,omitempty"` - NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `form:"namespace_type,omitempty" json:"namespace_type,omitempty"` -} - -// CreateExceptionListJSONBody defines parameters for CreateExceptionList. -type CreateExceptionListJSONBody struct { - // Description Describes the exception list. - Description SecurityExceptionsAPIExceptionListDescription `json:"description"` - - // ListId The exception list's human readable string identifier, `endpoint_list`. - ListId *SecurityExceptionsAPIExceptionListHumanId `json:"list_id,omitempty"` - - // Meta Placeholder for metadata about the list container. - Meta *SecurityExceptionsAPIExceptionListMeta `json:"meta,omitempty"` - - // Name The name of the exception list. - Name SecurityExceptionsAPIExceptionListName `json:"name"` - - // NamespaceType Determines whether the exception container is available in all Kibana spaces or just the space - // in which it is created, where: - // - // - `single`: Only available in the Kibana space in which it is created. - // - `agnostic`: Available in all Kibana spaces. - NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `json:"namespace_type,omitempty"` - - // OsTypes Use this field to specify the operating system. Only enter one value. - OsTypes *SecurityExceptionsAPIExceptionListOsTypeArray `json:"os_types,omitempty"` - - // Tags String array containing words and phrases to help categorize exception containers. - Tags *SecurityExceptionsAPIExceptionListTags `json:"tags,omitempty"` - - // Type The type of exception list to be created. Different list types may denote where they can be utilized. - Type SecurityExceptionsAPIExceptionListType `json:"type"` - - // Version The document version, automatically increasd on updates. - Version *SecurityExceptionsAPIExceptionListVersion `json:"version,omitempty"` -} - -// UpdateExceptionListJSONBody defines parameters for UpdateExceptionList. -type UpdateExceptionListJSONBody struct { - // UnderscoreVersion The version id, normally returned by the API when the item was retrieved. Use it ensure updates are done against the latest version. - UnderscoreVersion *string `json:"_version,omitempty"` - - // Description Describes the exception list. - Description SecurityExceptionsAPIExceptionListDescription `json:"description"` - - // Id Exception list's identifier. - Id *SecurityExceptionsAPIExceptionListId `json:"id,omitempty"` - - // ListId The exception list's human readable string identifier, `endpoint_list`. - ListId *SecurityExceptionsAPIExceptionListHumanId `json:"list_id,omitempty"` - - // Meta Placeholder for metadata about the list container. - Meta *SecurityExceptionsAPIExceptionListMeta `json:"meta,omitempty"` - - // Name The name of the exception list. - Name SecurityExceptionsAPIExceptionListName `json:"name"` - - // NamespaceType Determines whether the exception container is available in all Kibana spaces or just the space - // in which it is created, where: - // - // - `single`: Only available in the Kibana space in which it is created. - // - `agnostic`: Available in all Kibana spaces. - NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `json:"namespace_type,omitempty"` - - // OsTypes Use this field to specify the operating system. Only enter one value. - OsTypes *SecurityExceptionsAPIExceptionListOsTypeArray `json:"os_types,omitempty"` - - // Tags String array containing words and phrases to help categorize exception containers. - Tags *SecurityExceptionsAPIExceptionListTags `json:"tags,omitempty"` - - // Type The type of exception list to be created. Different list types may denote where they can be utilized. - Type SecurityExceptionsAPIExceptionListType `json:"type"` - - // Version The document version, automatically increasd on updates. - Version *SecurityExceptionsAPIExceptionListVersion `json:"version,omitempty"` -} - // DuplicateExceptionListParams defines parameters for DuplicateExceptionList. type DuplicateExceptionListParams struct { ListId SecurityExceptionsAPIExceptionListHumanId `form:"list_id" json:"list_id"` @@ -29155,95 +29061,6 @@ type ImportExceptionListParams struct { AsNewList *bool `form:"as_new_list,omitempty" json:"as_new_list,omitempty"` } -// DeleteExceptionListItemParams defines parameters for DeleteExceptionListItem. -type DeleteExceptionListItemParams struct { - // Id Exception item's identifier. Either `id` or `item_id` must be specified - Id *SecurityExceptionsAPIExceptionListItemId `form:"id,omitempty" json:"id,omitempty"` - - // ItemId Human readable exception item string identifier, e.g. `trusted-linux-processes`. Either `id` or `item_id` must be specified - ItemId *SecurityExceptionsAPIExceptionListItemHumanId `form:"item_id,omitempty" json:"item_id,omitempty"` - NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `form:"namespace_type,omitempty" json:"namespace_type,omitempty"` -} - -// ReadExceptionListItemParams defines parameters for ReadExceptionListItem. -type ReadExceptionListItemParams struct { - // Id Exception list item's identifier. Either `id` or `item_id` must be specified. - Id *SecurityExceptionsAPIExceptionListItemId `form:"id,omitempty" json:"id,omitempty"` - - // ItemId Human readable exception item string identifier, e.g. `trusted-linux-processes`. Either `id` or `item_id` must be specified. - ItemId *SecurityExceptionsAPIExceptionListItemHumanId `form:"item_id,omitempty" json:"item_id,omitempty"` - NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `form:"namespace_type,omitempty" json:"namespace_type,omitempty"` -} - -// CreateExceptionListItemJSONBody defines parameters for CreateExceptionListItem. -type CreateExceptionListItemJSONBody struct { - Comments *SecurityExceptionsAPICreateExceptionListItemCommentArray `json:"comments,omitempty"` - - // Description Describes the exception list. - Description SecurityExceptionsAPIExceptionListItemDescription `json:"description"` - Entries SecurityExceptionsAPIExceptionListItemEntryArray `json:"entries"` - - // ExpireTime The exception item’s expiration date, in ISO format. This field is only available for regular exception items, not endpoint exceptions. - ExpireTime *SecurityExceptionsAPIExceptionListItemExpireTime `json:"expire_time,omitempty"` - - // ItemId Human readable string identifier, e.g. `trusted-linux-processes` - ItemId *SecurityExceptionsAPIExceptionListItemHumanId `json:"item_id,omitempty"` - - // ListId The exception list's human readable string identifier, `endpoint_list`. - ListId SecurityExceptionsAPIExceptionListHumanId `json:"list_id"` - Meta *SecurityExceptionsAPIExceptionListItemMeta `json:"meta,omitempty"` - - // Name Exception list name. - Name SecurityExceptionsAPIExceptionListItemName `json:"name"` - - // NamespaceType Determines whether the exception container is available in all Kibana spaces or just the space - // in which it is created, where: - // - // - `single`: Only available in the Kibana space in which it is created. - // - `agnostic`: Available in all Kibana spaces. - NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `json:"namespace_type,omitempty"` - OsTypes *SecurityExceptionsAPIExceptionListItemOsTypeArray `json:"os_types,omitempty"` - Tags *SecurityExceptionsAPIExceptionListItemTags `json:"tags,omitempty"` - Type SecurityExceptionsAPIExceptionListItemType `json:"type"` -} - -// UpdateExceptionListItemJSONBody defines parameters for UpdateExceptionListItem. -type UpdateExceptionListItemJSONBody struct { - // UnderscoreVersion The version id, normally returned by the API when the item was retrieved. Use it ensure updates are done against the latest version. - UnderscoreVersion *string `json:"_version,omitempty"` - Comments *SecurityExceptionsAPIUpdateExceptionListItemCommentArray `json:"comments,omitempty"` - - // Description Describes the exception list. - Description SecurityExceptionsAPIExceptionListItemDescription `json:"description"` - Entries SecurityExceptionsAPIExceptionListItemEntryArray `json:"entries"` - - // ExpireTime The exception item’s expiration date, in ISO format. This field is only available for regular exception items, not endpoint exceptions. - ExpireTime *SecurityExceptionsAPIExceptionListItemExpireTime `json:"expire_time,omitempty"` - - // Id Exception's identifier. - Id *SecurityExceptionsAPIExceptionListItemId `json:"id,omitempty"` - - // ItemId Human readable string identifier, e.g. `trusted-linux-processes` - ItemId *SecurityExceptionsAPIExceptionListItemHumanId `json:"item_id,omitempty"` - - // ListId The exception list's human readable string identifier, `endpoint_list`. - ListId *SecurityExceptionsAPIExceptionListHumanId `json:"list_id,omitempty"` - Meta *SecurityExceptionsAPIExceptionListItemMeta `json:"meta,omitempty"` - - // Name Exception list name. - Name SecurityExceptionsAPIExceptionListItemName `json:"name"` - - // NamespaceType Determines whether the exception container is available in all Kibana spaces or just the space - // in which it is created, where: - // - // - `single`: Only available in the Kibana space in which it is created. - // - `agnostic`: Available in all Kibana spaces. - NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `json:"namespace_type,omitempty"` - OsTypes *SecurityExceptionsAPIExceptionListItemOsTypeArray `json:"os_types,omitempty"` - Tags *SecurityExceptionsAPIExceptionListItemTags `json:"tags,omitempty"` - Type SecurityExceptionsAPIExceptionListItemType `json:"type"` -} - // FindExceptionListItemsParams defines parameters for FindExceptionListItems. type FindExceptionListItemsParams struct { // ListId The `list_id`s of the items to fetch. @@ -46057,6 +45874,189 @@ type ReadRuleParams struct { RuleId *SecurityDetectionsAPIRuleSignatureId `form:"rule_id,omitempty" json:"rule_id,omitempty"` } +// DeleteExceptionListParams defines parameters for DeleteExceptionList. +type DeleteExceptionListParams struct { + // Id Exception list's identifier. Either `id` or `list_id` must be specified. + Id *SecurityExceptionsAPIExceptionListId `form:"id,omitempty" json:"id,omitempty"` + + // ListId Human readable exception list string identifier, e.g. `trusted-linux-processes`. Either `id` or `list_id` must be specified. + ListId *SecurityExceptionsAPIExceptionListHumanId `form:"list_id,omitempty" json:"list_id,omitempty"` + NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `form:"namespace_type,omitempty" json:"namespace_type,omitempty"` +} + +// ReadExceptionListParams defines parameters for ReadExceptionList. +type ReadExceptionListParams struct { + // Id Exception list's identifier. Either `id` or `list_id` must be specified. + Id *SecurityExceptionsAPIExceptionListId `form:"id,omitempty" json:"id,omitempty"` + + // ListId Human readable exception list string identifier, e.g. `trusted-linux-processes`. Either `id` or `list_id` must be specified. + ListId *SecurityExceptionsAPIExceptionListHumanId `form:"list_id,omitempty" json:"list_id,omitempty"` + NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `form:"namespace_type,omitempty" json:"namespace_type,omitempty"` +} + +// CreateExceptionListJSONBody defines parameters for CreateExceptionList. +type CreateExceptionListJSONBody struct { + // Description Describes the exception list. + Description SecurityExceptionsAPIExceptionListDescription `json:"description"` + + // ListId The exception list's human readable string identifier, `endpoint_list`. + ListId *SecurityExceptionsAPIExceptionListHumanId `json:"list_id,omitempty"` + + // Meta Placeholder for metadata about the list container. + Meta *SecurityExceptionsAPIExceptionListMeta `json:"meta,omitempty"` + + // Name The name of the exception list. + Name SecurityExceptionsAPIExceptionListName `json:"name"` + + // NamespaceType Determines whether the exception container is available in all Kibana spaces or just the space + // in which it is created, where: + // + // - `single`: Only available in the Kibana space in which it is created. + // - `agnostic`: Available in all Kibana spaces. + NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `json:"namespace_type,omitempty"` + + // OsTypes Use this field to specify the operating system. Only enter one value. + OsTypes *SecurityExceptionsAPIExceptionListOsTypeArray `json:"os_types,omitempty"` + + // Tags String array containing words and phrases to help categorize exception containers. + Tags *SecurityExceptionsAPIExceptionListTags `json:"tags,omitempty"` + + // Type The type of exception list to be created. Different list types may denote where they can be utilized. + Type SecurityExceptionsAPIExceptionListType `json:"type"` + + // Version The document version, automatically increasd on updates. + Version *SecurityExceptionsAPIExceptionListVersion `json:"version,omitempty"` +} + +// UpdateExceptionListJSONBody defines parameters for UpdateExceptionList. +type UpdateExceptionListJSONBody struct { + // UnderscoreVersion The version id, normally returned by the API when the item was retrieved. Use it ensure updates are done against the latest version. + UnderscoreVersion *string `json:"_version,omitempty"` + + // Description Describes the exception list. + Description SecurityExceptionsAPIExceptionListDescription `json:"description"` + + // Id Exception list's identifier. + Id *SecurityExceptionsAPIExceptionListId `json:"id,omitempty"` + + // ListId The exception list's human readable string identifier, `endpoint_list`. + ListId *SecurityExceptionsAPIExceptionListHumanId `json:"list_id,omitempty"` + + // Meta Placeholder for metadata about the list container. + Meta *SecurityExceptionsAPIExceptionListMeta `json:"meta,omitempty"` + + // Name The name of the exception list. + Name SecurityExceptionsAPIExceptionListName `json:"name"` + + // NamespaceType Determines whether the exception container is available in all Kibana spaces or just the space + // in which it is created, where: + // + // - `single`: Only available in the Kibana space in which it is created. + // - `agnostic`: Available in all Kibana spaces. + NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `json:"namespace_type,omitempty"` + + // OsTypes Use this field to specify the operating system. Only enter one value. + OsTypes *SecurityExceptionsAPIExceptionListOsTypeArray `json:"os_types,omitempty"` + + // Tags String array containing words and phrases to help categorize exception containers. + Tags *SecurityExceptionsAPIExceptionListTags `json:"tags,omitempty"` + + // Type The type of exception list to be created. Different list types may denote where they can be utilized. + Type SecurityExceptionsAPIExceptionListType `json:"type"` + + // Version The document version, automatically increasd on updates. + Version *SecurityExceptionsAPIExceptionListVersion `json:"version,omitempty"` +} + +// DeleteExceptionListItemParams defines parameters for DeleteExceptionListItem. +type DeleteExceptionListItemParams struct { + // Id Exception item's identifier. Either `id` or `item_id` must be specified + Id *SecurityExceptionsAPIExceptionListItemId `form:"id,omitempty" json:"id,omitempty"` + + // ItemId Human readable exception item string identifier, e.g. `trusted-linux-processes`. Either `id` or `item_id` must be specified + ItemId *SecurityExceptionsAPIExceptionListItemHumanId `form:"item_id,omitempty" json:"item_id,omitempty"` + NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `form:"namespace_type,omitempty" json:"namespace_type,omitempty"` +} + +// ReadExceptionListItemParams defines parameters for ReadExceptionListItem. +type ReadExceptionListItemParams struct { + // Id Exception list item's identifier. Either `id` or `item_id` must be specified. + Id *SecurityExceptionsAPIExceptionListItemId `form:"id,omitempty" json:"id,omitempty"` + + // ItemId Human readable exception item string identifier, e.g. `trusted-linux-processes`. Either `id` or `item_id` must be specified. + ItemId *SecurityExceptionsAPIExceptionListItemHumanId `form:"item_id,omitempty" json:"item_id,omitempty"` + NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `form:"namespace_type,omitempty" json:"namespace_type,omitempty"` +} + +// CreateExceptionListItemJSONBody defines parameters for CreateExceptionListItem. +type CreateExceptionListItemJSONBody struct { + Comments *SecurityExceptionsAPICreateExceptionListItemCommentArray `json:"comments,omitempty"` + + // Description Describes the exception list. + Description SecurityExceptionsAPIExceptionListItemDescription `json:"description"` + Entries SecurityExceptionsAPIExceptionListItemEntryArray `json:"entries"` + + // ExpireTime The exception item’s expiration date, in ISO format. This field is only available for regular exception items, not endpoint exceptions. + ExpireTime *SecurityExceptionsAPIExceptionListItemExpireTime `json:"expire_time,omitempty"` + + // ItemId Human readable string identifier, e.g. `trusted-linux-processes` + ItemId *SecurityExceptionsAPIExceptionListItemHumanId `json:"item_id,omitempty"` + + // ListId The exception list's human readable string identifier, `endpoint_list`. + ListId SecurityExceptionsAPIExceptionListHumanId `json:"list_id"` + Meta *SecurityExceptionsAPIExceptionListItemMeta `json:"meta,omitempty"` + + // Name Exception list name. + Name SecurityExceptionsAPIExceptionListItemName `json:"name"` + + // NamespaceType Determines whether the exception container is available in all Kibana spaces or just the space + // in which it is created, where: + // + // - `single`: Only available in the Kibana space in which it is created. + // - `agnostic`: Available in all Kibana spaces. + NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `json:"namespace_type,omitempty"` + OsTypes *SecurityExceptionsAPIExceptionListItemOsTypeArray `json:"os_types,omitempty"` + Tags *SecurityExceptionsAPIExceptionListItemTags `json:"tags,omitempty"` + Type SecurityExceptionsAPIExceptionListItemType `json:"type"` +} + +// UpdateExceptionListItemJSONBody defines parameters for UpdateExceptionListItem. +type UpdateExceptionListItemJSONBody struct { + // UnderscoreVersion The version id, normally returned by the API when the item was retrieved. Use it ensure updates are done against the latest version. + UnderscoreVersion *string `json:"_version,omitempty"` + Comments *SecurityExceptionsAPIUpdateExceptionListItemCommentArray `json:"comments,omitempty"` + + // Description Describes the exception list. + Description SecurityExceptionsAPIExceptionListItemDescription `json:"description"` + Entries SecurityExceptionsAPIExceptionListItemEntryArray `json:"entries"` + + // ExpireTime The exception item’s expiration date, in ISO format. This field is only available for regular exception items, not endpoint exceptions. + ExpireTime *SecurityExceptionsAPIExceptionListItemExpireTime `json:"expire_time,omitempty"` + + // Id Exception's identifier. + Id *SecurityExceptionsAPIExceptionListItemId `json:"id,omitempty"` + + // ItemId Human readable string identifier, e.g. `trusted-linux-processes` + ItemId *SecurityExceptionsAPIExceptionListItemHumanId `json:"item_id,omitempty"` + + // ListId The exception list's human readable string identifier, `endpoint_list`. + ListId *SecurityExceptionsAPIExceptionListHumanId `json:"list_id,omitempty"` + Meta *SecurityExceptionsAPIExceptionListItemMeta `json:"meta,omitempty"` + + // Name Exception list name. + Name SecurityExceptionsAPIExceptionListItemName `json:"name"` + + // NamespaceType Determines whether the exception container is available in all Kibana spaces or just the space + // in which it is created, where: + // + // - `single`: Only available in the Kibana space in which it is created. + // - `agnostic`: Available in all Kibana spaces. + NamespaceType *SecurityExceptionsAPIExceptionNamespaceType `json:"namespace_type,omitempty"` + OsTypes *SecurityExceptionsAPIExceptionListItemOsTypeArray `json:"os_types,omitempty"` + Tags *SecurityExceptionsAPIExceptionListItemTags `json:"tags,omitempty"` + Type SecurityExceptionsAPIExceptionListItemType `json:"type"` +} + // PostMaintenanceWindowJSONBody defines parameters for PostMaintenanceWindow. type PostMaintenanceWindowJSONBody struct { // Enabled Whether the current maintenance window is enabled. Disabled maintenance windows do not suppress notifications. @@ -46441,21 +46441,9 @@ type DeleteSingleEntityJSONRequestBody DeleteSingleEntityJSONBody // UpsertEntityJSONRequestBody defines body for UpsertEntity for application/json ContentType. type UpsertEntityJSONRequestBody = SecurityEntityAnalyticsAPIEntity -// CreateExceptionListJSONRequestBody defines body for CreateExceptionList for application/json ContentType. -type CreateExceptionListJSONRequestBody CreateExceptionListJSONBody - -// UpdateExceptionListJSONRequestBody defines body for UpdateExceptionList for application/json ContentType. -type UpdateExceptionListJSONRequestBody UpdateExceptionListJSONBody - // ImportExceptionListMultipartRequestBody defines body for ImportExceptionList for multipart/form-data ContentType. type ImportExceptionListMultipartRequestBody ImportExceptionListMultipartBody -// CreateExceptionListItemJSONRequestBody defines body for CreateExceptionListItem for application/json ContentType. -type CreateExceptionListItemJSONRequestBody CreateExceptionListItemJSONBody - -// UpdateExceptionListItemJSONRequestBody defines body for UpdateExceptionListItem for application/json ContentType. -type UpdateExceptionListItemJSONRequestBody UpdateExceptionListItemJSONBody - // CreateSharedExceptionListJSONRequestBody defines body for CreateSharedExceptionList for application/json ContentType. type CreateSharedExceptionListJSONRequestBody CreateSharedExceptionListJSONBody @@ -46933,6 +46921,18 @@ type CreateRuleJSONRequestBody = SecurityDetectionsAPIRuleCreateProps // UpdateRuleJSONRequestBody defines body for UpdateRule for application/json ContentType. type UpdateRuleJSONRequestBody = SecurityDetectionsAPIRuleUpdateProps +// CreateExceptionListJSONRequestBody defines body for CreateExceptionList for application/json ContentType. +type CreateExceptionListJSONRequestBody CreateExceptionListJSONBody + +// UpdateExceptionListJSONRequestBody defines body for UpdateExceptionList for application/json ContentType. +type UpdateExceptionListJSONRequestBody UpdateExceptionListJSONBody + +// CreateExceptionListItemJSONRequestBody defines body for CreateExceptionListItem for application/json ContentType. +type CreateExceptionListItemJSONRequestBody CreateExceptionListItemJSONBody + +// UpdateExceptionListItemJSONRequestBody defines body for UpdateExceptionListItem for application/json ContentType. +type UpdateExceptionListItemJSONRequestBody UpdateExceptionListItemJSONBody + // PostMaintenanceWindowJSONRequestBody defines body for PostMaintenanceWindow for application/json ContentType. type PostMaintenanceWindowJSONRequestBody PostMaintenanceWindowJSONBody @@ -59445,7 +59445,7 @@ func (t SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item) AsSLO // FromSLOsTimesliceMetricBasicMetricWithField overwrites any union data inside the SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item as the provided SLOsTimesliceMetricBasicMetricWithField func (t *SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item) FromSLOsTimesliceMetricBasicMetricWithField(v SLOsTimesliceMetricBasicMetricWithField) error { - v.Aggregation = "avg" + v.Aggregation = "last_value" b, err := json.Marshal(v) t.union = b return err @@ -59453,7 +59453,7 @@ func (t *SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item) From // MergeSLOsTimesliceMetricBasicMetricWithField performs a merge with any union data inside the SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item, using the provided SLOsTimesliceMetricBasicMetricWithField func (t *SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item) MergeSLOsTimesliceMetricBasicMetricWithField(v SLOsTimesliceMetricBasicMetricWithField) error { - v.Aggregation = "avg" + v.Aggregation = "last_value" b, err := json.Marshal(v) if err != nil { return err @@ -59534,10 +59534,10 @@ func (t SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item) Value return nil, err } switch discriminator { - case "avg": - return t.AsSLOsTimesliceMetricBasicMetricWithField() case "doc_count": return t.AsSLOsTimesliceMetricDocCountMetric() + case "last_value": + return t.AsSLOsTimesliceMetricBasicMetricWithField() case "percentile": return t.AsSLOsTimesliceMetricPercentileMetric() default: @@ -74101,22 +74101,6 @@ type ClientInterface interface { // GetEntityStoreStatus request GetEntityStoreStatus(ctx context.Context, params *GetEntityStoreStatusParams, reqEditors ...RequestEditorFn) (*http.Response, error) - // DeleteExceptionList request - DeleteExceptionList(ctx context.Context, params *DeleteExceptionListParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // ReadExceptionList request - ReadExceptionList(ctx context.Context, params *ReadExceptionListParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // CreateExceptionListWithBody request with any body - CreateExceptionListWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - CreateExceptionList(ctx context.Context, body CreateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // UpdateExceptionListWithBody request with any body - UpdateExceptionListWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - UpdateExceptionList(ctx context.Context, body UpdateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - // DuplicateExceptionList request DuplicateExceptionList(ctx context.Context, params *DuplicateExceptionListParams, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -74129,22 +74113,6 @@ type ClientInterface interface { // ImportExceptionListWithBody request with any body ImportExceptionListWithBody(ctx context.Context, params *ImportExceptionListParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - // DeleteExceptionListItem request - DeleteExceptionListItem(ctx context.Context, params *DeleteExceptionListItemParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // ReadExceptionListItem request - ReadExceptionListItem(ctx context.Context, params *ReadExceptionListItemParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // CreateExceptionListItemWithBody request with any body - CreateExceptionListItemWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - CreateExceptionListItem(ctx context.Context, body CreateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // UpdateExceptionListItemWithBody request with any body - UpdateExceptionListItemWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - UpdateExceptionListItem(ctx context.Context, body UpdateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - // FindExceptionListItems request FindExceptionListItems(ctx context.Context, params *FindExceptionListItemsParams, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -75394,6 +75362,38 @@ type ClientInterface interface { UpdateRule(ctx context.Context, spaceId SpaceId, body UpdateRuleJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // DeleteExceptionList request + DeleteExceptionList(ctx context.Context, spaceId SpaceId, params *DeleteExceptionListParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // ReadExceptionList request + ReadExceptionList(ctx context.Context, spaceId SpaceId, params *ReadExceptionListParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // CreateExceptionListWithBody request with any body + CreateExceptionListWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreateExceptionList(ctx context.Context, spaceId SpaceId, body CreateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // UpdateExceptionListWithBody request with any body + UpdateExceptionListWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + UpdateExceptionList(ctx context.Context, spaceId SpaceId, body UpdateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // DeleteExceptionListItem request + DeleteExceptionListItem(ctx context.Context, spaceId SpaceId, params *DeleteExceptionListItemParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // ReadExceptionListItem request + ReadExceptionListItem(ctx context.Context, spaceId SpaceId, params *ReadExceptionListItemParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // CreateExceptionListItemWithBody request with any body + CreateExceptionListItemWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreateExceptionListItem(ctx context.Context, spaceId SpaceId, body CreateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // UpdateExceptionListItemWithBody request with any body + UpdateExceptionListItemWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + UpdateExceptionListItem(ctx context.Context, spaceId SpaceId, body UpdateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // PostMaintenanceWindowWithBody request with any body PostMaintenanceWindowWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -78436,78 +78436,6 @@ func (c *Client) GetEntityStoreStatus(ctx context.Context, params *GetEntityStor return c.Client.Do(req) } -func (c *Client) DeleteExceptionList(ctx context.Context, params *DeleteExceptionListParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeleteExceptionListRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) ReadExceptionList(ctx context.Context, params *ReadExceptionListParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewReadExceptionListRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) CreateExceptionListWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewCreateExceptionListRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) CreateExceptionList(ctx context.Context, body CreateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewCreateExceptionListRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) UpdateExceptionListWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewUpdateExceptionListRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) UpdateExceptionList(ctx context.Context, body UpdateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewUpdateExceptionListRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - func (c *Client) DuplicateExceptionList(ctx context.Context, params *DuplicateExceptionListParams, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewDuplicateExceptionListRequest(c.Server, params) if err != nil { @@ -78556,78 +78484,6 @@ func (c *Client) ImportExceptionListWithBody(ctx context.Context, params *Import return c.Client.Do(req) } -func (c *Client) DeleteExceptionListItem(ctx context.Context, params *DeleteExceptionListItemParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeleteExceptionListItemRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) ReadExceptionListItem(ctx context.Context, params *ReadExceptionListItemParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewReadExceptionListItemRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) CreateExceptionListItemWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewCreateExceptionListItemRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) CreateExceptionListItem(ctx context.Context, body CreateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewCreateExceptionListItemRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) UpdateExceptionListItemWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewUpdateExceptionListItemRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) UpdateExceptionListItem(ctx context.Context, body UpdateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewUpdateExceptionListItemRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - func (c *Client) FindExceptionListItems(ctx context.Context, params *FindExceptionListItemsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewFindExceptionListItemsRequest(c.Server, params) if err != nil { @@ -84244,6 +84100,150 @@ func (c *Client) UpdateRule(ctx context.Context, spaceId SpaceId, body UpdateRul return c.Client.Do(req) } +func (c *Client) DeleteExceptionList(ctx context.Context, spaceId SpaceId, params *DeleteExceptionListParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeleteExceptionListRequest(c.Server, spaceId, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) ReadExceptionList(ctx context.Context, spaceId SpaceId, params *ReadExceptionListParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewReadExceptionListRequest(c.Server, spaceId, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) CreateExceptionListWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateExceptionListRequestWithBody(c.Server, spaceId, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) CreateExceptionList(ctx context.Context, spaceId SpaceId, body CreateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateExceptionListRequest(c.Server, spaceId, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateExceptionListWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateExceptionListRequestWithBody(c.Server, spaceId, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateExceptionList(ctx context.Context, spaceId SpaceId, body UpdateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateExceptionListRequest(c.Server, spaceId, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) DeleteExceptionListItem(ctx context.Context, spaceId SpaceId, params *DeleteExceptionListItemParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeleteExceptionListItemRequest(c.Server, spaceId, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) ReadExceptionListItem(ctx context.Context, spaceId SpaceId, params *ReadExceptionListItemParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewReadExceptionListItemRequest(c.Server, spaceId, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) CreateExceptionListItemWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateExceptionListItemRequestWithBody(c.Server, spaceId, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) CreateExceptionListItem(ctx context.Context, spaceId SpaceId, body CreateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateExceptionListItemRequest(c.Server, spaceId, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateExceptionListItemWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateExceptionListItemRequestWithBody(c.Server, spaceId, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateExceptionListItem(ctx context.Context, spaceId SpaceId, body UpdateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateExceptionListItemRequest(c.Server, spaceId, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) PostMaintenanceWindowWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewPostMaintenanceWindowRequestWithBody(c.Server, spaceId, contentType, body) if err != nil { @@ -93500,248 +93500,6 @@ func NewGetEntityStoreStatusRequest(server string, params *GetEntityStoreStatusP return req, nil } -// NewDeleteExceptionListRequest generates requests for DeleteExceptionList -func NewDeleteExceptionListRequest(server string, params *DeleteExceptionListParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/exception_lists") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Id != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, *params.Id); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.ListId != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "list_id", runtime.ParamLocationQuery, *params.ListId); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.NamespaceType != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "namespace_type", runtime.ParamLocationQuery, *params.NamespaceType); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewReadExceptionListRequest generates requests for ReadExceptionList -func NewReadExceptionListRequest(server string, params *ReadExceptionListParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/exception_lists") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Id != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, *params.Id); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.ListId != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "list_id", runtime.ParamLocationQuery, *params.ListId); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.NamespaceType != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "namespace_type", runtime.ParamLocationQuery, *params.NamespaceType); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewCreateExceptionListRequest calls the generic CreateExceptionList builder with application/json body -func NewCreateExceptionListRequest(server string, body CreateExceptionListJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewCreateExceptionListRequestWithBody(server, "application/json", bodyReader) -} - -// NewCreateExceptionListRequestWithBody generates requests for CreateExceptionList with any type of body -func NewCreateExceptionListRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/exception_lists") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewUpdateExceptionListRequest calls the generic UpdateExceptionList builder with application/json body -func NewUpdateExceptionListRequest(server string, body UpdateExceptionListJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewUpdateExceptionListRequestWithBody(server, "application/json", bodyReader) -} - -// NewUpdateExceptionListRequestWithBody generates requests for UpdateExceptionList with any type of body -func NewUpdateExceptionListRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/exception_lists") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("PUT", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - // NewDuplicateExceptionListRequest generates requests for DuplicateExceptionList func NewDuplicateExceptionListRequest(server string, params *DuplicateExceptionListParams) (*http.Request, error) { var err error @@ -94088,248 +93846,6 @@ func NewImportExceptionListRequestWithBody(server string, params *ImportExceptio return req, nil } -// NewDeleteExceptionListItemRequest generates requests for DeleteExceptionListItem -func NewDeleteExceptionListItemRequest(server string, params *DeleteExceptionListItemParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/exception_lists/items") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Id != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, *params.Id); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.ItemId != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "item_id", runtime.ParamLocationQuery, *params.ItemId); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.NamespaceType != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "namespace_type", runtime.ParamLocationQuery, *params.NamespaceType); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewReadExceptionListItemRequest generates requests for ReadExceptionListItem -func NewReadExceptionListItemRequest(server string, params *ReadExceptionListItemParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/exception_lists/items") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if params.Id != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, *params.Id); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.ItemId != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "item_id", runtime.ParamLocationQuery, *params.ItemId); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.NamespaceType != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "namespace_type", runtime.ParamLocationQuery, *params.NamespaceType); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewCreateExceptionListItemRequest calls the generic CreateExceptionListItem builder with application/json body -func NewCreateExceptionListItemRequest(server string, body CreateExceptionListItemJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewCreateExceptionListItemRequestWithBody(server, "application/json", bodyReader) -} - -// NewCreateExceptionListItemRequestWithBody generates requests for CreateExceptionListItem with any type of body -func NewCreateExceptionListItemRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/exception_lists/items") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewUpdateExceptionListItemRequest calls the generic UpdateExceptionListItem builder with application/json body -func NewUpdateExceptionListItemRequest(server string, body UpdateExceptionListItemJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewUpdateExceptionListItemRequestWithBody(server, "application/json", bodyReader) -} - -// NewUpdateExceptionListItemRequestWithBody generates requests for UpdateExceptionListItem with any type of body -func NewUpdateExceptionListItemRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/exception_lists/items") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("PUT", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - // NewFindExceptionListItemsRequest generates requests for FindExceptionListItems func NewFindExceptionListItemsRequest(server string, params *FindExceptionListItemsParams) (*http.Request, error) { var err error @@ -111158,6 +110674,546 @@ func NewUpdateRuleRequestWithBody(server string, spaceId SpaceId, contentType st return req, nil } +// NewDeleteExceptionListRequest generates requests for DeleteExceptionList +func NewDeleteExceptionListRequest(server string, spaceId SpaceId, params *DeleteExceptionListParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/exception_lists", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Id != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, *params.Id); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.ListId != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "list_id", runtime.ParamLocationQuery, *params.ListId); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.NamespaceType != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "namespace_type", runtime.ParamLocationQuery, *params.NamespaceType); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewReadExceptionListRequest generates requests for ReadExceptionList +func NewReadExceptionListRequest(server string, spaceId SpaceId, params *ReadExceptionListParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/exception_lists", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Id != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, *params.Id); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.ListId != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "list_id", runtime.ParamLocationQuery, *params.ListId); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.NamespaceType != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "namespace_type", runtime.ParamLocationQuery, *params.NamespaceType); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewCreateExceptionListRequest calls the generic CreateExceptionList builder with application/json body +func NewCreateExceptionListRequest(server string, spaceId SpaceId, body CreateExceptionListJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreateExceptionListRequestWithBody(server, spaceId, "application/json", bodyReader) +} + +// NewCreateExceptionListRequestWithBody generates requests for CreateExceptionList with any type of body +func NewCreateExceptionListRequestWithBody(server string, spaceId SpaceId, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/exception_lists", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewUpdateExceptionListRequest calls the generic UpdateExceptionList builder with application/json body +func NewUpdateExceptionListRequest(server string, spaceId SpaceId, body UpdateExceptionListJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewUpdateExceptionListRequestWithBody(server, spaceId, "application/json", bodyReader) +} + +// NewUpdateExceptionListRequestWithBody generates requests for UpdateExceptionList with any type of body +func NewUpdateExceptionListRequestWithBody(server string, spaceId SpaceId, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/exception_lists", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("PUT", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewDeleteExceptionListItemRequest generates requests for DeleteExceptionListItem +func NewDeleteExceptionListItemRequest(server string, spaceId SpaceId, params *DeleteExceptionListItemParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/exception_lists/items", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Id != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, *params.Id); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.ItemId != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "item_id", runtime.ParamLocationQuery, *params.ItemId); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.NamespaceType != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "namespace_type", runtime.ParamLocationQuery, *params.NamespaceType); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewReadExceptionListItemRequest generates requests for ReadExceptionListItem +func NewReadExceptionListItemRequest(server string, spaceId SpaceId, params *ReadExceptionListItemParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/exception_lists/items", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Id != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, *params.Id); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.ItemId != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "item_id", runtime.ParamLocationQuery, *params.ItemId); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.NamespaceType != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "namespace_type", runtime.ParamLocationQuery, *params.NamespaceType); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewCreateExceptionListItemRequest calls the generic CreateExceptionListItem builder with application/json body +func NewCreateExceptionListItemRequest(server string, spaceId SpaceId, body CreateExceptionListItemJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreateExceptionListItemRequestWithBody(server, spaceId, "application/json", bodyReader) +} + +// NewCreateExceptionListItemRequestWithBody generates requests for CreateExceptionListItem with any type of body +func NewCreateExceptionListItemRequestWithBody(server string, spaceId SpaceId, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/exception_lists/items", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewUpdateExceptionListItemRequest calls the generic UpdateExceptionListItem builder with application/json body +func NewUpdateExceptionListItemRequest(server string, spaceId SpaceId, body UpdateExceptionListItemJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewUpdateExceptionListItemRequestWithBody(server, spaceId, "application/json", bodyReader) +} + +// NewUpdateExceptionListItemRequestWithBody generates requests for UpdateExceptionListItem with any type of body +func NewUpdateExceptionListItemRequestWithBody(server string, spaceId SpaceId, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/exception_lists/items", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("PUT", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + // NewPostMaintenanceWindowRequest calls the generic PostMaintenanceWindow builder with application/json body func NewPostMaintenanceWindowRequest(server string, spaceId SpaceId, body PostMaintenanceWindowJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader @@ -112871,22 +112927,6 @@ type ClientWithResponsesInterface interface { // GetEntityStoreStatusWithResponse request GetEntityStoreStatusWithResponse(ctx context.Context, params *GetEntityStoreStatusParams, reqEditors ...RequestEditorFn) (*GetEntityStoreStatusResponse, error) - // DeleteExceptionListWithResponse request - DeleteExceptionListWithResponse(ctx context.Context, params *DeleteExceptionListParams, reqEditors ...RequestEditorFn) (*DeleteExceptionListResponse, error) - - // ReadExceptionListWithResponse request - ReadExceptionListWithResponse(ctx context.Context, params *ReadExceptionListParams, reqEditors ...RequestEditorFn) (*ReadExceptionListResponse, error) - - // CreateExceptionListWithBodyWithResponse request with any body - CreateExceptionListWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateExceptionListResponse, error) - - CreateExceptionListWithResponse(ctx context.Context, body CreateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateExceptionListResponse, error) - - // UpdateExceptionListWithBodyWithResponse request with any body - UpdateExceptionListWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateExceptionListResponse, error) - - UpdateExceptionListWithResponse(ctx context.Context, body UpdateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateExceptionListResponse, error) - // DuplicateExceptionListWithResponse request DuplicateExceptionListWithResponse(ctx context.Context, params *DuplicateExceptionListParams, reqEditors ...RequestEditorFn) (*DuplicateExceptionListResponse, error) @@ -112899,22 +112939,6 @@ type ClientWithResponsesInterface interface { // ImportExceptionListWithBodyWithResponse request with any body ImportExceptionListWithBodyWithResponse(ctx context.Context, params *ImportExceptionListParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ImportExceptionListResponse, error) - // DeleteExceptionListItemWithResponse request - DeleteExceptionListItemWithResponse(ctx context.Context, params *DeleteExceptionListItemParams, reqEditors ...RequestEditorFn) (*DeleteExceptionListItemResponse, error) - - // ReadExceptionListItemWithResponse request - ReadExceptionListItemWithResponse(ctx context.Context, params *ReadExceptionListItemParams, reqEditors ...RequestEditorFn) (*ReadExceptionListItemResponse, error) - - // CreateExceptionListItemWithBodyWithResponse request with any body - CreateExceptionListItemWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateExceptionListItemResponse, error) - - CreateExceptionListItemWithResponse(ctx context.Context, body CreateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateExceptionListItemResponse, error) - - // UpdateExceptionListItemWithBodyWithResponse request with any body - UpdateExceptionListItemWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateExceptionListItemResponse, error) - - UpdateExceptionListItemWithResponse(ctx context.Context, body UpdateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateExceptionListItemResponse, error) - // FindExceptionListItemsWithResponse request FindExceptionListItemsWithResponse(ctx context.Context, params *FindExceptionListItemsParams, reqEditors ...RequestEditorFn) (*FindExceptionListItemsResponse, error) @@ -114164,6 +114188,38 @@ type ClientWithResponsesInterface interface { UpdateRuleWithResponse(ctx context.Context, spaceId SpaceId, body UpdateRuleJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateRuleResponse, error) + // DeleteExceptionListWithResponse request + DeleteExceptionListWithResponse(ctx context.Context, spaceId SpaceId, params *DeleteExceptionListParams, reqEditors ...RequestEditorFn) (*DeleteExceptionListResponse, error) + + // ReadExceptionListWithResponse request + ReadExceptionListWithResponse(ctx context.Context, spaceId SpaceId, params *ReadExceptionListParams, reqEditors ...RequestEditorFn) (*ReadExceptionListResponse, error) + + // CreateExceptionListWithBodyWithResponse request with any body + CreateExceptionListWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateExceptionListResponse, error) + + CreateExceptionListWithResponse(ctx context.Context, spaceId SpaceId, body CreateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateExceptionListResponse, error) + + // UpdateExceptionListWithBodyWithResponse request with any body + UpdateExceptionListWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateExceptionListResponse, error) + + UpdateExceptionListWithResponse(ctx context.Context, spaceId SpaceId, body UpdateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateExceptionListResponse, error) + + // DeleteExceptionListItemWithResponse request + DeleteExceptionListItemWithResponse(ctx context.Context, spaceId SpaceId, params *DeleteExceptionListItemParams, reqEditors ...RequestEditorFn) (*DeleteExceptionListItemResponse, error) + + // ReadExceptionListItemWithResponse request + ReadExceptionListItemWithResponse(ctx context.Context, spaceId SpaceId, params *ReadExceptionListItemParams, reqEditors ...RequestEditorFn) (*ReadExceptionListItemResponse, error) + + // CreateExceptionListItemWithBodyWithResponse request with any body + CreateExceptionListItemWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateExceptionListItemResponse, error) + + CreateExceptionListItemWithResponse(ctx context.Context, spaceId SpaceId, body CreateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateExceptionListItemResponse, error) + + // UpdateExceptionListItemWithBodyWithResponse request with any body + UpdateExceptionListItemWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateExceptionListItemResponse, error) + + UpdateExceptionListItemWithResponse(ctx context.Context, spaceId SpaceId, body UpdateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateExceptionListItemResponse, error) + // PostMaintenanceWindowWithBodyWithResponse request with any body PostMaintenanceWindowWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostMaintenanceWindowResponse, error) @@ -120471,122 +120527,6 @@ func (r GetEntityStoreStatusResponse) StatusCode() int { return 0 } -type DeleteExceptionListResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityExceptionsAPIExceptionList - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityExceptionsAPIPlatformErrorResponse - JSON403 *SecurityExceptionsAPIPlatformErrorResponse - JSON404 *SecurityExceptionsAPISiemErrorResponse - JSON500 *SecurityExceptionsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r DeleteExceptionListResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r DeleteExceptionListResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type ReadExceptionListResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityExceptionsAPIExceptionList - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityExceptionsAPIPlatformErrorResponse - JSON403 *SecurityExceptionsAPIPlatformErrorResponse - JSON404 *SecurityExceptionsAPISiemErrorResponse - JSON500 *SecurityExceptionsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r ReadExceptionListResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r ReadExceptionListResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type CreateExceptionListResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityExceptionsAPIExceptionList - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityExceptionsAPIPlatformErrorResponse - JSON403 *SecurityExceptionsAPIPlatformErrorResponse - JSON409 *SecurityExceptionsAPISiemErrorResponse - JSON500 *SecurityExceptionsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r CreateExceptionListResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r CreateExceptionListResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type UpdateExceptionListResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityExceptionsAPIExceptionList - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityExceptionsAPIPlatformErrorResponse - JSON403 *SecurityExceptionsAPIPlatformErrorResponse - JSON404 *SecurityExceptionsAPISiemErrorResponse - JSON500 *SecurityExceptionsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r UpdateExceptionListResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r UpdateExceptionListResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - type DuplicateExceptionListResponse struct { Body []byte HTTPResponse *http.Response @@ -120714,122 +120654,6 @@ func (r ImportExceptionListResponse) StatusCode() int { return 0 } -type DeleteExceptionListItemResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityExceptionsAPIExceptionListItem - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityExceptionsAPIPlatformErrorResponse - JSON403 *SecurityExceptionsAPIPlatformErrorResponse - JSON404 *SecurityExceptionsAPISiemErrorResponse - JSON500 *SecurityExceptionsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r DeleteExceptionListItemResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r DeleteExceptionListItemResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type ReadExceptionListItemResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityExceptionsAPIExceptionListItem - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityExceptionsAPIPlatformErrorResponse - JSON403 *SecurityExceptionsAPIPlatformErrorResponse - JSON404 *SecurityExceptionsAPISiemErrorResponse - JSON500 *SecurityExceptionsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r ReadExceptionListItemResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r ReadExceptionListItemResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type CreateExceptionListItemResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityExceptionsAPIExceptionListItem - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityExceptionsAPIPlatformErrorResponse - JSON403 *SecurityExceptionsAPIPlatformErrorResponse - JSON409 *SecurityExceptionsAPISiemErrorResponse - JSON500 *SecurityExceptionsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r CreateExceptionListItemResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r CreateExceptionListItemResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type UpdateExceptionListItemResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityExceptionsAPIExceptionListItem - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityExceptionsAPIPlatformErrorResponse - JSON403 *SecurityExceptionsAPIPlatformErrorResponse - JSON404 *SecurityExceptionsAPISiemErrorResponse - JSON500 *SecurityExceptionsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r UpdateExceptionListItemResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r UpdateExceptionListItemResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - type FindExceptionListItemsResponse struct { Body []byte HTTPResponse *http.Response @@ -132639,6 +132463,238 @@ func (r UpdateRuleResponse) StatusCode() int { return 0 } +type DeleteExceptionListResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityExceptionsAPIExceptionList + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityExceptionsAPIPlatformErrorResponse + JSON403 *SecurityExceptionsAPIPlatformErrorResponse + JSON404 *SecurityExceptionsAPISiemErrorResponse + JSON500 *SecurityExceptionsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r DeleteExceptionListResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r DeleteExceptionListResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type ReadExceptionListResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityExceptionsAPIExceptionList + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityExceptionsAPIPlatformErrorResponse + JSON403 *SecurityExceptionsAPIPlatformErrorResponse + JSON404 *SecurityExceptionsAPISiemErrorResponse + JSON500 *SecurityExceptionsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r ReadExceptionListResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ReadExceptionListResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type CreateExceptionListResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityExceptionsAPIExceptionList + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityExceptionsAPIPlatformErrorResponse + JSON403 *SecurityExceptionsAPIPlatformErrorResponse + JSON409 *SecurityExceptionsAPISiemErrorResponse + JSON500 *SecurityExceptionsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r CreateExceptionListResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r CreateExceptionListResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type UpdateExceptionListResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityExceptionsAPIExceptionList + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityExceptionsAPIPlatformErrorResponse + JSON403 *SecurityExceptionsAPIPlatformErrorResponse + JSON404 *SecurityExceptionsAPISiemErrorResponse + JSON500 *SecurityExceptionsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r UpdateExceptionListResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r UpdateExceptionListResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type DeleteExceptionListItemResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityExceptionsAPIExceptionListItem + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityExceptionsAPIPlatformErrorResponse + JSON403 *SecurityExceptionsAPIPlatformErrorResponse + JSON404 *SecurityExceptionsAPISiemErrorResponse + JSON500 *SecurityExceptionsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r DeleteExceptionListItemResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r DeleteExceptionListItemResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type ReadExceptionListItemResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityExceptionsAPIExceptionListItem + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityExceptionsAPIPlatformErrorResponse + JSON403 *SecurityExceptionsAPIPlatformErrorResponse + JSON404 *SecurityExceptionsAPISiemErrorResponse + JSON500 *SecurityExceptionsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r ReadExceptionListItemResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ReadExceptionListItemResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type CreateExceptionListItemResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityExceptionsAPIExceptionListItem + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityExceptionsAPIPlatformErrorResponse + JSON403 *SecurityExceptionsAPIPlatformErrorResponse + JSON409 *SecurityExceptionsAPISiemErrorResponse + JSON500 *SecurityExceptionsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r CreateExceptionListItemResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r CreateExceptionListItemResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type UpdateExceptionListItemResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityExceptionsAPIExceptionListItem + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityExceptionsAPIPlatformErrorResponse + JSON403 *SecurityExceptionsAPIPlatformErrorResponse + JSON404 *SecurityExceptionsAPISiemErrorResponse + JSON500 *SecurityExceptionsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r UpdateExceptionListItemResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r UpdateExceptionListItemResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type PostMaintenanceWindowResponse struct { Body []byte HTTPResponse *http.Response @@ -135408,58 +135464,6 @@ func (c *ClientWithResponses) GetEntityStoreStatusWithResponse(ctx context.Conte return ParseGetEntityStoreStatusResponse(rsp) } -// DeleteExceptionListWithResponse request returning *DeleteExceptionListResponse -func (c *ClientWithResponses) DeleteExceptionListWithResponse(ctx context.Context, params *DeleteExceptionListParams, reqEditors ...RequestEditorFn) (*DeleteExceptionListResponse, error) { - rsp, err := c.DeleteExceptionList(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseDeleteExceptionListResponse(rsp) -} - -// ReadExceptionListWithResponse request returning *ReadExceptionListResponse -func (c *ClientWithResponses) ReadExceptionListWithResponse(ctx context.Context, params *ReadExceptionListParams, reqEditors ...RequestEditorFn) (*ReadExceptionListResponse, error) { - rsp, err := c.ReadExceptionList(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseReadExceptionListResponse(rsp) -} - -// CreateExceptionListWithBodyWithResponse request with arbitrary body returning *CreateExceptionListResponse -func (c *ClientWithResponses) CreateExceptionListWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateExceptionListResponse, error) { - rsp, err := c.CreateExceptionListWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseCreateExceptionListResponse(rsp) -} - -func (c *ClientWithResponses) CreateExceptionListWithResponse(ctx context.Context, body CreateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateExceptionListResponse, error) { - rsp, err := c.CreateExceptionList(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseCreateExceptionListResponse(rsp) -} - -// UpdateExceptionListWithBodyWithResponse request with arbitrary body returning *UpdateExceptionListResponse -func (c *ClientWithResponses) UpdateExceptionListWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateExceptionListResponse, error) { - rsp, err := c.UpdateExceptionListWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseUpdateExceptionListResponse(rsp) -} - -func (c *ClientWithResponses) UpdateExceptionListWithResponse(ctx context.Context, body UpdateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateExceptionListResponse, error) { - rsp, err := c.UpdateExceptionList(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseUpdateExceptionListResponse(rsp) -} - // DuplicateExceptionListWithResponse request returning *DuplicateExceptionListResponse func (c *ClientWithResponses) DuplicateExceptionListWithResponse(ctx context.Context, params *DuplicateExceptionListParams, reqEditors ...RequestEditorFn) (*DuplicateExceptionListResponse, error) { rsp, err := c.DuplicateExceptionList(ctx, params, reqEditors...) @@ -135496,58 +135500,6 @@ func (c *ClientWithResponses) ImportExceptionListWithBodyWithResponse(ctx contex return ParseImportExceptionListResponse(rsp) } -// DeleteExceptionListItemWithResponse request returning *DeleteExceptionListItemResponse -func (c *ClientWithResponses) DeleteExceptionListItemWithResponse(ctx context.Context, params *DeleteExceptionListItemParams, reqEditors ...RequestEditorFn) (*DeleteExceptionListItemResponse, error) { - rsp, err := c.DeleteExceptionListItem(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseDeleteExceptionListItemResponse(rsp) -} - -// ReadExceptionListItemWithResponse request returning *ReadExceptionListItemResponse -func (c *ClientWithResponses) ReadExceptionListItemWithResponse(ctx context.Context, params *ReadExceptionListItemParams, reqEditors ...RequestEditorFn) (*ReadExceptionListItemResponse, error) { - rsp, err := c.ReadExceptionListItem(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseReadExceptionListItemResponse(rsp) -} - -// CreateExceptionListItemWithBodyWithResponse request with arbitrary body returning *CreateExceptionListItemResponse -func (c *ClientWithResponses) CreateExceptionListItemWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateExceptionListItemResponse, error) { - rsp, err := c.CreateExceptionListItemWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseCreateExceptionListItemResponse(rsp) -} - -func (c *ClientWithResponses) CreateExceptionListItemWithResponse(ctx context.Context, body CreateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateExceptionListItemResponse, error) { - rsp, err := c.CreateExceptionListItem(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseCreateExceptionListItemResponse(rsp) -} - -// UpdateExceptionListItemWithBodyWithResponse request with arbitrary body returning *UpdateExceptionListItemResponse -func (c *ClientWithResponses) UpdateExceptionListItemWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateExceptionListItemResponse, error) { - rsp, err := c.UpdateExceptionListItemWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseUpdateExceptionListItemResponse(rsp) -} - -func (c *ClientWithResponses) UpdateExceptionListItemWithResponse(ctx context.Context, body UpdateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateExceptionListItemResponse, error) { - rsp, err := c.UpdateExceptionListItem(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseUpdateExceptionListItemResponse(rsp) -} - // FindExceptionListItemsWithResponse request returning *FindExceptionListItemsResponse func (c *ClientWithResponses) FindExceptionListItemsWithResponse(ctx context.Context, params *FindExceptionListItemsParams, reqEditors ...RequestEditorFn) (*FindExceptionListItemsResponse, error) { rsp, err := c.FindExceptionListItems(ctx, params, reqEditors...) @@ -139605,6 +139557,110 @@ func (c *ClientWithResponses) UpdateRuleWithResponse(ctx context.Context, spaceI return ParseUpdateRuleResponse(rsp) } +// DeleteExceptionListWithResponse request returning *DeleteExceptionListResponse +func (c *ClientWithResponses) DeleteExceptionListWithResponse(ctx context.Context, spaceId SpaceId, params *DeleteExceptionListParams, reqEditors ...RequestEditorFn) (*DeleteExceptionListResponse, error) { + rsp, err := c.DeleteExceptionList(ctx, spaceId, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseDeleteExceptionListResponse(rsp) +} + +// ReadExceptionListWithResponse request returning *ReadExceptionListResponse +func (c *ClientWithResponses) ReadExceptionListWithResponse(ctx context.Context, spaceId SpaceId, params *ReadExceptionListParams, reqEditors ...RequestEditorFn) (*ReadExceptionListResponse, error) { + rsp, err := c.ReadExceptionList(ctx, spaceId, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseReadExceptionListResponse(rsp) +} + +// CreateExceptionListWithBodyWithResponse request with arbitrary body returning *CreateExceptionListResponse +func (c *ClientWithResponses) CreateExceptionListWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateExceptionListResponse, error) { + rsp, err := c.CreateExceptionListWithBody(ctx, spaceId, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateExceptionListResponse(rsp) +} + +func (c *ClientWithResponses) CreateExceptionListWithResponse(ctx context.Context, spaceId SpaceId, body CreateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateExceptionListResponse, error) { + rsp, err := c.CreateExceptionList(ctx, spaceId, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateExceptionListResponse(rsp) +} + +// UpdateExceptionListWithBodyWithResponse request with arbitrary body returning *UpdateExceptionListResponse +func (c *ClientWithResponses) UpdateExceptionListWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateExceptionListResponse, error) { + rsp, err := c.UpdateExceptionListWithBody(ctx, spaceId, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateExceptionListResponse(rsp) +} + +func (c *ClientWithResponses) UpdateExceptionListWithResponse(ctx context.Context, spaceId SpaceId, body UpdateExceptionListJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateExceptionListResponse, error) { + rsp, err := c.UpdateExceptionList(ctx, spaceId, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateExceptionListResponse(rsp) +} + +// DeleteExceptionListItemWithResponse request returning *DeleteExceptionListItemResponse +func (c *ClientWithResponses) DeleteExceptionListItemWithResponse(ctx context.Context, spaceId SpaceId, params *DeleteExceptionListItemParams, reqEditors ...RequestEditorFn) (*DeleteExceptionListItemResponse, error) { + rsp, err := c.DeleteExceptionListItem(ctx, spaceId, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseDeleteExceptionListItemResponse(rsp) +} + +// ReadExceptionListItemWithResponse request returning *ReadExceptionListItemResponse +func (c *ClientWithResponses) ReadExceptionListItemWithResponse(ctx context.Context, spaceId SpaceId, params *ReadExceptionListItemParams, reqEditors ...RequestEditorFn) (*ReadExceptionListItemResponse, error) { + rsp, err := c.ReadExceptionListItem(ctx, spaceId, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseReadExceptionListItemResponse(rsp) +} + +// CreateExceptionListItemWithBodyWithResponse request with arbitrary body returning *CreateExceptionListItemResponse +func (c *ClientWithResponses) CreateExceptionListItemWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateExceptionListItemResponse, error) { + rsp, err := c.CreateExceptionListItemWithBody(ctx, spaceId, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateExceptionListItemResponse(rsp) +} + +func (c *ClientWithResponses) CreateExceptionListItemWithResponse(ctx context.Context, spaceId SpaceId, body CreateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateExceptionListItemResponse, error) { + rsp, err := c.CreateExceptionListItem(ctx, spaceId, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateExceptionListItemResponse(rsp) +} + +// UpdateExceptionListItemWithBodyWithResponse request with arbitrary body returning *UpdateExceptionListItemResponse +func (c *ClientWithResponses) UpdateExceptionListItemWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateExceptionListItemResponse, error) { + rsp, err := c.UpdateExceptionListItemWithBody(ctx, spaceId, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateExceptionListItemResponse(rsp) +} + +func (c *ClientWithResponses) UpdateExceptionListItemWithResponse(ctx context.Context, spaceId SpaceId, body UpdateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateExceptionListItemResponse, error) { + rsp, err := c.UpdateExceptionListItem(ctx, spaceId, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateExceptionListItemResponse(rsp) +} + // PostMaintenanceWindowWithBodyWithResponse request with arbitrary body returning *PostMaintenanceWindowResponse func (c *ClientWithResponses) PostMaintenanceWindowWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostMaintenanceWindowResponse, error) { rsp, err := c.PostMaintenanceWindowWithBody(ctx, spaceId, contentType, body, reqEditors...) @@ -147368,258 +147424,6 @@ func ParseGetEntityStoreStatusResponse(rsp *http.Response) (*GetEntityStoreStatu return response, nil } -// ParseDeleteExceptionListResponse parses an HTTP response from a DeleteExceptionListWithResponse call -func ParseDeleteExceptionListResponse(rsp *http.Response) (*DeleteExceptionListResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &DeleteExceptionListResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityExceptionsAPIExceptionList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseReadExceptionListResponse parses an HTTP response from a ReadExceptionListWithResponse call -func ParseReadExceptionListResponse(rsp *http.Response) (*ReadExceptionListResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &ReadExceptionListResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityExceptionsAPIExceptionList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseCreateExceptionListResponse parses an HTTP response from a CreateExceptionListWithResponse call -func ParseCreateExceptionListResponse(rsp *http.Response) (*CreateExceptionListResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &CreateExceptionListResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityExceptionsAPIExceptionList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON409 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseUpdateExceptionListResponse parses an HTTP response from a UpdateExceptionListWithResponse call -func ParseUpdateExceptionListResponse(rsp *http.Response) (*UpdateExceptionListResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &UpdateExceptionListResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityExceptionsAPIExceptionList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - // ParseDuplicateExceptionListResponse parses an HTTP response from a DuplicateExceptionListWithResponse call func ParseDuplicateExceptionListResponse(rsp *http.Response) (*DuplicateExceptionListResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -147871,258 +147675,6 @@ func ParseImportExceptionListResponse(rsp *http.Response) (*ImportExceptionListR return response, nil } -// ParseDeleteExceptionListItemResponse parses an HTTP response from a DeleteExceptionListItemWithResponse call -func ParseDeleteExceptionListItemResponse(rsp *http.Response) (*DeleteExceptionListItemResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &DeleteExceptionListItemResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityExceptionsAPIExceptionListItem - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseReadExceptionListItemResponse parses an HTTP response from a ReadExceptionListItemWithResponse call -func ParseReadExceptionListItemResponse(rsp *http.Response) (*ReadExceptionListItemResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &ReadExceptionListItemResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityExceptionsAPIExceptionListItem - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseCreateExceptionListItemResponse parses an HTTP response from a CreateExceptionListItemWithResponse call -func ParseCreateExceptionListItemResponse(rsp *http.Response) (*CreateExceptionListItemResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &CreateExceptionListItemResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityExceptionsAPIExceptionListItem - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON409 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseUpdateExceptionListItemResponse parses an HTTP response from a UpdateExceptionListItemWithResponse call -func ParseUpdateExceptionListItemResponse(rsp *http.Response) (*UpdateExceptionListItemResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &UpdateExceptionListItemResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityExceptionsAPIExceptionListItem - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityExceptionsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityExceptionsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - // ParseFindExceptionListItemsResponse parses an HTTP response from a FindExceptionListItemsWithResponse call func ParseFindExceptionListItemsResponse(rsp *http.Response) (*FindExceptionListItemsResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -160669,6 +160221,510 @@ func ParseUpdateRuleResponse(rsp *http.Response) (*UpdateRuleResponse, error) { return response, nil } +// ParseDeleteExceptionListResponse parses an HTTP response from a DeleteExceptionListWithResponse call +func ParseDeleteExceptionListResponse(rsp *http.Response) (*DeleteExceptionListResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &DeleteExceptionListResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityExceptionsAPIExceptionList + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseReadExceptionListResponse parses an HTTP response from a ReadExceptionListWithResponse call +func ParseReadExceptionListResponse(rsp *http.Response) (*ReadExceptionListResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ReadExceptionListResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityExceptionsAPIExceptionList + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseCreateExceptionListResponse parses an HTTP response from a CreateExceptionListWithResponse call +func ParseCreateExceptionListResponse(rsp *http.Response) (*CreateExceptionListResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &CreateExceptionListResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityExceptionsAPIExceptionList + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON409 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseUpdateExceptionListResponse parses an HTTP response from a UpdateExceptionListWithResponse call +func ParseUpdateExceptionListResponse(rsp *http.Response) (*UpdateExceptionListResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &UpdateExceptionListResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityExceptionsAPIExceptionList + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseDeleteExceptionListItemResponse parses an HTTP response from a DeleteExceptionListItemWithResponse call +func ParseDeleteExceptionListItemResponse(rsp *http.Response) (*DeleteExceptionListItemResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &DeleteExceptionListItemResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityExceptionsAPIExceptionListItem + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseReadExceptionListItemResponse parses an HTTP response from a ReadExceptionListItemWithResponse call +func ParseReadExceptionListItemResponse(rsp *http.Response) (*ReadExceptionListItemResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ReadExceptionListItemResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityExceptionsAPIExceptionListItem + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseCreateExceptionListItemResponse parses an HTTP response from a CreateExceptionListItemWithResponse call +func ParseCreateExceptionListItemResponse(rsp *http.Response) (*CreateExceptionListItemResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &CreateExceptionListItemResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityExceptionsAPIExceptionListItem + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON409 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseUpdateExceptionListItemResponse parses an HTTP response from a UpdateExceptionListItemWithResponse call +func ParseUpdateExceptionListItemResponse(rsp *http.Response) (*UpdateExceptionListItemResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &UpdateExceptionListItemResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityExceptionsAPIExceptionListItem + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityExceptionsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityExceptionsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + // ParsePostMaintenanceWindowResponse parses an HTTP response from a PostMaintenanceWindowWithResponse call func ParsePostMaintenanceWindowResponse(rsp *http.Response) (*PostMaintenanceWindowResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) diff --git a/generated/kbapi/transform_schema.go b/generated/kbapi/transform_schema.go index a377cfe9b..32db70360 100644 --- a/generated/kbapi/transform_schema.go +++ b/generated/kbapi/transform_schema.go @@ -691,6 +691,8 @@ func transformKibanaPaths(schema *Schema) { "/api/actions/connector/{id}", "/api/actions/connectors", "/api/detection_engine/rules", + "/api/exception_lists", + "/api/exception_lists/items", } // Add a spaceId parameter if not already present diff --git a/internal/clients/kibana_oapi/exceptions.go b/internal/clients/kibana_oapi/exceptions.go index 188b83826..8c1d39464 100644 --- a/internal/clients/kibana_oapi/exceptions.go +++ b/internal/clients/kibana_oapi/exceptions.go @@ -10,8 +10,8 @@ import ( ) // GetExceptionList reads an exception list from the API by ID or list_id -func GetExceptionList(ctx context.Context, client *Client, params *kbapi.ReadExceptionListParams) (*kbapi.ReadExceptionListResponse, diag.Diagnostics) { - resp, err := client.API.ReadExceptionListWithResponse(ctx, params) +func GetExceptionList(ctx context.Context, client *Client, spaceId string, params *kbapi.ReadExceptionListParams) (*kbapi.ReadExceptionListResponse, diag.Diagnostics) { + resp, err := client.API.ReadExceptionListWithResponse(ctx, kbapi.SpaceId(spaceId), params) if err != nil { return nil, diagutil.FrameworkDiagFromError(err) } @@ -27,8 +27,8 @@ func GetExceptionList(ctx context.Context, client *Client, params *kbapi.ReadExc } // CreateExceptionList creates a new exception list. -func CreateExceptionList(ctx context.Context, client *Client, body kbapi.CreateExceptionListJSONRequestBody) (*kbapi.CreateExceptionListResponse, diag.Diagnostics) { - resp, err := client.API.CreateExceptionListWithResponse(ctx, body) +func CreateExceptionList(ctx context.Context, client *Client, spaceId string, body kbapi.CreateExceptionListJSONRequestBody) (*kbapi.CreateExceptionListResponse, diag.Diagnostics) { + resp, err := client.API.CreateExceptionListWithResponse(ctx, kbapi.SpaceId(spaceId), body) if err != nil { return nil, diagutil.FrameworkDiagFromError(err) } @@ -42,8 +42,8 @@ func CreateExceptionList(ctx context.Context, client *Client, body kbapi.CreateE } // UpdateExceptionList updates an existing exception list. -func UpdateExceptionList(ctx context.Context, client *Client, body kbapi.UpdateExceptionListJSONRequestBody) (*kbapi.UpdateExceptionListResponse, diag.Diagnostics) { - resp, err := client.API.UpdateExceptionListWithResponse(ctx, body) +func UpdateExceptionList(ctx context.Context, client *Client, spaceId string, body kbapi.UpdateExceptionListJSONRequestBody) (*kbapi.UpdateExceptionListResponse, diag.Diagnostics) { + resp, err := client.API.UpdateExceptionListWithResponse(ctx, kbapi.SpaceId(spaceId), body) if err != nil { return nil, diagutil.FrameworkDiagFromError(err) } @@ -57,8 +57,8 @@ func UpdateExceptionList(ctx context.Context, client *Client, body kbapi.UpdateE } // DeleteExceptionList deletes an existing exception list. -func DeleteExceptionList(ctx context.Context, client *Client, params *kbapi.DeleteExceptionListParams) diag.Diagnostics { - resp, err := client.API.DeleteExceptionListWithResponse(ctx, params) +func DeleteExceptionList(ctx context.Context, client *Client, spaceId string, params *kbapi.DeleteExceptionListParams) diag.Diagnostics { + resp, err := client.API.DeleteExceptionListWithResponse(ctx, kbapi.SpaceId(spaceId), params) if err != nil { return diagutil.FrameworkDiagFromError(err) } @@ -74,8 +74,8 @@ func DeleteExceptionList(ctx context.Context, client *Client, params *kbapi.Dele } // GetExceptionListItem reads an exception list item from the API by ID or item_id -func GetExceptionListItem(ctx context.Context, client *Client, params *kbapi.ReadExceptionListItemParams) (*kbapi.ReadExceptionListItemResponse, diag.Diagnostics) { - resp, err := client.API.ReadExceptionListItemWithResponse(ctx, params) +func GetExceptionListItem(ctx context.Context, client *Client, spaceId string, params *kbapi.ReadExceptionListItemParams) (*kbapi.ReadExceptionListItemResponse, diag.Diagnostics) { + resp, err := client.API.ReadExceptionListItemWithResponse(ctx, kbapi.SpaceId(spaceId), params) if err != nil { return nil, diagutil.FrameworkDiagFromError(err) } @@ -91,8 +91,8 @@ func GetExceptionListItem(ctx context.Context, client *Client, params *kbapi.Rea } // CreateExceptionListItem creates a new exception list item. -func CreateExceptionListItem(ctx context.Context, client *Client, body kbapi.CreateExceptionListItemJSONRequestBody) (*kbapi.CreateExceptionListItemResponse, diag.Diagnostics) { - resp, err := client.API.CreateExceptionListItemWithResponse(ctx, body) +func CreateExceptionListItem(ctx context.Context, client *Client, spaceId string, body kbapi.CreateExceptionListItemJSONRequestBody) (*kbapi.CreateExceptionListItemResponse, diag.Diagnostics) { + resp, err := client.API.CreateExceptionListItemWithResponse(ctx, kbapi.SpaceId(spaceId), body) if err != nil { return nil, diagutil.FrameworkDiagFromError(err) } @@ -106,8 +106,8 @@ func CreateExceptionListItem(ctx context.Context, client *Client, body kbapi.Cre } // UpdateExceptionListItem updates an existing exception list item. -func UpdateExceptionListItem(ctx context.Context, client *Client, body kbapi.UpdateExceptionListItemJSONRequestBody) (*kbapi.UpdateExceptionListItemResponse, diag.Diagnostics) { - resp, err := client.API.UpdateExceptionListItemWithResponse(ctx, body) +func UpdateExceptionListItem(ctx context.Context, client *Client, spaceId string, body kbapi.UpdateExceptionListItemJSONRequestBody) (*kbapi.UpdateExceptionListItemResponse, diag.Diagnostics) { + resp, err := client.API.UpdateExceptionListItemWithResponse(ctx, kbapi.SpaceId(spaceId), body) if err != nil { return nil, diagutil.FrameworkDiagFromError(err) } @@ -121,8 +121,8 @@ func UpdateExceptionListItem(ctx context.Context, client *Client, body kbapi.Upd } // DeleteExceptionListItem deletes an existing exception list item. -func DeleteExceptionListItem(ctx context.Context, client *Client, params *kbapi.DeleteExceptionListItemParams) diag.Diagnostics { - resp, err := client.API.DeleteExceptionListItemWithResponse(ctx, params) +func DeleteExceptionListItem(ctx context.Context, client *Client, spaceId string, params *kbapi.DeleteExceptionListItemParams) diag.Diagnostics { + resp, err := client.API.DeleteExceptionListItemWithResponse(ctx, kbapi.SpaceId(spaceId), params) if err != nil { return diagutil.FrameworkDiagFromError(err) } diff --git a/internal/kibana/security/exception_item/acc_test.go b/internal/kibana/security/exception_item/acc_test.go index ae564a599..4837bf70e 100644 --- a/internal/kibana/security/exception_item/acc_test.go +++ b/internal/kibana/security/exception_item/acc_test.go @@ -1,10 +1,12 @@ package exception_item_test import ( + "fmt" "testing" "github.com/elastic/terraform-provider-elasticstack/internal/acctest" "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" + "github.com/google/uuid" "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-plugin-testing/config" "github.com/hashicorp/terraform-plugin-testing/helper/resource" @@ -70,3 +72,80 @@ func TestAccResourceExceptionItem(t *testing.T) { }, }) } + +func TestAccResourceExceptionItemWithSpace(t *testing.T) { + resourceName := "elasticstack_kibana_security_exception_item.test" + spaceResourceName := "elasticstack_kibana_space.test" + spaceID := fmt.Sprintf("test-space-%s", uuid.New().String()[:8]) + entriesCreate := `[{"field":"process.name","operator":"included","type":"match","value":"test-process-space"}]` + entriesUpdate := `[{"field":"process.name","operator":"included","type":"match","value":"test-process-space-updated"}]` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ConfigDirectory: acctest.NamedTestCaseDirectory("create"), + ConfigVariables: config.Variables{ + "space_id": config.StringVariable(spaceID), + "list_id": config.StringVariable("test-exception-list-for-item-space"), + "item_id": config.StringVariable("test-exception-item-space"), + "name": config.StringVariable("Test Exception Item in Space"), + "description": config.StringVariable("Test exception item in custom space"), + "type": config.StringVariable("simple"), + "namespace_type": config.StringVariable("single"), + "entries": config.StringVariable(entriesCreate), + "tags": config.ListVariable(config.StringVariable("test"), config.StringVariable("space")), + }, + Check: resource.ComposeTestCheckFunc( + // Check space attributes + resource.TestCheckResourceAttr(spaceResourceName, "space_id", spaceID), + resource.TestCheckResourceAttr(spaceResourceName, "name", "Test Space for Exception Items"), + + // Check exception item attributes + resource.TestCheckResourceAttr(resourceName, "space_id", spaceID), + resource.TestCheckResourceAttr(resourceName, "item_id", "test-exception-item-space"), + resource.TestCheckResourceAttr(resourceName, "name", "Test Exception Item in Space"), + resource.TestCheckResourceAttr(resourceName, "description", "Test exception item in custom space"), + resource.TestCheckResourceAttr(resourceName, "type", "simple"), + resource.TestCheckResourceAttr(resourceName, "namespace_type", "single"), + resource.TestCheckResourceAttr(resourceName, "tags.0", "test"), + resource.TestCheckResourceAttr(resourceName, "tags.1", "space"), + resource.TestCheckResourceAttrSet(resourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, "entries"), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "created_by"), + ), + }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ConfigDirectory: acctest.NamedTestCaseDirectory("update"), + ConfigVariables: config.Variables{ + "space_id": config.StringVariable(spaceID), + "list_id": config.StringVariable("test-exception-list-for-item-space"), + "item_id": config.StringVariable("test-exception-item-space"), + "name": config.StringVariable("Test Exception Item in Space Updated"), + "description": config.StringVariable("Updated description in space"), + "type": config.StringVariable("simple"), + "namespace_type": config.StringVariable("single"), + "entries": config.StringVariable(entriesUpdate), + "tags": config.ListVariable(config.StringVariable("test"), config.StringVariable("space"), config.StringVariable("updated")), + }, + Check: resource.ComposeTestCheckFunc( + // Check space attributes remain the same + resource.TestCheckResourceAttr(spaceResourceName, "space_id", spaceID), + resource.TestCheckResourceAttr(spaceResourceName, "name", "Test Space for Exception Items"), + + // Check updated exception item attributes + resource.TestCheckResourceAttr(resourceName, "space_id", spaceID), + resource.TestCheckResourceAttr(resourceName, "name", "Test Exception Item in Space Updated"), + resource.TestCheckResourceAttr(resourceName, "description", "Updated description in space"), + resource.TestCheckResourceAttr(resourceName, "tags.0", "test"), + resource.TestCheckResourceAttr(resourceName, "tags.1", "space"), + resource.TestCheckResourceAttr(resourceName, "tags.2", "updated"), + ), + }, + }, + }) +} diff --git a/internal/kibana/security/exception_item/create.go b/internal/kibana/security/exception_item/create.go index 49ca87c7c..117b1fb3c 100644 --- a/internal/kibana/security/exception_item/create.go +++ b/internal/kibana/security/exception_item/create.go @@ -130,7 +130,7 @@ func (r *ExceptionItemResource) Create(ctx context.Context, req resource.CreateR } // Create the exception item - createResp, diags := kibana_oapi.CreateExceptionListItem(ctx, client, body) + createResp, diags := kibana_oapi.CreateExceptionListItem(ctx, client, plan.SpaceID.ValueString(), body) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return @@ -150,7 +150,7 @@ func (r *ExceptionItemResource) Create(ctx context.Context, req resource.CreateR Id: (*kbapi.SecurityExceptionsAPIExceptionListItemId)(&createResp.JSON200.Id), } - readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, readParams) + readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, plan.SpaceID.ValueString(), readParams) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return diff --git a/internal/kibana/security/exception_item/delete.go b/internal/kibana/security/exception_item/delete.go index 4edb4d4c9..de2148bd3 100644 --- a/internal/kibana/security/exception_item/delete.go +++ b/internal/kibana/security/exception_item/delete.go @@ -29,6 +29,6 @@ func (r *ExceptionItemResource) Delete(ctx context.Context, req resource.DeleteR Id: &id, } - diags = kibana_oapi.DeleteExceptionListItem(ctx, client, params) + diags = kibana_oapi.DeleteExceptionListItem(ctx, client, state.SpaceID.ValueString(), params) resp.Diagnostics.Append(diags...) } diff --git a/internal/kibana/security/exception_item/models.go b/internal/kibana/security/exception_item/models.go index 4152fa484..05853187f 100644 --- a/internal/kibana/security/exception_item/models.go +++ b/internal/kibana/security/exception_item/models.go @@ -7,6 +7,7 @@ import ( type ExceptionItemModel struct { ID types.String `tfsdk:"id"` + SpaceID types.String `tfsdk:"space_id"` ItemID types.String `tfsdk:"item_id"` ListID types.String `tfsdk:"list_id"` Name types.String `tfsdk:"name"` diff --git a/internal/kibana/security/exception_item/read.go b/internal/kibana/security/exception_item/read.go index ba9d3fd41..63c534fdf 100644 --- a/internal/kibana/security/exception_item/read.go +++ b/internal/kibana/security/exception_item/read.go @@ -29,7 +29,7 @@ func (r *ExceptionItemResource) Read(ctx context.Context, req resource.ReadReque Id: &id, } - readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, params) + readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, state.SpaceID.ValueString(), params) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return diff --git a/internal/kibana/security/exception_item/schema.go b/internal/kibana/security/exception_item/schema.go index 9bf1c33ae..8b6d3f4cc 100644 --- a/internal/kibana/security/exception_item/schema.go +++ b/internal/kibana/security/exception_item/schema.go @@ -29,6 +29,15 @@ func (r *ExceptionItemResource) Schema(_ context.Context, _ resource.SchemaReque stringplanmodifier.UseStateForUnknown(), }, }, + "space_id": schema.StringAttribute{ + MarkdownDescription: "An identifier for the space. If space_id is not provided, the default space is used.", + Optional: true, + Computed: true, + Default: stringdefault.StaticString("default"), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, "item_id": schema.StringAttribute{ MarkdownDescription: "The exception item's human readable string identifier.", Optional: true, diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf new file mode 100644 index 000000000..3b26db40e --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf @@ -0,0 +1,71 @@ +variable "space_id" { + description = "The Kibana space ID" + type = string +} + +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +variable "name" { + description = "The exception item name" + type = string +} + +variable "description" { + description = "The exception item description" + type = string +} + +variable "type" { + description = "The exception item type" + type = string +} + +variable "namespace_type" { + description = "The namespace type" + type = string +} + +variable "entries" { + description = "The entries JSON" + type = string +} + +variable "tags" { + description = "Tags for the exception item" + type = list(string) +} + +resource "elasticstack_kibana_space" "test" { + space_id = var.space_id + name = "Test Space for Exception Items" + description = "Space for testing exception items" +} + +resource "elasticstack_kibana_security_exception_list" "test" { + space_id = elasticstack_kibana_space.test.space_id + list_id = var.list_id + name = "Test Exception List for Item" + description = "Test exception list" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + space_id = elasticstack_kibana_space.test.space_id + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = var.name + description = var.description + type = var.type + namespace_type = var.namespace_type + entries = var.entries + tags = var.tags +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf new file mode 100644 index 000000000..3b26db40e --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf @@ -0,0 +1,71 @@ +variable "space_id" { + description = "The Kibana space ID" + type = string +} + +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +variable "name" { + description = "The exception item name" + type = string +} + +variable "description" { + description = "The exception item description" + type = string +} + +variable "type" { + description = "The exception item type" + type = string +} + +variable "namespace_type" { + description = "The namespace type" + type = string +} + +variable "entries" { + description = "The entries JSON" + type = string +} + +variable "tags" { + description = "Tags for the exception item" + type = list(string) +} + +resource "elasticstack_kibana_space" "test" { + space_id = var.space_id + name = "Test Space for Exception Items" + description = "Space for testing exception items" +} + +resource "elasticstack_kibana_security_exception_list" "test" { + space_id = elasticstack_kibana_space.test.space_id + list_id = var.list_id + name = "Test Exception List for Item" + description = "Test exception list" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + space_id = elasticstack_kibana_space.test.space_id + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = var.name + description = var.description + type = var.type + namespace_type = var.namespace_type + entries = var.entries + tags = var.tags +} diff --git a/internal/kibana/security/exception_item/update.go b/internal/kibana/security/exception_item/update.go index 7891cf957..edf06cb38 100644 --- a/internal/kibana/security/exception_item/update.go +++ b/internal/kibana/security/exception_item/update.go @@ -121,7 +121,7 @@ func (r *ExceptionItemResource) Update(ctx context.Context, req resource.UpdateR } // Update the exception item - updateResp, diags := kibana_oapi.UpdateExceptionListItem(ctx, client, body) + updateResp, diags := kibana_oapi.UpdateExceptionListItem(ctx, client, plan.SpaceID.ValueString(), body) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return @@ -141,7 +141,7 @@ func (r *ExceptionItemResource) Update(ctx context.Context, req resource.UpdateR Id: (*kbapi.SecurityExceptionsAPIExceptionListItemId)(&updateResp.JSON200.Id), } - readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, readParams) + readResp, diags := kibana_oapi.GetExceptionListItem(ctx, client, plan.SpaceID.ValueString(), readParams) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return diff --git a/internal/kibana/security/exception_list/acc_test.go b/internal/kibana/security/exception_list/acc_test.go index 1db3764f2..0c57cc100 100644 --- a/internal/kibana/security/exception_list/acc_test.go +++ b/internal/kibana/security/exception_list/acc_test.go @@ -1,10 +1,12 @@ package exception_list_test import ( + "fmt" "testing" "github.com/elastic/terraform-provider-elasticstack/internal/acctest" "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" + "github.com/google/uuid" "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-plugin-testing/config" "github.com/hashicorp/terraform-plugin-testing/helper/resource" @@ -62,3 +64,73 @@ func TestAccResourceExceptionList(t *testing.T) { }, }) } + +func TestAccResourceExceptionListWithSpace(t *testing.T) { + resourceName := "elasticstack_kibana_security_exception_list.test" + spaceResourceName := "elasticstack_kibana_space.test" + spaceID := fmt.Sprintf("test-space-%s", uuid.New().String()[:8]) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionListAPISupport), + ConfigDirectory: acctest.NamedTestCaseDirectory("create"), + ConfigVariables: config.Variables{ + "space_id": config.StringVariable(spaceID), + "list_id": config.StringVariable("test-exception-list-space"), + "name": config.StringVariable("Test Exception List in Space"), + "description": config.StringVariable("Test exception list in custom space"), + "type": config.StringVariable("detection"), + "namespace_type": config.StringVariable("single"), + "tags": config.ListVariable(config.StringVariable("test"), config.StringVariable("space")), + }, + Check: resource.ComposeTestCheckFunc( + // Check space attributes + resource.TestCheckResourceAttr(spaceResourceName, "space_id", spaceID), + resource.TestCheckResourceAttr(spaceResourceName, "name", "Test Space for Exception Lists"), + + // Check exception list attributes + resource.TestCheckResourceAttr(resourceName, "space_id", spaceID), + resource.TestCheckResourceAttr(resourceName, "list_id", "test-exception-list-space"), + resource.TestCheckResourceAttr(resourceName, "name", "Test Exception List in Space"), + resource.TestCheckResourceAttr(resourceName, "description", "Test exception list in custom space"), + resource.TestCheckResourceAttr(resourceName, "type", "detection"), + resource.TestCheckResourceAttr(resourceName, "namespace_type", "single"), + resource.TestCheckResourceAttr(resourceName, "tags.0", "test"), + resource.TestCheckResourceAttr(resourceName, "tags.1", "space"), + resource.TestCheckResourceAttrSet(resourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "created_by"), + ), + }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionListAPISupport), + ConfigDirectory: acctest.NamedTestCaseDirectory("update"), + ConfigVariables: config.Variables{ + "space_id": config.StringVariable(spaceID), + "list_id": config.StringVariable("test-exception-list-space"), + "name": config.StringVariable("Test Exception List in Space Updated"), + "description": config.StringVariable("Updated description in space"), + "type": config.StringVariable("detection"), + "namespace_type": config.StringVariable("single"), + "tags": config.ListVariable(config.StringVariable("test"), config.StringVariable("space"), config.StringVariable("updated")), + }, + Check: resource.ComposeTestCheckFunc( + // Check space attributes remain the same + resource.TestCheckResourceAttr(spaceResourceName, "space_id", spaceID), + resource.TestCheckResourceAttr(spaceResourceName, "name", "Test Space for Exception Lists"), + + // Check updated exception list attributes + resource.TestCheckResourceAttr(resourceName, "space_id", spaceID), + resource.TestCheckResourceAttr(resourceName, "name", "Test Exception List in Space Updated"), + resource.TestCheckResourceAttr(resourceName, "description", "Updated description in space"), + resource.TestCheckResourceAttr(resourceName, "tags.0", "test"), + resource.TestCheckResourceAttr(resourceName, "tags.1", "space"), + resource.TestCheckResourceAttr(resourceName, "tags.2", "updated"), + ), + }, + }, + }) +} diff --git a/internal/kibana/security/exception_list/create.go b/internal/kibana/security/exception_list/create.go index 96d78180a..c1e5d6b6f 100644 --- a/internal/kibana/security/exception_list/create.go +++ b/internal/kibana/security/exception_list/create.go @@ -83,7 +83,7 @@ func (r *ExceptionListResource) Create(ctx context.Context, req resource.CreateR } // Create the exception list - createResp, diags := kibana_oapi.CreateExceptionList(ctx, client, body) + createResp, diags := kibana_oapi.CreateExceptionList(ctx, client, plan.SpaceID.ValueString(), body) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return @@ -103,7 +103,7 @@ func (r *ExceptionListResource) Create(ctx context.Context, req resource.CreateR Id: (*kbapi.SecurityExceptionsAPIExceptionListId)(&createResp.JSON200.Id), } - readResp, diags := kibana_oapi.GetExceptionList(ctx, client, readParams) + readResp, diags := kibana_oapi.GetExceptionList(ctx, client, plan.SpaceID.ValueString(), readParams) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return @@ -143,11 +143,12 @@ func (r *ExceptionListResource) updateStateFromAPIResponse(ctx context.Context, // Set optional os_types if apiResp.OsTypes != nil && len(*apiResp.OsTypes) > 0 { - osTypes := make([]string, len(*apiResp.OsTypes)) - for i, osType := range *apiResp.OsTypes { - osTypes[i] = string(osType) - } - list, d := types.ListValueFrom(ctx, types.StringType, osTypes) + // osTypes := make([]string, len(*apiResp.OsTypes)) + // for i, osType := range *apiResp.OsTypes { + // osTypes[i] = string(osType) + // } + // list, d := types.ListValueFrom(ctx, types.StringType, osTypes) + list, d := types.ListValueFrom(ctx, types.StringType, apiResp.OsTypes) diags.Append(d...) model.OsTypes = list } else { diff --git a/internal/kibana/security/exception_list/delete.go b/internal/kibana/security/exception_list/delete.go index a52571c68..8ff642223 100644 --- a/internal/kibana/security/exception_list/delete.go +++ b/internal/kibana/security/exception_list/delete.go @@ -29,6 +29,6 @@ func (r *ExceptionListResource) Delete(ctx context.Context, req resource.DeleteR Id: &id, } - diags = kibana_oapi.DeleteExceptionList(ctx, client, params) + diags = kibana_oapi.DeleteExceptionList(ctx, client, state.SpaceID.ValueString(), params) resp.Diagnostics.Append(diags...) } diff --git a/internal/kibana/security/exception_list/models.go b/internal/kibana/security/exception_list/models.go index a0f8925f0..29bb77ff2 100644 --- a/internal/kibana/security/exception_list/models.go +++ b/internal/kibana/security/exception_list/models.go @@ -6,6 +6,7 @@ import ( type ExceptionListModel struct { ID types.String `tfsdk:"id"` + SpaceID types.String `tfsdk:"space_id"` ListID types.String `tfsdk:"list_id"` Name types.String `tfsdk:"name"` Description types.String `tfsdk:"description"` diff --git a/internal/kibana/security/exception_list/read.go b/internal/kibana/security/exception_list/read.go index e62b45fbd..b44386b17 100644 --- a/internal/kibana/security/exception_list/read.go +++ b/internal/kibana/security/exception_list/read.go @@ -29,7 +29,7 @@ func (r *ExceptionListResource) Read(ctx context.Context, req resource.ReadReque Id: &id, } - readResp, diags := kibana_oapi.GetExceptionList(ctx, client, params) + readResp, diags := kibana_oapi.GetExceptionList(ctx, client, state.SpaceID.ValueString(), params) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return diff --git a/internal/kibana/security/exception_list/schema.go b/internal/kibana/security/exception_list/schema.go index 041756cb1..32121b7b3 100644 --- a/internal/kibana/security/exception_list/schema.go +++ b/internal/kibana/security/exception_list/schema.go @@ -28,6 +28,15 @@ func (r *ExceptionListResource) Schema(_ context.Context, _ resource.SchemaReque stringplanmodifier.UseStateForUnknown(), }, }, + "space_id": schema.StringAttribute{ + MarkdownDescription: "An identifier for the space. If space_id is not provided, the default space is used.", + Optional: true, + Computed: true, + Default: stringdefault.StaticString("default"), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, "list_id": schema.StringAttribute{ MarkdownDescription: "The exception list's human readable string identifier.", Required: true, diff --git a/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/create/exception_list.tf b/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/create/exception_list.tf new file mode 100644 index 000000000..c9122eb0f --- /dev/null +++ b/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/create/exception_list.tf @@ -0,0 +1,50 @@ +variable "space_id" { + description = "The Kibana space ID" + type = string +} + +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "name" { + description = "The exception list name" + type = string +} + +variable "description" { + description = "The exception list description" + type = string +} + +variable "type" { + description = "The exception list type" + type = string +} + +variable "namespace_type" { + description = "The namespace type" + type = string +} + +variable "tags" { + description = "Tags for the exception list" + type = list(string) +} + +resource "elasticstack_kibana_space" "test" { + space_id = var.space_id + name = "Test Space for Exception Lists" + description = "Space for testing exception lists" +} + +resource "elasticstack_kibana_security_exception_list" "test" { + space_id = elasticstack_kibana_space.test.space_id + list_id = var.list_id + name = var.name + description = var.description + type = var.type + namespace_type = var.namespace_type + tags = var.tags +} diff --git a/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/update/exception_list.tf b/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/update/exception_list.tf new file mode 100644 index 000000000..c9122eb0f --- /dev/null +++ b/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/update/exception_list.tf @@ -0,0 +1,50 @@ +variable "space_id" { + description = "The Kibana space ID" + type = string +} + +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "name" { + description = "The exception list name" + type = string +} + +variable "description" { + description = "The exception list description" + type = string +} + +variable "type" { + description = "The exception list type" + type = string +} + +variable "namespace_type" { + description = "The namespace type" + type = string +} + +variable "tags" { + description = "Tags for the exception list" + type = list(string) +} + +resource "elasticstack_kibana_space" "test" { + space_id = var.space_id + name = "Test Space for Exception Lists" + description = "Space for testing exception lists" +} + +resource "elasticstack_kibana_security_exception_list" "test" { + space_id = elasticstack_kibana_space.test.space_id + list_id = var.list_id + name = var.name + description = var.description + type = var.type + namespace_type = var.namespace_type + tags = var.tags +} diff --git a/internal/kibana/security/exception_list/update.go b/internal/kibana/security/exception_list/update.go index c7f9b5196..07a59269b 100644 --- a/internal/kibana/security/exception_list/update.go +++ b/internal/kibana/security/exception_list/update.go @@ -84,7 +84,7 @@ func (r *ExceptionListResource) Update(ctx context.Context, req resource.UpdateR } // Update the exception list - updateResp, diags := kibana_oapi.UpdateExceptionList(ctx, client, body) + updateResp, diags := kibana_oapi.UpdateExceptionList(ctx, client, plan.SpaceID.ValueString(), body) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return @@ -104,7 +104,7 @@ func (r *ExceptionListResource) Update(ctx context.Context, req resource.UpdateR Id: (*kbapi.SecurityExceptionsAPIExceptionListId)(&updateResp.JSON200.Id), } - readResp, diags := kibana_oapi.GetExceptionList(ctx, client, readParams) + readResp, diags := kibana_oapi.GetExceptionList(ctx, client, plan.SpaceID.ValueString(), readParams) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return From d0d929c21c5100924e5e03157ee06fd6dc82a8f4 Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Mon, 24 Nov 2025 09:42:51 -0700 Subject: [PATCH 12/21] Add tests for exception item types --- .../security/exception_item/acc_test.go | 175 ++++++++++++++++-- .../create/exception_item.tf | 16 +- .../update/exception_item.tf | 16 +- .../exists/exception_item.tf | 39 ++++ .../list/exception_item.tf | 57 ++++++ .../match/exception_item.tf | 40 ++++ .../match_any/exception_item.tf | 40 ++++ .../nested/exception_item.tf | 46 +++++ .../wildcard/exception_item.tf | 40 ++++ .../create/exception_item.tf | 16 +- .../update/exception_item.tf | 16 +- 11 files changed, 462 insertions(+), 39 deletions(-) create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Exists/exists/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Match/match/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_MatchAny/match_any/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Wildcard/wildcard/exception_item.tf diff --git a/internal/kibana/security/exception_item/acc_test.go b/internal/kibana/security/exception_item/acc_test.go index 4837bf70e..e169e7927 100644 --- a/internal/kibana/security/exception_item/acc_test.go +++ b/internal/kibana/security/exception_item/acc_test.go @@ -15,9 +15,6 @@ import ( var minExceptionItemAPISupport = version.Must(version.NewVersion("7.9.0")) func TestAccResourceExceptionItem(t *testing.T) { - entriesCreate := `[{"field":"process.name","operator":"included","type":"match","value":"test-process"}]` - entriesUpdate := `[{"field":"process.name","operator":"included","type":"match","value":"test-process-updated"}]` - resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, Steps: []resource.TestStep{ @@ -32,7 +29,6 @@ func TestAccResourceExceptionItem(t *testing.T) { "description": config.StringVariable("Test exception item for acceptance tests"), "type": config.StringVariable("simple"), "namespace_type": config.StringVariable("single"), - "entries": config.StringVariable(entriesCreate), "tags": config.ListVariable(config.StringVariable("test")), }, Check: resource.ComposeTestCheckFunc( @@ -43,7 +39,7 @@ func TestAccResourceExceptionItem(t *testing.T) { resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "namespace_type", "single"), resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "tags.0", "test"), resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_item.test", "id"), - resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_item.test", "entries"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_item.test", "entries.#"), resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_item.test", "created_at"), resource.TestCheckResourceAttrSet("elasticstack_kibana_security_exception_item.test", "created_by"), ), @@ -59,7 +55,6 @@ func TestAccResourceExceptionItem(t *testing.T) { "description": config.StringVariable("Updated description"), "type": config.StringVariable("simple"), "namespace_type": config.StringVariable("single"), - "entries": config.StringVariable(entriesUpdate), "tags": config.ListVariable(config.StringVariable("test"), config.StringVariable("updated")), }, Check: resource.ComposeTestCheckFunc( @@ -77,8 +72,6 @@ func TestAccResourceExceptionItemWithSpace(t *testing.T) { resourceName := "elasticstack_kibana_security_exception_item.test" spaceResourceName := "elasticstack_kibana_space.test" spaceID := fmt.Sprintf("test-space-%s", uuid.New().String()[:8]) - entriesCreate := `[{"field":"process.name","operator":"included","type":"match","value":"test-process-space"}]` - entriesUpdate := `[{"field":"process.name","operator":"included","type":"match","value":"test-process-space-updated"}]` resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -95,7 +88,6 @@ func TestAccResourceExceptionItemWithSpace(t *testing.T) { "description": config.StringVariable("Test exception item in custom space"), "type": config.StringVariable("simple"), "namespace_type": config.StringVariable("single"), - "entries": config.StringVariable(entriesCreate), "tags": config.ListVariable(config.StringVariable("test"), config.StringVariable("space")), }, Check: resource.ComposeTestCheckFunc( @@ -113,7 +105,7 @@ func TestAccResourceExceptionItemWithSpace(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.0", "test"), resource.TestCheckResourceAttr(resourceName, "tags.1", "space"), resource.TestCheckResourceAttrSet(resourceName, "id"), - resource.TestCheckResourceAttrSet(resourceName, "entries"), + resource.TestCheckResourceAttrSet(resourceName, "entries.#"), resource.TestCheckResourceAttrSet(resourceName, "created_at"), resource.TestCheckResourceAttrSet(resourceName, "created_by"), ), @@ -129,7 +121,6 @@ func TestAccResourceExceptionItemWithSpace(t *testing.T) { "description": config.StringVariable("Updated description in space"), "type": config.StringVariable("simple"), "namespace_type": config.StringVariable("single"), - "entries": config.StringVariable(entriesUpdate), "tags": config.ListVariable(config.StringVariable("test"), config.StringVariable("space"), config.StringVariable("updated")), }, Check: resource.ComposeTestCheckFunc( @@ -149,3 +140,165 @@ func TestAccResourceExceptionItemWithSpace(t *testing.T) { }, }) } + +func TestAccResourceExceptionItemEntryType_Match(t *testing.T) { + listID := fmt.Sprintf("test-exception-list-match-%s", uuid.New().String()[:8]) + itemID := fmt.Sprintf("test-exception-item-match-%s", uuid.New().String()[:8]) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("match"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.type", "match"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.field", "process.name"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.operator", "included"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.value", "test-process"), + ), + }, + }, + }) +} + +func TestAccResourceExceptionItemEntryType_MatchAny(t *testing.T) { + listID := fmt.Sprintf("test-exception-list-match-any-%s", uuid.New().String()[:8]) + itemID := fmt.Sprintf("test-exception-item-match-any-%s", uuid.New().String()[:8]) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("match_any"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.type", "match_any"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.field", "process.name"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.operator", "included"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.values.0", "process1"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.values.1", "process2"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.values.2", "process3"), + ), + }, + }, + }) +} + +// func TestAccResourceExceptionItemEntryType_List(t *testing.T) { +// exceptionListID := fmt.Sprintf("test-exception-list-list-entry-%s", uuid.New().String()[:8]) +// itemID := fmt.Sprintf("test-exception-item-list-entry-%s", uuid.New().String()[:8]) +// valueListID := fmt.Sprintf("test-value-list-%s", uuid.New().String()[:8]) + +// resource.Test(t, resource.TestCase{ +// PreCheck: func() { acctest.PreCheck(t) }, +// Steps: []resource.TestStep{ +// { +// SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), +// ProtoV6ProviderFactories: acctest.Providers, +// ConfigDirectory: acctest.NamedTestCaseDirectory("list"), +// ConfigVariables: config.Variables{ +// "exception_list_id": config.StringVariable(exceptionListID), +// "item_id": config.StringVariable(itemID), +// "value_list_id": config.StringVariable(valueListID), +// }, +// Check: resource.ComposeTestCheckFunc( +// resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.type", "list"), +// resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.field", "source.ip"), +// resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.operator", "included"), +// resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.list.id", "test-value-list"), +// resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.list.type", "ip"), +// ), +// }, +// }, +// }) +// } + +func TestAccResourceExceptionItemEntryType_Exists(t *testing.T) { + listID := fmt.Sprintf("test-exception-list-exists-%s", uuid.New().String()[:8]) + itemID := fmt.Sprintf("test-exception-item-exists-%s", uuid.New().String()[:8]) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("exists"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.type", "exists"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.field", "file.hash.sha256"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.operator", "included"), + ), + }, + }, + }) +} + +func TestAccResourceExceptionItemEntryType_Nested(t *testing.T) { + listID := fmt.Sprintf("test-exception-list-nested-%s", uuid.New().String()[:8]) + itemID := fmt.Sprintf("test-exception-item-nested-%s", uuid.New().String()[:8]) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("nested"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.type", "nested"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.field", "parent.field"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.entries.0.type", "match"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.entries.0.field", "nested.field"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.entries.0.operator", "included"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.entries.0.value", "nested-value"), + ), + }, + }, + }) +} + +func TestAccResourceExceptionItemEntryType_Wildcard(t *testing.T) { + listID := fmt.Sprintf("test-exception-list-wildcard-%s", uuid.New().String()[:8]) + itemID := fmt.Sprintf("test-exception-item-wildcard-%s", uuid.New().String()[:8]) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("wildcard"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.type", "wildcard"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.field", "file.path"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.operator", "included"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.value", "/tmp/*.tmp"), + ), + }, + }, + }) +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf index 7cc2cad13..383f279ae 100644 --- a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf @@ -28,11 +28,6 @@ variable "namespace_type" { type = string } -variable "entries" { - description = "The entries JSON" - type = string -} - variable "tags" { description = "Tags for the exception item" type = list(string) @@ -58,6 +53,13 @@ resource "elasticstack_kibana_security_exception_item" "test" { description = var.description type = var.type namespace_type = var.namespace_type - entries = var.entries - tags = var.tags + entries = [ + { + type = "match" + field = "process.name" + operator = "included" + value = "test-process" + } + ] + tags = var.tags } diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf index 7cc2cad13..c3423ad43 100644 --- a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf @@ -28,11 +28,6 @@ variable "namespace_type" { type = string } -variable "entries" { - description = "The entries JSON" - type = string -} - variable "tags" { description = "Tags for the exception item" type = list(string) @@ -58,6 +53,13 @@ resource "elasticstack_kibana_security_exception_item" "test" { description = var.description type = var.type namespace_type = var.namespace_type - entries = var.entries - tags = var.tags + entries = [ + { + type = "match" + field = "process.name" + operator = "included" + value = "test-process-updated" + } + ] + tags = var.tags } diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Exists/exists/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Exists/exists/exception_item.tf new file mode 100644 index 000000000..566d0809f --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Exists/exists/exception_item.tf @@ -0,0 +1,39 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List for Exists Entry" + description = "Test exception list for exists entry type" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Exists Entry" + description = "Test exception item with exists entry type" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "exists" + field = "file.hash.sha256" + operator = "included" + } + ] + tags = ["test", "exists"] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf new file mode 100644 index 000000000..c4cd67c9d --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf @@ -0,0 +1,57 @@ +variable "exception_list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +variable "value_list_id" { + description = "The value list ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.exception_list_id + name = "Test Exception List for List Entry" + description = "Test exception list for list entry type" + type = "detection" + namespace_type = "single" +} + +# Create a value list to reference in the exception item +resource "elasticstack_kibana_security_value_list" "test" { + list_id = var.value_list_id + name = "Test Value List" + description = "Test value list for list entry type" + type = "ip" + values = ["192.168.1.1", "192.168.1.2", "10.0.0.1"] +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - List Entry" + description = "Test exception item with list entry type" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "list" + field = "source.ip" + operator = "included" + list = { + id = elasticstack_kibana_security_value_list.test.list_id + type = "ip" + } + } + ] + tags = ["test", "list"] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Match/match/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Match/match/exception_item.tf new file mode 100644 index 000000000..72106432b --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Match/match/exception_item.tf @@ -0,0 +1,40 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List for Match Entry" + description = "Test exception list for match entry type" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Match Entry" + description = "Test exception item with match entry type" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "match" + field = "process.name" + operator = "included" + value = "test-process" + } + ] + tags = ["test", "match"] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_MatchAny/match_any/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_MatchAny/match_any/exception_item.tf new file mode 100644 index 000000000..7564996cb --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_MatchAny/match_any/exception_item.tf @@ -0,0 +1,40 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List for Match Any Entry" + description = "Test exception list for match_any entry type" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Match Any Entry" + description = "Test exception item with match_any entry type" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "match_any" + field = "process.name" + operator = "included" + values = ["process1", "process2", "process3"] + } + ] + tags = ["test", "match_any"] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf new file mode 100644 index 000000000..15baf96b1 --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf @@ -0,0 +1,46 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List for Nested Entry" + description = "Test exception list for nested entry type" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Nested Entry" + description = "Test exception item with nested entry type" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "nested" + field = "parent.field" + entries = [ + { + type = "match" + field = "nested.field" + operator = "included" + value = "nested-value" + } + ] + } + ] + tags = ["test", "nested"] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Wildcard/wildcard/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Wildcard/wildcard/exception_item.tf new file mode 100644 index 000000000..ea49b6e3d --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Wildcard/wildcard/exception_item.tf @@ -0,0 +1,40 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List for Wildcard Entry" + description = "Test exception list for wildcard entry type" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Wildcard Entry" + description = "Test exception item with wildcard entry type" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "wildcard" + field = "file.path" + operator = "included" + value = "/tmp/*.tmp" + } + ] + tags = ["test", "wildcard"] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf index 3b26db40e..c5a4f0a32 100644 --- a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf @@ -33,11 +33,6 @@ variable "namespace_type" { type = string } -variable "entries" { - description = "The entries JSON" - type = string -} - variable "tags" { description = "Tags for the exception item" type = list(string) @@ -66,6 +61,13 @@ resource "elasticstack_kibana_security_exception_item" "test" { description = var.description type = var.type namespace_type = var.namespace_type - entries = var.entries - tags = var.tags + entries = [ + { + type = "match" + field = "process.name" + operator = "included" + value = "test-process-space" + } + ] + tags = var.tags } diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf index 3b26db40e..e27275925 100644 --- a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf @@ -33,11 +33,6 @@ variable "namespace_type" { type = string } -variable "entries" { - description = "The entries JSON" - type = string -} - variable "tags" { description = "Tags for the exception item" type = list(string) @@ -66,6 +61,13 @@ resource "elasticstack_kibana_security_exception_item" "test" { description = var.description type = var.type namespace_type = var.namespace_type - entries = var.entries - tags = var.tags + entries = [ + { + type = "match" + field = "process.name" + operator = "included" + value = "test-process-space-updated" + } + ] + tags = var.tags } From b1f6bb15c52fe1a31bec8e0be7ce4c40e46bbaa6 Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Mon, 24 Nov 2025 09:46:06 -0700 Subject: [PATCH 13/21] Add typed schema for exception item types --- .../kibana/security/exception_item/create.go | 20 +- .../kibana/security/exception_item/models.go | 546 +++++++++++++++++- .../kibana/security/exception_item/schema.go | 132 ++++- .../kibana/security/exception_item/update.go | 8 +- internal/utils/validators/conditional.go | 4 + 5 files changed, 670 insertions(+), 40 deletions(-) diff --git a/internal/kibana/security/exception_item/create.go b/internal/kibana/security/exception_item/create.go index 117b1fb3c..5a704cca6 100644 --- a/internal/kibana/security/exception_item/create.go +++ b/internal/kibana/security/exception_item/create.go @@ -8,7 +8,6 @@ import ( "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" "github.com/elastic/terraform-provider-elasticstack/internal/utils" - "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -30,10 +29,10 @@ func (r *ExceptionItemResource) Create(ctx context.Context, req resource.CreateR return } - // Parse entries JSON - var entries kbapi.SecurityExceptionsAPIExceptionListItemEntryArray - if err := json.Unmarshal([]byte(plan.Entries.ValueString()), &entries); err != nil { - resp.Diagnostics.AddError("Failed to parse entries JSON", err.Error()) + // Convert entries from Terraform model to API model + entries, diags := convertEntriesToAPI(ctx, plan.Entries) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { return } @@ -229,13 +228,10 @@ func (r *ExceptionItemResource) updateStateFromAPIResponse(ctx context.Context, model.Meta = types.StringNull() } - // Set entries (convert back to JSON and normalize) - entriesJSON, err := json.Marshal(apiResp.Entries) - if err != nil { - diags.AddError("Failed to serialize entries", err.Error()) - return diags - } - model.Entries = jsontypes.NewNormalizedValue(string(entriesJSON)) + // Set entries (convert from API model to Terraform model) + entriesList, d := convertEntriesFromAPI(ctx, apiResp.Entries) + diags.Append(d...) + model.Entries = entriesList // Set optional comments if len(apiResp.Comments) > 0 { diff --git a/internal/kibana/security/exception_item/models.go b/internal/kibana/security/exception_item/models.go index 05853187f..05758f60f 100644 --- a/internal/kibana/security/exception_item/models.go +++ b/internal/kibana/security/exception_item/models.go @@ -1,33 +1,539 @@ package exception_item import ( - "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "context" + "encoding/json" + "fmt" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) type ExceptionItemModel struct { - ID types.String `tfsdk:"id"` - SpaceID types.String `tfsdk:"space_id"` - ItemID types.String `tfsdk:"item_id"` - ListID types.String `tfsdk:"list_id"` - Name types.String `tfsdk:"name"` - Description types.String `tfsdk:"description"` - Type types.String `tfsdk:"type"` - NamespaceType types.String `tfsdk:"namespace_type"` - OsTypes types.List `tfsdk:"os_types"` - Tags types.List `tfsdk:"tags"` - Meta types.String `tfsdk:"meta"` - Entries jsontypes.Normalized `tfsdk:"entries"` - Comments types.List `tfsdk:"comments"` - ExpireTime types.String `tfsdk:"expire_time"` - CreatedAt types.String `tfsdk:"created_at"` - CreatedBy types.String `tfsdk:"created_by"` - UpdatedAt types.String `tfsdk:"updated_at"` - UpdatedBy types.String `tfsdk:"updated_by"` - TieBreakerID types.String `tfsdk:"tie_breaker_id"` + ID types.String `tfsdk:"id"` + SpaceID types.String `tfsdk:"space_id"` + ItemID types.String `tfsdk:"item_id"` + ListID types.String `tfsdk:"list_id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Type types.String `tfsdk:"type"` + NamespaceType types.String `tfsdk:"namespace_type"` + OsTypes types.List `tfsdk:"os_types"` + Tags types.List `tfsdk:"tags"` + Meta types.String `tfsdk:"meta"` + Entries types.List `tfsdk:"entries"` + Comments types.List `tfsdk:"comments"` + ExpireTime types.String `tfsdk:"expire_time"` + CreatedAt types.String `tfsdk:"created_at"` + CreatedBy types.String `tfsdk:"created_by"` + UpdatedAt types.String `tfsdk:"updated_at"` + UpdatedBy types.String `tfsdk:"updated_by"` + TieBreakerID types.String `tfsdk:"tie_breaker_id"` } type CommentModel struct { ID types.String `tfsdk:"id"` Comment types.String `tfsdk:"comment"` } + +type EntryModel struct { + Type types.String `tfsdk:"type"` + Field types.String `tfsdk:"field"` + Operator types.String `tfsdk:"operator"` + Value types.String `tfsdk:"value"` + Values types.List `tfsdk:"values"` + List types.Object `tfsdk:"list"` + Entries types.List `tfsdk:"entries"` +} + +type EntryListModel struct { + ID types.String `tfsdk:"id"` + Type types.String `tfsdk:"type"` +} + +type NestedEntryModel struct { + Type types.String `tfsdk:"type"` + Field types.String `tfsdk:"field"` + Operator types.String `tfsdk:"operator"` + Value types.String `tfsdk:"value"` + Values types.List `tfsdk:"values"` +} + +// convertEntriesToAPI converts Terraform entry models to API entry models +func convertEntriesToAPI(ctx context.Context, entries types.List) (kbapi.SecurityExceptionsAPIExceptionListItemEntryArray, diag.Diagnostics) { + var diags diag.Diagnostics + + if entries.IsNull() || entries.IsUnknown() { + return nil, diags + } + + var entryModels []EntryModel + diags.Append(entries.ElementsAs(ctx, &entryModels, false)...) + if diags.HasError() { + return nil, diags + } + + apiEntries := make(kbapi.SecurityExceptionsAPIExceptionListItemEntryArray, 0, len(entryModels)) + for _, entry := range entryModels { + apiEntry, d := convertEntryToAPI(ctx, entry) + diags.Append(d...) + if d.HasError() { + continue + } + apiEntries = append(apiEntries, apiEntry) + } + + return apiEntries, diags +} + +// convertEntryToAPI converts a single Terraform entry model to an API entry model +func convertEntryToAPI(ctx context.Context, entry EntryModel) (kbapi.SecurityExceptionsAPIExceptionListItemEntry, diag.Diagnostics) { + var diags diag.Diagnostics + var result kbapi.SecurityExceptionsAPIExceptionListItemEntry + + entryType := entry.Type.ValueString() + operator := kbapi.SecurityExceptionsAPIExceptionListItemEntryOperator(entry.Operator.ValueString()) + field := kbapi.SecurityExceptionsAPINonEmptyString(entry.Field.ValueString()) + + switch entryType { + case "match": + // Validate required field + if entry.Value.IsNull() || entry.Value.IsUnknown() || entry.Value.ValueString() == "" { + diags.AddError("Invalid Configuration", "Attribute 'value' is required when type is 'match'") + return result, diags + } + + apiEntry := kbapi.SecurityExceptionsAPIExceptionListItemEntryMatch{ + Type: "match", + Field: field, + Operator: operator, + Value: kbapi.SecurityExceptionsAPINonEmptyString(entry.Value.ValueString()), + } + if err := result.FromSecurityExceptionsAPIExceptionListItemEntryMatch(apiEntry); err != nil { + diags.AddError("Failed to create match entry", err.Error()) + } + + case "match_any": + // Validate required field + if entry.Values.IsNull() || entry.Values.IsUnknown() { + diags.AddError("Invalid Configuration", "Attribute 'values' is required when type is 'match_any'") + return result, diags + } + + var values []string + diags.Append(entry.Values.ElementsAs(ctx, &values, false)...) + if diags.HasError() { + return result, diags + } + + if len(values) == 0 { + diags.AddError("Invalid Configuration", "Attribute 'values' must contain at least one value when type is 'match_any'") + return result, diags + } + + apiValues := make([]kbapi.SecurityExceptionsAPINonEmptyString, len(values)) + for i, v := range values { + apiValues[i] = kbapi.SecurityExceptionsAPINonEmptyString(v) + } + apiEntry := kbapi.SecurityExceptionsAPIExceptionListItemEntryMatchAny{ + Type: "match_any", + Field: field, + Operator: operator, + Value: apiValues, + } + if err := result.FromSecurityExceptionsAPIExceptionListItemEntryMatchAny(apiEntry); err != nil { + diags.AddError("Failed to create match_any entry", err.Error()) + } + + case "list": + // Validate required field + if entry.List.IsNull() || entry.List.IsUnknown() { + diags.AddError("Invalid Configuration", "Attribute 'list' is required when type is 'list'") + return result, diags + } + + var listModel EntryListModel + diags.Append(entry.List.As(ctx, &listModel, basetypes.ObjectAsOptions{})...) + if diags.HasError() { + return result, diags + } + apiEntry := kbapi.SecurityExceptionsAPIExceptionListItemEntryList{ + Type: "list", + Field: field, + Operator: operator, + } + apiEntry.List.Id = kbapi.SecurityExceptionsAPIListId(listModel.ID.ValueString()) + apiEntry.List.Type = kbapi.SecurityExceptionsAPIListType(listModel.Type.ValueString()) + if err := result.FromSecurityExceptionsAPIExceptionListItemEntryList(apiEntry); err != nil { + diags.AddError("Failed to create list entry", err.Error()) + } + + case "exists": + apiEntry := kbapi.SecurityExceptionsAPIExceptionListItemEntryExists{ + Type: "exists", + Field: field, + Operator: operator, + } + if err := result.FromSecurityExceptionsAPIExceptionListItemEntryExists(apiEntry); err != nil { + diags.AddError("Failed to create exists entry", err.Error()) + } + + case "wildcard": + // Validate required field + if entry.Value.IsNull() || entry.Value.IsUnknown() || entry.Value.ValueString() == "" { + diags.AddError("Invalid Configuration", "Attribute 'value' is required when type is 'wildcard'") + return result, diags + } + + apiEntry := kbapi.SecurityExceptionsAPIExceptionListItemEntryMatchWildcard{ + Type: "wildcard", + Field: field, + Operator: operator, + Value: kbapi.SecurityExceptionsAPINonEmptyString(entry.Value.ValueString()), + } + if err := result.FromSecurityExceptionsAPIExceptionListItemEntryMatchWildcard(apiEntry); err != nil { + diags.AddError("Failed to create wildcard entry", err.Error()) + } + + case "nested": + // Validate required field + if entry.Entries.IsNull() || entry.Entries.IsUnknown() { + diags.AddError("Invalid Configuration", "Attribute 'entries' is required when type is 'nested'") + return result, diags + } + + var nestedEntries []NestedEntryModel + diags.Append(entry.Entries.ElementsAs(ctx, &nestedEntries, false)...) + if diags.HasError() { + return result, diags + } + + if len(nestedEntries) == 0 { + diags.AddError("Invalid Configuration", "Attribute 'entries' must contain at least one entry when type is 'nested'") + return result, diags + } + + apiNestedEntries := make([]kbapi.SecurityExceptionsAPIExceptionListItemEntryNestedEntryItem, 0, len(nestedEntries)) + for _, ne := range nestedEntries { + nestedAPIEntry, d := convertNestedEntryToAPI(ctx, ne) + diags.Append(d...) + if d.HasError() { + continue + } + apiNestedEntries = append(apiNestedEntries, nestedAPIEntry) + } + + apiEntry := kbapi.SecurityExceptionsAPIExceptionListItemEntryNested{ + Type: "nested", + Field: field, + Entries: apiNestedEntries, + } + if err := result.FromSecurityExceptionsAPIExceptionListItemEntryNested(apiEntry); err != nil { + diags.AddError("Failed to create nested entry", err.Error()) + } + + default: + diags.AddError("Invalid entry type", fmt.Sprintf("Unknown entry type: %s", entryType)) + } + + return result, diags +} + +// convertNestedEntryToAPI converts a nested entry model to an API nested entry model +func convertNestedEntryToAPI(ctx context.Context, entry NestedEntryModel) (kbapi.SecurityExceptionsAPIExceptionListItemEntryNestedEntryItem, diag.Diagnostics) { + var diags diag.Diagnostics + var result kbapi.SecurityExceptionsAPIExceptionListItemEntryNestedEntryItem + + entryType := entry.Type.ValueString() + operator := kbapi.SecurityExceptionsAPIExceptionListItemEntryOperator(entry.Operator.ValueString()) + field := kbapi.SecurityExceptionsAPINonEmptyString(entry.Field.ValueString()) + + switch entryType { + case "match": + // Validate required field + if entry.Value.IsNull() || entry.Value.IsUnknown() || entry.Value.ValueString() == "" { + diags.AddError("Invalid Configuration", "Attribute 'value' is required for nested entry when type is 'match'") + return result, diags + } + + apiEntry := kbapi.SecurityExceptionsAPIExceptionListItemEntryMatch{ + Type: "match", + Field: field, + Operator: operator, + Value: kbapi.SecurityExceptionsAPINonEmptyString(entry.Value.ValueString()), + } + if err := result.FromSecurityExceptionsAPIExceptionListItemEntryMatch(apiEntry); err != nil { + diags.AddError("Failed to create nested match entry", err.Error()) + } + + case "match_any": + // Validate required field + if entry.Values.IsNull() || entry.Values.IsUnknown() { + diags.AddError("Invalid Configuration", "Attribute 'values' is required for nested entry when type is 'match_any'") + return result, diags + } + + var values []string + diags.Append(entry.Values.ElementsAs(ctx, &values, false)...) + if diags.HasError() { + return result, diags + } + + if len(values) == 0 { + diags.AddError("Invalid Configuration", "Attribute 'values' must contain at least one value for nested entry when type is 'match_any'") + return result, diags + } + + apiValues := make([]kbapi.SecurityExceptionsAPINonEmptyString, len(values)) + for i, v := range values { + apiValues[i] = kbapi.SecurityExceptionsAPINonEmptyString(v) + } + apiEntry := kbapi.SecurityExceptionsAPIExceptionListItemEntryMatchAny{ + Type: "match_any", + Field: field, + Operator: operator, + Value: apiValues, + } + if err := result.FromSecurityExceptionsAPIExceptionListItemEntryMatchAny(apiEntry); err != nil { + diags.AddError("Failed to create nested match_any entry", err.Error()) + } + + case "exists": + apiEntry := kbapi.SecurityExceptionsAPIExceptionListItemEntryExists{ + Type: "exists", + Field: field, + Operator: operator, + } + if err := result.FromSecurityExceptionsAPIExceptionListItemEntryExists(apiEntry); err != nil { + diags.AddError("Failed to create nested exists entry", err.Error()) + } + + default: + diags.AddError("Invalid nested entry type", fmt.Sprintf("Unknown nested entry type: %s. Only 'match', 'match_any', and 'exists' are allowed.", entryType)) + } + + return result, diags +} + +// convertEntriesFromAPI converts API entry models to Terraform entry models +func convertEntriesFromAPI(ctx context.Context, apiEntries kbapi.SecurityExceptionsAPIExceptionListItemEntryArray) (types.List, diag.Diagnostics) { + var diags diag.Diagnostics + + if len(apiEntries) == 0 { + return types.ListNull(types.ObjectType{ + AttrTypes: getEntryAttrTypes(), + }), diags + } + + entries := make([]EntryModel, 0, len(apiEntries)) + for _, apiEntry := range apiEntries { + entry, d := convertEntryFromAPI(ctx, apiEntry) + diags.Append(d...) + if d.HasError() { + continue + } + entries = append(entries, entry) + } + + list, d := types.ListValueFrom(ctx, types.ObjectType{ + AttrTypes: getEntryAttrTypes(), + }, entries) + diags.Append(d...) + return list, diags +} + +// convertEntryFromAPI converts a single API entry to a Terraform entry model +func convertEntryFromAPI(ctx context.Context, apiEntry kbapi.SecurityExceptionsAPIExceptionListItemEntry) (EntryModel, diag.Diagnostics) { + var diags diag.Diagnostics + var entry EntryModel + + // Marshal the entry back to JSON to inspect its type + entryBytes, err := apiEntry.MarshalJSON() + if err != nil { + diags.AddError("Failed to marshal entry", err.Error()) + return entry, diags + } + + // Try to unmarshal into a map to determine the type + var entryMap map[string]interface{} + if err := json.Unmarshal(entryBytes, &entryMap); err != nil { + diags.AddError("Failed to unmarshal entry", err.Error()) + return entry, diags + } + + entryType, ok := entryMap["type"].(string) + if !ok { + diags.AddError("Invalid entry", "Entry is missing 'type' field") + return entry, diags + } + + entry.Type = types.StringValue(entryType) + if field, ok := entryMap["field"].(string); ok { + entry.Field = types.StringValue(field) + } + if operator, ok := entryMap["operator"].(string); ok { + entry.Operator = types.StringValue(operator) + } + + switch entryType { + case "match", "wildcard": + if value, ok := entryMap["value"].(string); ok { + entry.Value = types.StringValue(value) + } else { + entry.Value = types.StringNull() + } + entry.Values = types.ListNull(types.StringType) + entry.List = types.ObjectNull(getListAttrTypes()) + entry.Entries = types.ListNull(types.ObjectType{AttrTypes: getNestedEntryAttrTypes()}) + + case "match_any": + if values, ok := entryMap["value"].([]interface{}); ok { + strValues := make([]string, 0, len(values)) + for _, v := range values { + if str, ok := v.(string); ok { + strValues = append(strValues, str) + } + } + list, d := types.ListValueFrom(ctx, types.StringType, strValues) + diags.Append(d...) + entry.Values = list + } else { + entry.Values = types.ListNull(types.StringType) + } + entry.Value = types.StringNull() + entry.List = types.ObjectNull(getListAttrTypes()) + entry.Entries = types.ListNull(types.ObjectType{AttrTypes: getNestedEntryAttrTypes()}) + + case "list": + if listData, ok := entryMap["list"].(map[string]interface{}); ok { + listModel := EntryListModel{ + ID: types.StringValue(listData["id"].(string)), + Type: types.StringValue(listData["type"].(string)), + } + obj, d := types.ObjectValueFrom(ctx, getListAttrTypes(), listModel) + diags.Append(d...) + entry.List = obj + } else { + entry.List = types.ObjectNull(getListAttrTypes()) + } + entry.Value = types.StringNull() + entry.Values = types.ListNull(types.StringType) + entry.Entries = types.ListNull(types.ObjectType{AttrTypes: getNestedEntryAttrTypes()}) + + case "exists": + entry.Value = types.StringNull() + entry.Values = types.ListNull(types.StringType) + entry.List = types.ObjectNull(getListAttrTypes()) + entry.Entries = types.ListNull(types.ObjectType{AttrTypes: getNestedEntryAttrTypes()}) + + case "nested": + // Nested entries don't have an operator field in the API + entry.Operator = types.StringNull() + if entriesData, ok := entryMap["entries"].([]interface{}); ok { + nestedEntries := make([]NestedEntryModel, 0, len(entriesData)) + for _, neData := range entriesData { + if neMap, ok := neData.(map[string]interface{}); ok { + ne, d := convertNestedEntryFromMap(ctx, neMap) + diags.Append(d...) + if !d.HasError() { + nestedEntries = append(nestedEntries, ne) + } + } + } + list, d := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: getNestedEntryAttrTypes()}, nestedEntries) + diags.Append(d...) + entry.Entries = list + } else { + entry.Entries = types.ListNull(types.ObjectType{AttrTypes: getNestedEntryAttrTypes()}) + } + entry.Value = types.StringNull() + entry.Values = types.ListNull(types.StringType) + entry.List = types.ObjectNull(getListAttrTypes()) + } + + return entry, diags +} + +// convertNestedEntryFromMap converts a map representation of nested entry to a model +func convertNestedEntryFromMap(ctx context.Context, entryMap map[string]interface{}) (NestedEntryModel, diag.Diagnostics) { + var diags diag.Diagnostics + var entry NestedEntryModel + + if entryType, ok := entryMap["type"].(string); ok { + entry.Type = types.StringValue(entryType) + } + if field, ok := entryMap["field"].(string); ok { + entry.Field = types.StringValue(field) + } + if operator, ok := entryMap["operator"].(string); ok { + entry.Operator = types.StringValue(operator) + } + + entryType := entry.Type.ValueString() + switch entryType { + case "match": + if value, ok := entryMap["value"].(string); ok { + entry.Value = types.StringValue(value) + } else { + entry.Value = types.StringNull() + } + entry.Values = types.ListNull(types.StringType) + + case "match_any": + if values, ok := entryMap["value"].([]interface{}); ok { + strValues := make([]string, 0, len(values)) + for _, v := range values { + if str, ok := v.(string); ok { + strValues = append(strValues, str) + } + } + list, d := types.ListValueFrom(ctx, types.StringType, strValues) + diags.Append(d...) + entry.Values = list + } else { + entry.Values = types.ListNull(types.StringType) + } + entry.Value = types.StringNull() + + case "exists": + entry.Value = types.StringNull() + entry.Values = types.ListNull(types.StringType) + } + + return entry, diags +} + +// getEntryAttrTypes returns the attribute types for entry objects +func getEntryAttrTypes() map[string]attr.Type { + return map[string]attr.Type{ + "type": types.StringType, + "field": types.StringType, + "operator": types.StringType, + "value": types.StringType, + "values": types.ListType{ElemType: types.StringType}, + "list": types.ObjectType{AttrTypes: getListAttrTypes()}, + "entries": types.ListType{ElemType: types.ObjectType{AttrTypes: getNestedEntryAttrTypes()}}, + } +} + +// getListAttrTypes returns the attribute types for list objects +func getListAttrTypes() map[string]attr.Type { + return map[string]attr.Type{ + "id": types.StringType, + "type": types.StringType, + } +} + +// getNestedEntryAttrTypes returns the attribute types for nested entry objects +func getNestedEntryAttrTypes() map[string]attr.Type { + return map[string]attr.Type{ + "type": types.StringType, + "field": types.StringType, + "operator": types.StringType, + "value": types.StringType, + "values": types.ListType{ElemType: types.StringType}, + } +} diff --git a/internal/kibana/security/exception_item/schema.go b/internal/kibana/security/exception_item/schema.go index 8b6d3f4cc..3e99ac38e 100644 --- a/internal/kibana/security/exception_item/schema.go +++ b/internal/kibana/security/exception_item/schema.go @@ -4,8 +4,9 @@ import ( "context" _ "embed" - "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/elastic/terraform-provider-elasticstack/internal/utils/validators" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -98,10 +99,133 @@ func (r *ExceptionItemResource) Schema(_ context.Context, _ resource.SchemaReque MarkdownDescription: "Placeholder for metadata about the exception item as JSON string.", Optional: true, }, - "entries": schema.StringAttribute{ - MarkdownDescription: "The exception item entries as JSON string. This defines the conditions under which the exception applies.", + "entries": schema.ListNestedAttribute{ + MarkdownDescription: "The exception item entries. This defines the conditions under which the exception applies.", Required: true, - CustomType: jsontypes.NormalizedType{}, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "type": schema.StringAttribute{ + MarkdownDescription: "The type of entry. Valid values: `match`, `match_any`, `list`, `exists`, `nested`, `wildcard`.", + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf("match", "match_any", "list", "exists", "nested", "wildcard"), + }, + }, + "field": schema.StringAttribute{ + MarkdownDescription: "The field name. Required for all entry types.", + Required: true, + }, + "operator": schema.StringAttribute{ + MarkdownDescription: "The operator to use. Valid values: `included`, `excluded`. Note: The operator field is not supported for nested entry types and will be ignored if specified.", + Optional: true, + Validators: []validator.String{ + validators.ForbiddenIfDependentPathOneOf( + path.Root("type"), + []string{"nested"}, + ), + validators.RequiredIfDependentPathOneOf( + path.Root("type"), + []string{"match", "match_any", "list", "exists", "wildcard"}, + ), + stringvalidator.OneOf("included", "excluded"), + }, + }, + "value": schema.StringAttribute{ + MarkdownDescription: "The value to match (for `match` and `wildcard` types).", + Optional: true, + Validators: []validator.String{ + validators.RequiredIfDependentPathOneOf( + path.Root("type"), + []string{"match", "wildcard"}, + ), + }, + }, + "values": schema.ListAttribute{ + ElementType: types.StringType, + MarkdownDescription: "Array of values to match (for `match_any` type).", + Optional: true, + Validators: []validator.List{ + validators.RequiredIfDependentPathOneOf( + path.Root("type"), + []string{"match_any"}, + ), + }, + }, + "list": schema.SingleNestedAttribute{ + MarkdownDescription: "Value list reference (for `list` type).", + Optional: true, + Validators: []validator.Object{ + validators.RequiredIfDependentPathOneOf( + path.Root("type"), + []string{"list"}, + ), + }, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The value list ID.", + Required: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "The value list type (e.g., `keyword`, `ip`, `ip_range`).", + Required: true, + }, + }, + }, + "entries": schema.ListNestedAttribute{ + MarkdownDescription: "Nested entries (for `nested` type). Only `match`, `match_any`, and `exists` entry types are allowed as nested entries.", + Optional: true, + Validators: []validator.List{ + validators.RequiredIfDependentPathOneOf( + path.Root("type"), + []string{"nested"}, + ), + }, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "type": schema.StringAttribute{ + MarkdownDescription: "The type of nested entry. Valid values: `match`, `match_any`, `exists`.", + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf("match", "match_any", "exists"), + }, + }, + "field": schema.StringAttribute{ + MarkdownDescription: "The field name.", + Required: true, + }, + "operator": schema.StringAttribute{ + MarkdownDescription: "The operator to use. Valid values: `included`, `excluded`.", + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf("included", "excluded"), + }, + }, + "value": schema.StringAttribute{ + MarkdownDescription: "The value to match (for `match` type).", + Optional: true, + Validators: []validator.String{ + validators.RequiredIfDependentPathOneOf( + path.Root("type"), + []string{"match"}, + ), + }, + }, + "values": schema.ListAttribute{ + ElementType: types.StringType, + MarkdownDescription: "Array of values to match (for `match_any` type).", + Optional: true, + Validators: []validator.List{ + validators.RequiredIfDependentPathOneOf( + path.Root("type"), + []string{"match_any"}, + ), + }, + }, + }, + }, + }, + }, + }, }, "comments": schema.ListNestedAttribute{ MarkdownDescription: "Array of comments about the exception item.", diff --git a/internal/kibana/security/exception_item/update.go b/internal/kibana/security/exception_item/update.go index edf06cb38..f57ff75c3 100644 --- a/internal/kibana/security/exception_item/update.go +++ b/internal/kibana/security/exception_item/update.go @@ -26,10 +26,10 @@ func (r *ExceptionItemResource) Update(ctx context.Context, req resource.UpdateR return } - // Parse entries JSON - var entries kbapi.SecurityExceptionsAPIExceptionListItemEntryArray - if err := json.Unmarshal([]byte(plan.Entries.ValueString()), &entries); err != nil { - resp.Diagnostics.AddError("Failed to parse entries JSON", err.Error()) + // Convert entries from Terraform model to API model + entries, diags := convertEntriesToAPI(ctx, plan.Entries) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { return } diff --git a/internal/utils/validators/conditional.go b/internal/utils/validators/conditional.go index df011533c..a1a10f2ea 100644 --- a/internal/utils/validators/conditional.go +++ b/internal/utils/validators/conditional.go @@ -93,6 +93,10 @@ func (v condition) ValidateInt64(ctx context.Context, request validator.Int64Req response.Diagnostics.Append(v.validate(ctx, request.Config, request.ConfigValue, request.Path)...) } +func (v condition) ValidateObject(ctx context.Context, request validator.ObjectRequest, response *validator.ObjectResponse) { + response.Diagnostics.Append(v.validate(ctx, request.Config, request.ConfigValue, request.Path)...) +} + // DependantPathOneOf creates a condition that validates a dependent path's value is one of the allowed values. // It returns a condition that checks if the value at dependentPath matches any of the provided allowedValues. // If the dependent field does not have an allowed value, it generates a diagnostic error indicating From 7e61490c6f5e662b15b788243a6cd453139dad27 Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Mon, 24 Nov 2025 09:56:35 -0700 Subject: [PATCH 14/21] Update docs --- .../kibana_security_exception_item.md | 60 ++++++++++++++++--- .../kibana_security_exception_list.md | 1 + 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/docs/resources/kibana_security_exception_item.md b/docs/resources/kibana_security_exception_item.md index 9614d6d3d..523ba6808 100644 --- a/docs/resources/kibana_security_exception_item.md +++ b/docs/resources/kibana_security_exception_item.md @@ -36,14 +36,14 @@ resource "elasticstack_kibana_security_exception_item" "example" { type = "simple" namespace_type = "single" - entries = jsonencode([ + entries = [ { + type = "match" field = "process.name" operator = "included" - type = "match" value = "trusted-process" } - ]) + ] tags = ["trusted", "whitelisted"] } @@ -69,20 +69,20 @@ resource "elasticstack_kibana_security_exception_item" "complex_entry" { namespace_type = "single" # Multiple entries with different operators - entries = jsonencode([ + entries = [ { + type = "match" field = "host.name" operator = "included" - type = "match" value = "trusted-host" }, { + type = "match_any" field = "user.name" operator = "excluded" - type = "match_any" - value = ["admin", "root"] + values = ["admin", "root"] } - ]) + ] os_types = ["linux"] tags = ["complex", "multi-condition"] @@ -95,7 +95,7 @@ resource "elasticstack_kibana_security_exception_item" "complex_entry" { ### Required - `description` (String) Describes the exception item. -- `entries` (String) The exception item entries as JSON string. This defines the conditions under which the exception applies. +- `entries` (Attributes List) The exception item entries. This defines the conditions under which the exception applies. (see [below for nested schema](#nestedatt--entries)) - `list_id` (String) The exception list's identifier that this item belongs to. - `name` (String) The name of the exception item. - `type` (String) The type of exception item. Must be `simple`. @@ -108,6 +108,7 @@ resource "elasticstack_kibana_security_exception_item" "complex_entry" { - `meta` (String) Placeholder for metadata about the exception item as JSON string. - `namespace_type` (String) Determines whether the exception item is available in all Kibana spaces or just the space in which it is created. Can be `single` (default) or `agnostic`. - `os_types` (List of String) Array of OS types for which the exceptions apply. Valid values: `linux`, `macos`, `windows`. +- `space_id` (String) An identifier for the space. If space_id is not provided, the default space is used. - `tags` (List of String) String array containing words and phrases to help categorize exception items. ### Read-Only @@ -119,6 +120,47 @@ resource "elasticstack_kibana_security_exception_item" "complex_entry" { - `updated_at` (String) The timestamp of when the exception item was last updated. - `updated_by` (String) The user who last updated the exception item. + +### Nested Schema for `entries` + +Required: + +- `field` (String) The field name. Required for all entry types. +- `operator` (String) The operator to use. Valid values: `included`, `excluded`. +- `type` (String) The type of entry. Valid values: `match`, `match_any`, `list`, `exists`, `nested`, `wildcard`. + +Optional: + +- `entries` (Attributes List) Nested entries (for `nested` type). Only `match`, `match_any`, and `exists` entry types are allowed as nested entries. (see [below for nested schema](#nestedatt--entries--entries)) +- `list` (Attributes) Value list reference (for `list` type). (see [below for nested schema](#nestedatt--entries--list)) +- `value` (String) The value to match (for `match` and `wildcard` types). +- `values` (List of String) Array of values to match (for `match_any` type). + + +### Nested Schema for `entries.entries` + +Required: + +- `field` (String) The field name. +- `operator` (String) The operator to use. Valid values: `included`, `excluded`. +- `type` (String) The type of nested entry. Valid values: `match`, `match_any`, `exists`. + +Optional: + +- `value` (String) The value to match (for `match` type). +- `values` (List of String) Array of values to match (for `match_any` type). + + + +### Nested Schema for `entries.list` + +Required: + +- `id` (String) The value list ID. +- `type` (String) The value list type (e.g., `keyword`, `ip`, `ip_range`). + + + ### Nested Schema for `comments` diff --git a/docs/resources/kibana_security_exception_list.md b/docs/resources/kibana_security_exception_list.md index c29101c93..974f92fac 100644 --- a/docs/resources/kibana_security_exception_list.md +++ b/docs/resources/kibana_security_exception_list.md @@ -59,6 +59,7 @@ resource "elasticstack_kibana_security_exception_list" "endpoint" { - `meta` (String) Placeholder for metadata about the list container as JSON string. - `namespace_type` (String) Determines whether the exception list is available in all Kibana spaces or just the space in which it is created. Can be `single` (default) or `agnostic`. - `os_types` (List of String) Array of OS types for which the exceptions apply. Valid values: `linux`, `macos`, `windows`. +- `space_id` (String) An identifier for the space. If space_id is not provided, the default space is used. - `tags` (List of String) String array containing words and phrases to help categorize exception containers. ### Read-Only From 51eca7fa1598c65f969aaafcd2bb0363bc21b15b Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Mon, 24 Nov 2025 11:40:45 -0700 Subject: [PATCH 15/21] Add security value list resource --- docs/resources/kibana_security_list.md | 110 + .../resource.tf | 6 +- .../resource_complex.tf | 10 +- .../resource.tf | 6 + .../resource_keyword.tf | 7 + generated/kbapi/kibana.gen.go | 3086 +++++++++-------- generated/kbapi/transform_schema.go | 2 + .../clients/kibana_oapi/security_lists.go | 90 + .../security/exception_item/acc_test.go | 54 +- .../list/exception_item.tf | 6 +- .../nested/exception_item.tf | 4 +- .../kibana/security/security_list/acc_test.go | 105 + .../kibana/security/security_list/create.go | 69 + .../kibana/security/security_list/delete.go | 33 + .../kibana/security/security_list/models.go | 154 + .../kibana/security/security_list/read.go | 50 + .../security_list/resource-description.md | 27 + .../kibana/security/security_list/resource.go | 38 + .../kibana/security/security_list/schema.go | 122 + .../create/main.tf | 22 + .../update/main.tf | 22 + .../keyword_type/main.tf | 22 + .../kibana/security/security_list/update.go | 80 + provider/plugin_framework.go | 2 + 24 files changed, 2572 insertions(+), 1555 deletions(-) create mode 100644 docs/resources/kibana_security_list.md create mode 100644 examples/resources/elasticstack_kibana_security_list/resource.tf create mode 100644 examples/resources/elasticstack_kibana_security_list/resource_keyword.tf create mode 100644 internal/clients/kibana_oapi/security_lists.go create mode 100644 internal/kibana/security/security_list/acc_test.go create mode 100644 internal/kibana/security/security_list/create.go create mode 100644 internal/kibana/security/security_list/delete.go create mode 100644 internal/kibana/security/security_list/models.go create mode 100644 internal/kibana/security/security_list/read.go create mode 100644 internal/kibana/security/security_list/resource-description.md create mode 100644 internal/kibana/security/security_list/resource.go create mode 100644 internal/kibana/security/security_list/schema.go create mode 100644 internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/create/main.tf create mode 100644 internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/update/main.tf create mode 100644 internal/kibana/security/security_list/testdata/TestAccResourceSecurityList_KeywordType/keyword_type/main.tf create mode 100644 internal/kibana/security/security_list/update.go diff --git a/docs/resources/kibana_security_list.md b/docs/resources/kibana_security_list.md new file mode 100644 index 000000000..52299ff2f --- /dev/null +++ b/docs/resources/kibana_security_list.md @@ -0,0 +1,110 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "elasticstack_kibana_security_list Resource - terraform-provider-elasticstack" +subcategory: "Kibana" +description: |- + Manages Kibana security lists (also known as value lists). Security lists are used by exception items to define sets of values for matching or excluding in security rules. + Example Usage + + resource "elasticstack_kibana_security_list" "ip_list" { + space_id = "default" + name = "Trusted IP Addresses" + description = "List of trusted IP addresses for security rules" + type = "ip" + } + + resource "elasticstack_kibana_security_list" "keyword_list" { + space_id = "security" + list_id = "custom-keywords" + name = "Custom Keywords" + description = "Custom keyword list for detection rules" + type = "keyword" + } + + Notes + Security lists define the type of data they can contain via the type attributeOnce created, the type of a list cannot be changedLists can be referenced by exception items to create more sophisticated matching rulesThe list_id is auto-generated if not provided +--- + +# elasticstack_kibana_security_list (Resource) + +Manages Kibana security lists (also known as value lists). Security lists are used by exception items to define sets of values for matching or excluding in security rules. + +## Example Usage + +```terraform +resource "elasticstack_kibana_security_list" "ip_list" { + space_id = "default" + name = "Trusted IP Addresses" + description = "List of trusted IP addresses for security rules" + type = "ip" +} + +resource "elasticstack_kibana_security_list" "keyword_list" { + space_id = "security" + list_id = "custom-keywords" + name = "Custom Keywords" + description = "Custom keyword list for detection rules" + type = "keyword" +} +``` + +## Notes + +- Security lists define the type of data they can contain via the `type` attribute +- Once created, the `type` of a list cannot be changed +- Lists can be referenced by exception items to create more sophisticated matching rules +- The `list_id` is auto-generated if not provided + +## Example Usage + +### IP address list + +```terraform +resource "elasticstack_kibana_security_list" "ip_list" { + space_id = "default" + name = "Trusted IP Addresses" + description = "List of trusted IP addresses for security rules" + type = "ip" +} +``` + +### Keyword list with custom list_id + +```terraform +resource "elasticstack_kibana_security_list" "keyword_list" { + space_id = "security" + list_id = "custom-keywords" + name = "Custom Keywords" + description = "Custom keyword list for detection rules" + type = "keyword" +} +``` + + +## Schema + +### Required + +- `description` (String) Describes the security list. +- `name` (String) The name of the security list. +- `type` (String) Specifies the Elasticsearch data type of values the list contains. Valid values include: `binary`, `boolean`, `byte`, `date`, `date_nanos`, `date_range`, `double`, `double_range`, `float`, `float_range`, `geo_point`, `geo_shape`, `half_float`, `integer`, `integer_range`, `ip`, `ip_range`, `keyword`, `long`, `long_range`, `shape`, `short`, `text`. + +### Optional + +- `deserializer` (String) Determines how retrieved list item values are presented. By default, list items are presented using Handlebars expressions based on the type. +- `id` (String) The unique identifier of the security list (auto-generated by Kibana if not specified). +- `list_id` (String) The value list's human-readable identifier. +- `meta` (String) Placeholder for metadata about the value list as JSON string. +- `serializer` (String) Determines how uploaded list item values are parsed. By default, list items are parsed using named regex groups based on the type. +- `space_id` (String) An identifier for the space. If space_id is not provided, the default space is used. +- `version` (Number) The document version number. + +### Read-Only + +- `created_at` (String) The timestamp of when the list was created. +- `created_by` (String) The user who created the list. +- `immutable` (Boolean) Whether the list is immutable. +- `tie_breaker_id` (String) Field used in search to ensure all containers are sorted and returned correctly. +- `updated_at` (String) The timestamp of when the list was last updated. +- `updated_by` (String) The user who last updated the list. +- `version_id` (String) The version id, normally returned by the API when the document is retrieved. diff --git a/examples/resources/elasticstack_kibana_security_exception_item/resource.tf b/examples/resources/elasticstack_kibana_security_exception_item/resource.tf index f336342f0..22d1bea09 100644 --- a/examples/resources/elasticstack_kibana_security_exception_item/resource.tf +++ b/examples/resources/elasticstack_kibana_security_exception_item/resource.tf @@ -16,14 +16,14 @@ resource "elasticstack_kibana_security_exception_item" "example" { type = "simple" namespace_type = "single" - entries = jsonencode([ + entries = [ { + type = "match" field = "process.name" operator = "included" - type = "match" value = "trusted-process" } - ]) + ] tags = ["trusted", "whitelisted"] } diff --git a/examples/resources/elasticstack_kibana_security_exception_item/resource_complex.tf b/examples/resources/elasticstack_kibana_security_exception_item/resource_complex.tf index d66717a51..6955e5245 100644 --- a/examples/resources/elasticstack_kibana_security_exception_item/resource_complex.tf +++ b/examples/resources/elasticstack_kibana_security_exception_item/resource_complex.tf @@ -15,20 +15,20 @@ resource "elasticstack_kibana_security_exception_item" "complex_entry" { namespace_type = "single" # Multiple entries with different operators - entries = jsonencode([ + entries = [ { + type = "match" field = "host.name" operator = "included" - type = "match" value = "trusted-host" }, { + type = "match_any" field = "user.name" operator = "excluded" - type = "match_any" - value = ["admin", "root"] + values = ["admin", "root"] } - ]) + ] os_types = ["linux"] tags = ["complex", "multi-condition"] diff --git a/examples/resources/elasticstack_kibana_security_list/resource.tf b/examples/resources/elasticstack_kibana_security_list/resource.tf new file mode 100644 index 000000000..b8d89eb50 --- /dev/null +++ b/examples/resources/elasticstack_kibana_security_list/resource.tf @@ -0,0 +1,6 @@ +resource "elasticstack_kibana_security_list" "ip_list" { + space_id = "default" + name = "Trusted IP Addresses" + description = "List of trusted IP addresses for security rules" + type = "ip" +} diff --git a/examples/resources/elasticstack_kibana_security_list/resource_keyword.tf b/examples/resources/elasticstack_kibana_security_list/resource_keyword.tf new file mode 100644 index 000000000..e8aa1e811 --- /dev/null +++ b/examples/resources/elasticstack_kibana_security_list/resource_keyword.tf @@ -0,0 +1,7 @@ +resource "elasticstack_kibana_security_list" "keyword_list" { + space_id = "security" + list_id = "custom-keywords" + name = "Custom Keywords" + description = "Custom keyword list for detection rules" + type = "keyword" +} diff --git a/generated/kbapi/kibana.gen.go b/generated/kbapi/kibana.gen.go index 4f5949154..ae79993af 100644 --- a/generated/kbapi/kibana.gen.go +++ b/generated/kbapi/kibana.gen.go @@ -30609,100 +30609,6 @@ type GetFleetUninstallTokensParams struct { Page *float32 `form:"page,omitempty" json:"page,omitempty"` } -// DeleteListParams defines parameters for DeleteList. -type DeleteListParams struct { - Id SecurityListsAPIListId `form:"id" json:"id"` - - // DeleteReferences Determines whether exception items referencing this value list should be deleted. - DeleteReferences *bool `form:"deleteReferences,omitempty" json:"deleteReferences,omitempty"` - - // IgnoreReferences Determines whether to delete value list without performing any additional checks of where this list may be utilized. - IgnoreReferences *bool `form:"ignoreReferences,omitempty" json:"ignoreReferences,omitempty"` -} - -// ReadListParams defines parameters for ReadList. -type ReadListParams struct { - Id SecurityListsAPIListId `form:"id" json:"id"` -} - -// PatchListJSONBody defines parameters for PatchList. -type PatchListJSONBody struct { - // UnderscoreVersion The version id, normally returned by the API when the document is retrieved. Use it ensure updates are done against the latest version. - UnderscoreVersion *SecurityListsAPIListVersionId `json:"_version,omitempty"` - - // Description Describes the value list. - Description *SecurityListsAPIListDescription `json:"description,omitempty"` - - // Id Value list's identifier. - Id SecurityListsAPIListId `json:"id"` - - // Meta Placeholder for metadata about the value list. - Meta *SecurityListsAPIListMetadata `json:"meta,omitempty"` - - // Name Value list's name. - Name *SecurityListsAPIListName `json:"name,omitempty"` - - // Version The document version number. - Version *SecurityListsAPIListVersion `json:"version,omitempty"` -} - -// CreateListJSONBody defines parameters for CreateList. -type CreateListJSONBody struct { - // Description Describes the value list. - Description SecurityListsAPIListDescription `json:"description"` - - // Deserializer Determines how retrieved list item values are presented. By default list items are presented using these Handelbar expressions: - // - // - `{{{value}}}` - Single value item types, such as `ip`, `long`, `date`, `keyword`, and `text`. - // - `{{{gte}}}-{{{lte}}}` - Range value item types, such as `ip_range`, `double_range`, `float_range`, `integer_range`, and `long_range`. - // - `{{{gte}}},{{{lte}}}` - Date range values. - Deserializer *SecurityListsAPIListDeserializer `json:"deserializer,omitempty"` - - // Id Value list's identifier. - Id *SecurityListsAPIListId `json:"id,omitempty"` - - // Meta Placeholder for metadata about the value list. - Meta *SecurityListsAPIListMetadata `json:"meta,omitempty"` - - // Name Value list's name. - Name SecurityListsAPIListName `json:"name"` - - // Serializer Determines how uploaded list item values are parsed. By default, list items are parsed using these named regex groups: - // - // - `(?.+)` - Single value item types, such as ip, long, date, keyword, and text. - // - `(?.+)-(?.+)|(?.+)` - Range value item types, such as `date_range`, `ip_range`, `double_range`, `float_range`, `integer_range`, and `long_range`. - Serializer *SecurityListsAPIListSerializer `json:"serializer,omitempty"` - - // Type Specifies the Elasticsearch data type of excludes the list container holds. Some common examples: - // - // - `keyword`: Many ECS fields are Elasticsearch keywords - // - `ip`: IP addresses - // - `ip_range`: Range of IP addresses (supports IPv4, IPv6, and CIDR notation) - Type SecurityListsAPIListType `json:"type"` - Version *int `json:"version,omitempty"` -} - -// UpdateListJSONBody defines parameters for UpdateList. -type UpdateListJSONBody struct { - // UnderscoreVersion The version id, normally returned by the API when the document is retrieved. Use it ensure updates are done against the latest version. - UnderscoreVersion *SecurityListsAPIListVersionId `json:"_version,omitempty"` - - // Description Describes the value list. - Description SecurityListsAPIListDescription `json:"description"` - - // Id Value list's identifier. - Id SecurityListsAPIListId `json:"id"` - - // Meta Placeholder for metadata about the value list. - Meta *SecurityListsAPIListMetadata `json:"meta,omitempty"` - - // Name Value list's name. - Name SecurityListsAPIListName `json:"name"` - - // Version The document version number. - Version *SecurityListsAPIListVersion `json:"version,omitempty"` -} - // FindListsParams defines parameters for FindLists. type FindListsParams struct { // Page The page number to return. @@ -46057,6 +45963,100 @@ type UpdateExceptionListItemJSONBody struct { Type SecurityExceptionsAPIExceptionListItemType `json:"type"` } +// DeleteListParams defines parameters for DeleteList. +type DeleteListParams struct { + Id SecurityListsAPIListId `form:"id" json:"id"` + + // DeleteReferences Determines whether exception items referencing this value list should be deleted. + DeleteReferences *bool `form:"deleteReferences,omitempty" json:"deleteReferences,omitempty"` + + // IgnoreReferences Determines whether to delete value list without performing any additional checks of where this list may be utilized. + IgnoreReferences *bool `form:"ignoreReferences,omitempty" json:"ignoreReferences,omitempty"` +} + +// ReadListParams defines parameters for ReadList. +type ReadListParams struct { + Id SecurityListsAPIListId `form:"id" json:"id"` +} + +// PatchListJSONBody defines parameters for PatchList. +type PatchListJSONBody struct { + // UnderscoreVersion The version id, normally returned by the API when the document is retrieved. Use it ensure updates are done against the latest version. + UnderscoreVersion *SecurityListsAPIListVersionId `json:"_version,omitempty"` + + // Description Describes the value list. + Description *SecurityListsAPIListDescription `json:"description,omitempty"` + + // Id Value list's identifier. + Id SecurityListsAPIListId `json:"id"` + + // Meta Placeholder for metadata about the value list. + Meta *SecurityListsAPIListMetadata `json:"meta,omitempty"` + + // Name Value list's name. + Name *SecurityListsAPIListName `json:"name,omitempty"` + + // Version The document version number. + Version *SecurityListsAPIListVersion `json:"version,omitempty"` +} + +// CreateListJSONBody defines parameters for CreateList. +type CreateListJSONBody struct { + // Description Describes the value list. + Description SecurityListsAPIListDescription `json:"description"` + + // Deserializer Determines how retrieved list item values are presented. By default list items are presented using these Handelbar expressions: + // + // - `{{{value}}}` - Single value item types, such as `ip`, `long`, `date`, `keyword`, and `text`. + // - `{{{gte}}}-{{{lte}}}` - Range value item types, such as `ip_range`, `double_range`, `float_range`, `integer_range`, and `long_range`. + // - `{{{gte}}},{{{lte}}}` - Date range values. + Deserializer *SecurityListsAPIListDeserializer `json:"deserializer,omitempty"` + + // Id Value list's identifier. + Id *SecurityListsAPIListId `json:"id,omitempty"` + + // Meta Placeholder for metadata about the value list. + Meta *SecurityListsAPIListMetadata `json:"meta,omitempty"` + + // Name Value list's name. + Name SecurityListsAPIListName `json:"name"` + + // Serializer Determines how uploaded list item values are parsed. By default, list items are parsed using these named regex groups: + // + // - `(?.+)` - Single value item types, such as ip, long, date, keyword, and text. + // - `(?.+)-(?.+)|(?.+)` - Range value item types, such as `date_range`, `ip_range`, `double_range`, `float_range`, `integer_range`, and `long_range`. + Serializer *SecurityListsAPIListSerializer `json:"serializer,omitempty"` + + // Type Specifies the Elasticsearch data type of excludes the list container holds. Some common examples: + // + // - `keyword`: Many ECS fields are Elasticsearch keywords + // - `ip`: IP addresses + // - `ip_range`: Range of IP addresses (supports IPv4, IPv6, and CIDR notation) + Type SecurityListsAPIListType `json:"type"` + Version *int `json:"version,omitempty"` +} + +// UpdateListJSONBody defines parameters for UpdateList. +type UpdateListJSONBody struct { + // UnderscoreVersion The version id, normally returned by the API when the document is retrieved. Use it ensure updates are done against the latest version. + UnderscoreVersion *SecurityListsAPIListVersionId `json:"_version,omitempty"` + + // Description Describes the value list. + Description SecurityListsAPIListDescription `json:"description"` + + // Id Value list's identifier. + Id SecurityListsAPIListId `json:"id"` + + // Meta Placeholder for metadata about the value list. + Meta *SecurityListsAPIListMetadata `json:"meta,omitempty"` + + // Name Value list's name. + Name SecurityListsAPIListName `json:"name"` + + // Version The document version number. + Version *SecurityListsAPIListVersion `json:"version,omitempty"` +} + // PostMaintenanceWindowJSONBody defines parameters for PostMaintenanceWindow. type PostMaintenanceWindowJSONBody struct { // Enabled Whether the current maintenance window is enabled. Disabled maintenance windows do not suppress notifications. @@ -46609,15 +46609,6 @@ type PutFleetSettingsJSONRequestBody PutFleetSettingsJSONBody // PutFleetSpaceSettingsJSONRequestBody defines body for PutFleetSpaceSettings for application/json ContentType. type PutFleetSpaceSettingsJSONRequestBody PutFleetSpaceSettingsJSONBody -// PatchListJSONRequestBody defines body for PatchList for application/json ContentType. -type PatchListJSONRequestBody PatchListJSONBody - -// CreateListJSONRequestBody defines body for CreateList for application/json ContentType. -type CreateListJSONRequestBody CreateListJSONBody - -// UpdateListJSONRequestBody defines body for UpdateList for application/json ContentType. -type UpdateListJSONRequestBody UpdateListJSONBody - // PatchListItemJSONRequestBody defines body for PatchListItem for application/json ContentType. type PatchListItemJSONRequestBody PatchListItemJSONBody @@ -46933,6 +46924,15 @@ type CreateExceptionListItemJSONRequestBody CreateExceptionListItemJSONBody // UpdateExceptionListItemJSONRequestBody defines body for UpdateExceptionListItem for application/json ContentType. type UpdateExceptionListItemJSONRequestBody UpdateExceptionListItemJSONBody +// PatchListJSONRequestBody defines body for PatchList for application/json ContentType. +type PatchListJSONRequestBody PatchListJSONBody + +// CreateListJSONRequestBody defines body for CreateList for application/json ContentType. +type CreateListJSONRequestBody CreateListJSONBody + +// UpdateListJSONRequestBody defines body for UpdateList for application/json ContentType. +type UpdateListJSONRequestBody UpdateListJSONBody + // PostMaintenanceWindowJSONRequestBody defines body for PostMaintenanceWindow for application/json ContentType. type PostMaintenanceWindowJSONRequestBody PostMaintenanceWindowJSONBody @@ -59445,7 +59445,7 @@ func (t SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item) AsSLO // FromSLOsTimesliceMetricBasicMetricWithField overwrites any union data inside the SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item as the provided SLOsTimesliceMetricBasicMetricWithField func (t *SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item) FromSLOsTimesliceMetricBasicMetricWithField(v SLOsTimesliceMetricBasicMetricWithField) error { - v.Aggregation = "last_value" + v.Aggregation = "cardinality" b, err := json.Marshal(v) t.union = b return err @@ -59453,7 +59453,7 @@ func (t *SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item) From // MergeSLOsTimesliceMetricBasicMetricWithField performs a merge with any union data inside the SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item, using the provided SLOsTimesliceMetricBasicMetricWithField func (t *SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item) MergeSLOsTimesliceMetricBasicMetricWithField(v SLOsTimesliceMetricBasicMetricWithField) error { - v.Aggregation = "last_value" + v.Aggregation = "cardinality" b, err := json.Marshal(v) if err != nil { return err @@ -59534,10 +59534,10 @@ func (t SLOsIndicatorPropertiesTimesliceMetric_Params_Metric_Metrics_Item) Value return nil, err } switch discriminator { + case "cardinality": + return t.AsSLOsTimesliceMetricBasicMetricWithField() case "doc_count": return t.AsSLOsTimesliceMetricDocCountMetric() - case "last_value": - return t.AsSLOsTimesliceMetricBasicMetricWithField() case "percentile": return t.AsSLOsTimesliceMetricPercentileMetric() default: @@ -74619,39 +74619,9 @@ type ClientInterface interface { // GetFleetUninstallTokensUninstalltokenid request GetFleetUninstallTokensUninstalltokenid(ctx context.Context, uninstallTokenId string, reqEditors ...RequestEditorFn) (*http.Response, error) - // DeleteList request - DeleteList(ctx context.Context, params *DeleteListParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // ReadList request - ReadList(ctx context.Context, params *ReadListParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // PatchListWithBody request with any body - PatchListWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - PatchList(ctx context.Context, body PatchListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // CreateListWithBody request with any body - CreateListWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - CreateList(ctx context.Context, body CreateListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - - // UpdateListWithBody request with any body - UpdateListWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - UpdateList(ctx context.Context, body UpdateListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - // FindLists request FindLists(ctx context.Context, params *FindListsParams, reqEditors ...RequestEditorFn) (*http.Response, error) - // DeleteListIndex request - DeleteListIndex(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) - - // ReadListIndex request - ReadListIndex(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) - - // CreateListIndex request - CreateListIndex(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) - // DeleteListItem request DeleteListItem(ctx context.Context, params *DeleteListItemParams, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -75394,6 +75364,36 @@ type ClientInterface interface { UpdateExceptionListItem(ctx context.Context, spaceId SpaceId, body UpdateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // DeleteList request + DeleteList(ctx context.Context, spaceId SpaceId, params *DeleteListParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // ReadList request + ReadList(ctx context.Context, spaceId SpaceId, params *ReadListParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PatchListWithBody request with any body + PatchListWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + PatchList(ctx context.Context, spaceId SpaceId, body PatchListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // CreateListWithBody request with any body + CreateListWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreateList(ctx context.Context, spaceId SpaceId, body CreateListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // UpdateListWithBody request with any body + UpdateListWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + UpdateList(ctx context.Context, spaceId SpaceId, body UpdateListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // DeleteListIndex request + DeleteListIndex(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*http.Response, error) + + // ReadListIndex request + ReadListIndex(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*http.Response, error) + + // CreateListIndex request + CreateListIndex(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*http.Response, error) + // PostMaintenanceWindowWithBody request with any body PostMaintenanceWindowWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -80728,102 +80728,6 @@ func (c *Client) GetFleetUninstallTokensUninstalltokenid(ctx context.Context, un return c.Client.Do(req) } -func (c *Client) DeleteList(ctx context.Context, params *DeleteListParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeleteListRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) ReadList(ctx context.Context, params *ReadListParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewReadListRequest(c.Server, params) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchListWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchListRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) PatchList(ctx context.Context, body PatchListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPatchListRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) CreateListWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewCreateListRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) CreateList(ctx context.Context, body CreateListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewCreateListRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) UpdateListWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewUpdateListRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) UpdateList(ctx context.Context, body UpdateListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewUpdateListRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - func (c *Client) FindLists(ctx context.Context, params *FindListsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewFindListsRequest(c.Server, params) if err != nil { @@ -80836,42 +80740,6 @@ func (c *Client) FindLists(ctx context.Context, params *FindListsParams, reqEdit return c.Client.Do(req) } -func (c *Client) DeleteListIndex(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeleteListIndexRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) ReadListIndex(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewReadListIndexRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) CreateListIndex(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewCreateListIndexRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - func (c *Client) DeleteListItem(ctx context.Context, params *DeleteListItemParams, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewDeleteListItemRequest(c.Server, params) if err != nil { @@ -84244,6 +84112,138 @@ func (c *Client) UpdateExceptionListItem(ctx context.Context, spaceId SpaceId, b return c.Client.Do(req) } +func (c *Client) DeleteList(ctx context.Context, spaceId SpaceId, params *DeleteListParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeleteListRequest(c.Server, spaceId, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) ReadList(ctx context.Context, spaceId SpaceId, params *ReadListParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewReadListRequest(c.Server, spaceId, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) PatchListWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPatchListRequestWithBody(c.Server, spaceId, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) PatchList(ctx context.Context, spaceId SpaceId, body PatchListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPatchListRequest(c.Server, spaceId, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) CreateListWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateListRequestWithBody(c.Server, spaceId, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) CreateList(ctx context.Context, spaceId SpaceId, body CreateListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateListRequest(c.Server, spaceId, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateListWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateListRequestWithBody(c.Server, spaceId, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateList(ctx context.Context, spaceId SpaceId, body UpdateListJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateListRequest(c.Server, spaceId, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) DeleteListIndex(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeleteListIndexRequest(c.Server, spaceId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) ReadListIndex(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewReadListIndexRequest(c.Server, spaceId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) CreateListIndex(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateListIndexRequest(c.Server, spaceId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) PostMaintenanceWindowWithBody(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewPostMaintenanceWindowRequestWithBody(c.Server, spaceId, contentType, body) if err != nil { @@ -100945,248 +100945,6 @@ func NewGetFleetUninstallTokensUninstalltokenidRequest(server string, uninstallT return req, nil } -// NewDeleteListRequest generates requests for DeleteList -func NewDeleteListRequest(server string, params *DeleteListParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/lists") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, params.Id); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - if params.DeleteReferences != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "deleteReferences", runtime.ParamLocationQuery, *params.DeleteReferences); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - if params.IgnoreReferences != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ignoreReferences", runtime.ParamLocationQuery, *params.IgnoreReferences); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewReadListRequest generates requests for ReadList -func NewReadListRequest(server string, params *ReadListParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/lists") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - if params != nil { - queryValues := queryURL.Query() - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, params.Id); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewPatchListRequest calls the generic PatchList builder with application/json body -func NewPatchListRequest(server string, body PatchListJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewPatchListRequestWithBody(server, "application/json", bodyReader) -} - -// NewPatchListRequestWithBody generates requests for PatchList with any type of body -func NewPatchListRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/lists") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("PATCH", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewCreateListRequest calls the generic CreateList builder with application/json body -func NewCreateListRequest(server string, body CreateListJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewCreateListRequestWithBody(server, "application/json", bodyReader) -} - -// NewCreateListRequestWithBody generates requests for CreateList with any type of body -func NewCreateListRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/lists") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewUpdateListRequest calls the generic UpdateList builder with application/json body -func NewUpdateListRequest(server string, body UpdateListJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewUpdateListRequestWithBody(server, "application/json", bodyReader) -} - -// NewUpdateListRequestWithBody generates requests for UpdateList with any type of body -func NewUpdateListRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/lists") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("PUT", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - // NewFindListsRequest generates requests for FindLists func NewFindListsRequest(server string, params *FindListsParams) (*http.Request, error) { var err error @@ -101316,87 +101074,6 @@ func NewFindListsRequest(server string, params *FindListsParams) (*http.Request, return req, nil } -// NewDeleteListIndexRequest generates requests for DeleteListIndex -func NewDeleteListIndexRequest(server string) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/lists/index") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewReadListIndexRequest generates requests for ReadListIndex -func NewReadListIndexRequest(server string) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/lists/index") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewCreateListIndexRequest generates requests for CreateListIndex -func NewCreateListIndexRequest(server string) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/api/lists/index") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - // NewDeleteListItemRequest generates requests for DeleteListItem func NewDeleteListItemRequest(server string, params *DeleteListItemParams) (*http.Request, error) { var err error @@ -111214,19 +110891,155 @@ func NewUpdateExceptionListItemRequestWithBody(server string, spaceId SpaceId, c return req, nil } -// NewPostMaintenanceWindowRequest calls the generic PostMaintenanceWindow builder with application/json body -func NewPostMaintenanceWindowRequest(server string, spaceId SpaceId, body PostMaintenanceWindowJSONRequestBody) (*http.Request, error) { +// NewDeleteListRequest generates requests for DeleteList +func NewDeleteListRequest(server string, spaceId SpaceId, params *DeleteListParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/lists", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, params.Id); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + if params.DeleteReferences != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "deleteReferences", runtime.ParamLocationQuery, *params.DeleteReferences); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.IgnoreReferences != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ignoreReferences", runtime.ParamLocationQuery, *params.IgnoreReferences); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewReadListRequest generates requests for ReadList +func NewReadListRequest(server string, spaceId SpaceId, params *ReadListParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/lists", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, params.Id); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPatchListRequest calls the generic PatchList builder with application/json body +func NewPatchListRequest(server string, spaceId SpaceId, body PatchListJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader buf, err := json.Marshal(body) if err != nil { return nil, err } bodyReader = bytes.NewReader(buf) - return NewPostMaintenanceWindowRequestWithBody(server, spaceId, "application/json", bodyReader) + return NewPatchListRequestWithBody(server, spaceId, "application/json", bodyReader) } -// NewPostMaintenanceWindowRequestWithBody generates requests for PostMaintenanceWindow with any type of body -func NewPostMaintenanceWindowRequestWithBody(server string, spaceId SpaceId, contentType string, body io.Reader) (*http.Request, error) { +// NewPatchListRequestWithBody generates requests for PatchList with any type of body +func NewPatchListRequestWithBody(server string, spaceId SpaceId, contentType string, body io.Reader) (*http.Request, error) { var err error var pathParam0 string @@ -111241,7 +111054,54 @@ func NewPostMaintenanceWindowRequestWithBody(server string, spaceId SpaceId, con return nil, err } - operationPath := fmt.Sprintf("/s/%s/api/maintenance_window", pathParam0) + operationPath := fmt.Sprintf("/s/%s/api/lists", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("PATCH", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewCreateListRequest calls the generic CreateList builder with application/json body +func NewCreateListRequest(server string, spaceId SpaceId, body CreateListJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreateListRequestWithBody(server, spaceId, "application/json", bodyReader) +} + +// NewCreateListRequestWithBody generates requests for CreateList with any type of body +func NewCreateListRequestWithBody(server string, spaceId SpaceId, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/lists", pathParam0) if operationPath[0] == '/' { operationPath = "." + operationPath } @@ -111261,8 +111121,19 @@ func NewPostMaintenanceWindowRequestWithBody(server string, spaceId SpaceId, con return req, nil } -// NewDeleteMaintenanceWindowIdRequest generates requests for DeleteMaintenanceWindowId -func NewDeleteMaintenanceWindowIdRequest(server string, spaceId SpaceId, id string) (*http.Request, error) { +// NewUpdateListRequest calls the generic UpdateList builder with application/json body +func NewUpdateListRequest(server string, spaceId SpaceId, body UpdateListJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewUpdateListRequestWithBody(server, spaceId, "application/json", bodyReader) +} + +// NewUpdateListRequestWithBody generates requests for UpdateList with any type of body +func NewUpdateListRequestWithBody(server string, spaceId SpaceId, contentType string, body io.Reader) (*http.Request, error) { var err error var pathParam0 string @@ -111272,9 +111143,38 @@ func NewDeleteMaintenanceWindowIdRequest(server string, spaceId SpaceId, id stri return nil, err } - var pathParam1 string + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } - pathParam1, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) + operationPath := fmt.Sprintf("/s/%s/api/lists", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("PUT", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewDeleteListIndexRequest generates requests for DeleteListIndex +func NewDeleteListIndexRequest(server string, spaceId SpaceId) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) if err != nil { return nil, err } @@ -111284,7 +111184,7 @@ func NewDeleteMaintenanceWindowIdRequest(server string, spaceId SpaceId, id stri return nil, err } - operationPath := fmt.Sprintf("/s/%s/api/maintenance_window/%s", pathParam0, pathParam1) + operationPath := fmt.Sprintf("/s/%s/api/lists/index", pathParam0) if operationPath[0] == '/' { operationPath = "." + operationPath } @@ -111302,8 +111202,8 @@ func NewDeleteMaintenanceWindowIdRequest(server string, spaceId SpaceId, id stri return req, nil } -// NewGetMaintenanceWindowIdRequest generates requests for GetMaintenanceWindowId -func NewGetMaintenanceWindowIdRequest(server string, spaceId SpaceId, id string) (*http.Request, error) { +// NewReadListIndexRequest generates requests for ReadListIndex +func NewReadListIndexRequest(server string, spaceId SpaceId) (*http.Request, error) { var err error var pathParam0 string @@ -111313,9 +111213,36 @@ func NewGetMaintenanceWindowIdRequest(server string, spaceId SpaceId, id string) return nil, err } - var pathParam1 string + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } - pathParam1, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) + operationPath := fmt.Sprintf("/s/%s/api/lists/index", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewCreateListIndexRequest generates requests for CreateListIndex +func NewCreateListIndexRequest(server string, spaceId SpaceId) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) if err != nil { return nil, err } @@ -111325,7 +111252,7 @@ func NewGetMaintenanceWindowIdRequest(server string, spaceId SpaceId, id string) return nil, err } - operationPath := fmt.Sprintf("/s/%s/api/maintenance_window/%s", pathParam0, pathParam1) + operationPath := fmt.Sprintf("/s/%s/api/lists/index", pathParam0) if operationPath[0] == '/' { operationPath = "." + operationPath } @@ -111335,7 +111262,7 @@ func NewGetMaintenanceWindowIdRequest(server string, spaceId SpaceId, id string) return nil, err } - req, err := http.NewRequest("GET", queryURL.String(), nil) + req, err := http.NewRequest("POST", queryURL.String(), nil) if err != nil { return nil, err } @@ -111343,19 +111270,148 @@ func NewGetMaintenanceWindowIdRequest(server string, spaceId SpaceId, id string) return req, nil } -// NewPatchMaintenanceWindowIdRequest calls the generic PatchMaintenanceWindowId builder with application/json body -func NewPatchMaintenanceWindowIdRequest(server string, spaceId SpaceId, id string, body PatchMaintenanceWindowIdJSONRequestBody) (*http.Request, error) { +// NewPostMaintenanceWindowRequest calls the generic PostMaintenanceWindow builder with application/json body +func NewPostMaintenanceWindowRequest(server string, spaceId SpaceId, body PostMaintenanceWindowJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader buf, err := json.Marshal(body) if err != nil { return nil, err } bodyReader = bytes.NewReader(buf) - return NewPatchMaintenanceWindowIdRequestWithBody(server, spaceId, id, "application/json", bodyReader) + return NewPostMaintenanceWindowRequestWithBody(server, spaceId, "application/json", bodyReader) } -// NewPatchMaintenanceWindowIdRequestWithBody generates requests for PatchMaintenanceWindowId with any type of body -func NewPatchMaintenanceWindowIdRequestWithBody(server string, spaceId SpaceId, id string, contentType string, body io.Reader) (*http.Request, error) { +// NewPostMaintenanceWindowRequestWithBody generates requests for PostMaintenanceWindow with any type of body +func NewPostMaintenanceWindowRequestWithBody(server string, spaceId SpaceId, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/maintenance_window", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewDeleteMaintenanceWindowIdRequest generates requests for DeleteMaintenanceWindowId +func NewDeleteMaintenanceWindowIdRequest(server string, spaceId SpaceId, id string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/maintenance_window/%s", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetMaintenanceWindowIdRequest generates requests for GetMaintenanceWindowId +func NewGetMaintenanceWindowIdRequest(server string, spaceId SpaceId, id string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "spaceId", runtime.ParamLocationPath, spaceId) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/s/%s/api/maintenance_window/%s", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPatchMaintenanceWindowIdRequest calls the generic PatchMaintenanceWindowId builder with application/json body +func NewPatchMaintenanceWindowIdRequest(server string, spaceId SpaceId, id string, body PatchMaintenanceWindowIdJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPatchMaintenanceWindowIdRequestWithBody(server, spaceId, id, "application/json", bodyReader) +} + +// NewPatchMaintenanceWindowIdRequestWithBody generates requests for PatchMaintenanceWindowId with any type of body +func NewPatchMaintenanceWindowIdRequestWithBody(server string, spaceId SpaceId, id string, contentType string, body io.Reader) (*http.Request, error) { var err error var pathParam0 string @@ -113445,39 +113501,9 @@ type ClientWithResponsesInterface interface { // GetFleetUninstallTokensUninstalltokenidWithResponse request GetFleetUninstallTokensUninstalltokenidWithResponse(ctx context.Context, uninstallTokenId string, reqEditors ...RequestEditorFn) (*GetFleetUninstallTokensUninstalltokenidResponse, error) - // DeleteListWithResponse request - DeleteListWithResponse(ctx context.Context, params *DeleteListParams, reqEditors ...RequestEditorFn) (*DeleteListResponse, error) - - // ReadListWithResponse request - ReadListWithResponse(ctx context.Context, params *ReadListParams, reqEditors ...RequestEditorFn) (*ReadListResponse, error) - - // PatchListWithBodyWithResponse request with any body - PatchListWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchListResponse, error) - - PatchListWithResponse(ctx context.Context, body PatchListJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchListResponse, error) - - // CreateListWithBodyWithResponse request with any body - CreateListWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateListResponse, error) - - CreateListWithResponse(ctx context.Context, body CreateListJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateListResponse, error) - - // UpdateListWithBodyWithResponse request with any body - UpdateListWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateListResponse, error) - - UpdateListWithResponse(ctx context.Context, body UpdateListJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateListResponse, error) - // FindListsWithResponse request FindListsWithResponse(ctx context.Context, params *FindListsParams, reqEditors ...RequestEditorFn) (*FindListsResponse, error) - // DeleteListIndexWithResponse request - DeleteListIndexWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*DeleteListIndexResponse, error) - - // ReadListIndexWithResponse request - ReadListIndexWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ReadListIndexResponse, error) - - // CreateListIndexWithResponse request - CreateListIndexWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*CreateListIndexResponse, error) - // DeleteListItemWithResponse request DeleteListItemWithResponse(ctx context.Context, params *DeleteListItemParams, reqEditors ...RequestEditorFn) (*DeleteListItemResponse, error) @@ -114220,6 +114246,36 @@ type ClientWithResponsesInterface interface { UpdateExceptionListItemWithResponse(ctx context.Context, spaceId SpaceId, body UpdateExceptionListItemJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateExceptionListItemResponse, error) + // DeleteListWithResponse request + DeleteListWithResponse(ctx context.Context, spaceId SpaceId, params *DeleteListParams, reqEditors ...RequestEditorFn) (*DeleteListResponse, error) + + // ReadListWithResponse request + ReadListWithResponse(ctx context.Context, spaceId SpaceId, params *ReadListParams, reqEditors ...RequestEditorFn) (*ReadListResponse, error) + + // PatchListWithBodyWithResponse request with any body + PatchListWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchListResponse, error) + + PatchListWithResponse(ctx context.Context, spaceId SpaceId, body PatchListJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchListResponse, error) + + // CreateListWithBodyWithResponse request with any body + CreateListWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateListResponse, error) + + CreateListWithResponse(ctx context.Context, spaceId SpaceId, body CreateListJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateListResponse, error) + + // UpdateListWithBodyWithResponse request with any body + UpdateListWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateListResponse, error) + + UpdateListWithResponse(ctx context.Context, spaceId SpaceId, body UpdateListJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateListResponse, error) + + // DeleteListIndexWithResponse request + DeleteListIndexWithResponse(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*DeleteListIndexResponse, error) + + // ReadListIndexWithResponse request + ReadListIndexWithResponse(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*ReadListIndexResponse, error) + + // CreateListIndexWithResponse request + CreateListIndexWithResponse(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*CreateListIndexResponse, error) + // PostMaintenanceWindowWithBodyWithResponse request with any body PostMaintenanceWindowWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostMaintenanceWindowResponse, error) @@ -127765,151 +127821,6 @@ func (r GetFleetUninstallTokensUninstalltokenidResponse) StatusCode() int { return 0 } -type DeleteListResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityListsAPIList - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityListsAPIPlatformErrorResponse - JSON403 *SecurityListsAPIPlatformErrorResponse - JSON404 *SecurityListsAPISiemErrorResponse - JSON500 *SecurityListsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r DeleteListResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r DeleteListResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type ReadListResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityListsAPIList - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityListsAPIPlatformErrorResponse - JSON403 *SecurityListsAPIPlatformErrorResponse - JSON404 *SecurityListsAPISiemErrorResponse - JSON500 *SecurityListsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r ReadListResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r ReadListResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type PatchListResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityListsAPIList - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityListsAPIPlatformErrorResponse - JSON403 *SecurityListsAPIPlatformErrorResponse - JSON404 *SecurityListsAPISiemErrorResponse - JSON500 *SecurityListsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r PatchListResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r PatchListResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type CreateListResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityListsAPIList - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityListsAPIPlatformErrorResponse - JSON403 *SecurityListsAPIPlatformErrorResponse - JSON409 *SecurityListsAPISiemErrorResponse - JSON500 *SecurityListsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r CreateListResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r CreateListResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type UpdateListResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *SecurityListsAPIList - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityListsAPIPlatformErrorResponse - JSON403 *SecurityListsAPIPlatformErrorResponse - JSON404 *SecurityListsAPISiemErrorResponse - JSON500 *SecurityListsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r UpdateListResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r UpdateListResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - type FindListsResponse struct { Body []byte HTTPResponse *http.Response @@ -127944,100 +127855,6 @@ func (r FindListsResponse) StatusCode() int { return 0 } -type DeleteListIndexResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *struct { - Acknowledged bool `json:"acknowledged"` - } - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityListsAPIPlatformErrorResponse - JSON403 *SecurityListsAPIPlatformErrorResponse - JSON404 *SecurityListsAPISiemErrorResponse - JSON500 *SecurityListsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r DeleteListIndexResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r DeleteListIndexResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type ReadListIndexResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *struct { - ListIndex bool `json:"list_index"` - ListItemIndex bool `json:"list_item_index"` - } - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityListsAPIPlatformErrorResponse - JSON403 *SecurityListsAPIPlatformErrorResponse - JSON404 *SecurityListsAPISiemErrorResponse - JSON500 *SecurityListsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r ReadListIndexResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r ReadListIndexResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type CreateListIndexResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *struct { - Acknowledged bool `json:"acknowledged"` - } - JSON400 *struct { - union json.RawMessage - } - JSON401 *SecurityListsAPIPlatformErrorResponse - JSON403 *SecurityListsAPIPlatformErrorResponse - JSON409 *SecurityListsAPISiemErrorResponse - JSON500 *SecurityListsAPISiemErrorResponse -} - -// Status returns HTTPResponse.Status -func (r CreateListIndexResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r CreateListIndexResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - type DeleteListItemResponse struct { Body []byte HTTPResponse *http.Response @@ -132695,6 +132512,245 @@ func (r UpdateExceptionListItemResponse) StatusCode() int { return 0 } +type DeleteListResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityListsAPIList + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityListsAPIPlatformErrorResponse + JSON403 *SecurityListsAPIPlatformErrorResponse + JSON404 *SecurityListsAPISiemErrorResponse + JSON500 *SecurityListsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r DeleteListResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r DeleteListResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type ReadListResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityListsAPIList + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityListsAPIPlatformErrorResponse + JSON403 *SecurityListsAPIPlatformErrorResponse + JSON404 *SecurityListsAPISiemErrorResponse + JSON500 *SecurityListsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r ReadListResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ReadListResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type PatchListResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityListsAPIList + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityListsAPIPlatformErrorResponse + JSON403 *SecurityListsAPIPlatformErrorResponse + JSON404 *SecurityListsAPISiemErrorResponse + JSON500 *SecurityListsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r PatchListResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PatchListResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type CreateListResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityListsAPIList + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityListsAPIPlatformErrorResponse + JSON403 *SecurityListsAPIPlatformErrorResponse + JSON409 *SecurityListsAPISiemErrorResponse + JSON500 *SecurityListsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r CreateListResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r CreateListResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type UpdateListResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SecurityListsAPIList + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityListsAPIPlatformErrorResponse + JSON403 *SecurityListsAPIPlatformErrorResponse + JSON404 *SecurityListsAPISiemErrorResponse + JSON500 *SecurityListsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r UpdateListResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r UpdateListResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type DeleteListIndexResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Acknowledged bool `json:"acknowledged"` + } + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityListsAPIPlatformErrorResponse + JSON403 *SecurityListsAPIPlatformErrorResponse + JSON404 *SecurityListsAPISiemErrorResponse + JSON500 *SecurityListsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r DeleteListIndexResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r DeleteListIndexResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type ReadListIndexResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + ListIndex bool `json:"list_index"` + ListItemIndex bool `json:"list_item_index"` + } + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityListsAPIPlatformErrorResponse + JSON403 *SecurityListsAPIPlatformErrorResponse + JSON404 *SecurityListsAPISiemErrorResponse + JSON500 *SecurityListsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r ReadListIndexResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ReadListIndexResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type CreateListIndexResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Acknowledged bool `json:"acknowledged"` + } + JSON400 *struct { + union json.RawMessage + } + JSON401 *SecurityListsAPIPlatformErrorResponse + JSON403 *SecurityListsAPIPlatformErrorResponse + JSON409 *SecurityListsAPISiemErrorResponse + JSON500 *SecurityListsAPISiemErrorResponse +} + +// Status returns HTTPResponse.Status +func (r CreateListIndexResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r CreateListIndexResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type PostMaintenanceWindowResponse struct { Body []byte HTTPResponse *http.Response @@ -137128,75 +137184,6 @@ func (c *ClientWithResponses) GetFleetUninstallTokensUninstalltokenidWithRespons return ParseGetFleetUninstallTokensUninstalltokenidResponse(rsp) } -// DeleteListWithResponse request returning *DeleteListResponse -func (c *ClientWithResponses) DeleteListWithResponse(ctx context.Context, params *DeleteListParams, reqEditors ...RequestEditorFn) (*DeleteListResponse, error) { - rsp, err := c.DeleteList(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseDeleteListResponse(rsp) -} - -// ReadListWithResponse request returning *ReadListResponse -func (c *ClientWithResponses) ReadListWithResponse(ctx context.Context, params *ReadListParams, reqEditors ...RequestEditorFn) (*ReadListResponse, error) { - rsp, err := c.ReadList(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseReadListResponse(rsp) -} - -// PatchListWithBodyWithResponse request with arbitrary body returning *PatchListResponse -func (c *ClientWithResponses) PatchListWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchListResponse, error) { - rsp, err := c.PatchListWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchListResponse(rsp) -} - -func (c *ClientWithResponses) PatchListWithResponse(ctx context.Context, body PatchListJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchListResponse, error) { - rsp, err := c.PatchList(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParsePatchListResponse(rsp) -} - -// CreateListWithBodyWithResponse request with arbitrary body returning *CreateListResponse -func (c *ClientWithResponses) CreateListWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateListResponse, error) { - rsp, err := c.CreateListWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseCreateListResponse(rsp) -} - -func (c *ClientWithResponses) CreateListWithResponse(ctx context.Context, body CreateListJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateListResponse, error) { - rsp, err := c.CreateList(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseCreateListResponse(rsp) -} - -// UpdateListWithBodyWithResponse request with arbitrary body returning *UpdateListResponse -func (c *ClientWithResponses) UpdateListWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateListResponse, error) { - rsp, err := c.UpdateListWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseUpdateListResponse(rsp) -} - -func (c *ClientWithResponses) UpdateListWithResponse(ctx context.Context, body UpdateListJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateListResponse, error) { - rsp, err := c.UpdateList(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseUpdateListResponse(rsp) -} - // FindListsWithResponse request returning *FindListsResponse func (c *ClientWithResponses) FindListsWithResponse(ctx context.Context, params *FindListsParams, reqEditors ...RequestEditorFn) (*FindListsResponse, error) { rsp, err := c.FindLists(ctx, params, reqEditors...) @@ -137206,33 +137193,6 @@ func (c *ClientWithResponses) FindListsWithResponse(ctx context.Context, params return ParseFindListsResponse(rsp) } -// DeleteListIndexWithResponse request returning *DeleteListIndexResponse -func (c *ClientWithResponses) DeleteListIndexWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*DeleteListIndexResponse, error) { - rsp, err := c.DeleteListIndex(ctx, reqEditors...) - if err != nil { - return nil, err - } - return ParseDeleteListIndexResponse(rsp) -} - -// ReadListIndexWithResponse request returning *ReadListIndexResponse -func (c *ClientWithResponses) ReadListIndexWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ReadListIndexResponse, error) { - rsp, err := c.ReadListIndex(ctx, reqEditors...) - if err != nil { - return nil, err - } - return ParseReadListIndexResponse(rsp) -} - -// CreateListIndexWithResponse request returning *CreateListIndexResponse -func (c *ClientWithResponses) CreateListIndexWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*CreateListIndexResponse, error) { - rsp, err := c.CreateListIndex(ctx, reqEditors...) - if err != nil { - return nil, err - } - return ParseCreateListIndexResponse(rsp) -} - // DeleteListItemWithResponse request returning *DeleteListItemResponse func (c *ClientWithResponses) DeleteListItemWithResponse(ctx context.Context, params *DeleteListItemParams, reqEditors ...RequestEditorFn) (*DeleteListItemResponse, error) { rsp, err := c.DeleteListItem(ctx, params, reqEditors...) @@ -139661,6 +139621,102 @@ func (c *ClientWithResponses) UpdateExceptionListItemWithResponse(ctx context.Co return ParseUpdateExceptionListItemResponse(rsp) } +// DeleteListWithResponse request returning *DeleteListResponse +func (c *ClientWithResponses) DeleteListWithResponse(ctx context.Context, spaceId SpaceId, params *DeleteListParams, reqEditors ...RequestEditorFn) (*DeleteListResponse, error) { + rsp, err := c.DeleteList(ctx, spaceId, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseDeleteListResponse(rsp) +} + +// ReadListWithResponse request returning *ReadListResponse +func (c *ClientWithResponses) ReadListWithResponse(ctx context.Context, spaceId SpaceId, params *ReadListParams, reqEditors ...RequestEditorFn) (*ReadListResponse, error) { + rsp, err := c.ReadList(ctx, spaceId, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseReadListResponse(rsp) +} + +// PatchListWithBodyWithResponse request with arbitrary body returning *PatchListResponse +func (c *ClientWithResponses) PatchListWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchListResponse, error) { + rsp, err := c.PatchListWithBody(ctx, spaceId, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePatchListResponse(rsp) +} + +func (c *ClientWithResponses) PatchListWithResponse(ctx context.Context, spaceId SpaceId, body PatchListJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchListResponse, error) { + rsp, err := c.PatchList(ctx, spaceId, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePatchListResponse(rsp) +} + +// CreateListWithBodyWithResponse request with arbitrary body returning *CreateListResponse +func (c *ClientWithResponses) CreateListWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateListResponse, error) { + rsp, err := c.CreateListWithBody(ctx, spaceId, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateListResponse(rsp) +} + +func (c *ClientWithResponses) CreateListWithResponse(ctx context.Context, spaceId SpaceId, body CreateListJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateListResponse, error) { + rsp, err := c.CreateList(ctx, spaceId, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateListResponse(rsp) +} + +// UpdateListWithBodyWithResponse request with arbitrary body returning *UpdateListResponse +func (c *ClientWithResponses) UpdateListWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateListResponse, error) { + rsp, err := c.UpdateListWithBody(ctx, spaceId, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateListResponse(rsp) +} + +func (c *ClientWithResponses) UpdateListWithResponse(ctx context.Context, spaceId SpaceId, body UpdateListJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateListResponse, error) { + rsp, err := c.UpdateList(ctx, spaceId, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateListResponse(rsp) +} + +// DeleteListIndexWithResponse request returning *DeleteListIndexResponse +func (c *ClientWithResponses) DeleteListIndexWithResponse(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*DeleteListIndexResponse, error) { + rsp, err := c.DeleteListIndex(ctx, spaceId, reqEditors...) + if err != nil { + return nil, err + } + return ParseDeleteListIndexResponse(rsp) +} + +// ReadListIndexWithResponse request returning *ReadListIndexResponse +func (c *ClientWithResponses) ReadListIndexWithResponse(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*ReadListIndexResponse, error) { + rsp, err := c.ReadListIndex(ctx, spaceId, reqEditors...) + if err != nil { + return nil, err + } + return ParseReadListIndexResponse(rsp) +} + +// CreateListIndexWithResponse request returning *CreateListIndexResponse +func (c *ClientWithResponses) CreateListIndexWithResponse(ctx context.Context, spaceId SpaceId, reqEditors ...RequestEditorFn) (*CreateListIndexResponse, error) { + rsp, err := c.CreateListIndex(ctx, spaceId, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateListIndexResponse(rsp) +} + // PostMaintenanceWindowWithBodyWithResponse request with arbitrary body returning *PostMaintenanceWindowResponse func (c *ClientWithResponses) PostMaintenanceWindowWithBodyWithResponse(ctx context.Context, spaceId SpaceId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostMaintenanceWindowResponse, error) { rsp, err := c.PostMaintenanceWindowWithBody(ctx, spaceId, contentType, body, reqEditors...) @@ -154461,22 +154517,28 @@ func ParseGetFleetUninstallTokensUninstalltokenidResponse(rsp *http.Response) (* return response, nil } -// ParseDeleteListResponse parses an HTTP response from a DeleteListWithResponse call -func ParseDeleteListResponse(rsp *http.Response) (*DeleteListResponse, error) { +// ParseFindListsResponse parses an HTTP response from a FindListsWithResponse call +func ParseFindListsResponse(rsp *http.Response) (*FindListsResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) defer func() { _ = rsp.Body.Close() }() if err != nil { return nil, err } - response := &DeleteListResponse{ + response := &FindListsResponse{ Body: bodyBytes, HTTPResponse: rsp, } switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityListsAPIList + var dest struct { + Cursor SecurityListsAPIFindListsCursor `json:"cursor"` + Data []SecurityListsAPIList `json:"data"` + Page int `json:"page"` + PerPage int `json:"per_page"` + Total int `json:"total"` + } if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -154505,13 +154567,6 @@ func ParseDeleteListResponse(rsp *http.Response) (*DeleteListResponse, error) { } response.JSON403 = &dest - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: var dest SecurityListsAPISiemErrorResponse if err := json.Unmarshal(bodyBytes, &dest); err != nil { @@ -154524,88 +154579,27 @@ func ParseDeleteListResponse(rsp *http.Response) (*DeleteListResponse, error) { return response, nil } -// ParseReadListResponse parses an HTTP response from a ReadListWithResponse call -func ParseReadListResponse(rsp *http.Response) (*ReadListResponse, error) { +// ParseDeleteListItemResponse parses an HTTP response from a DeleteListItemWithResponse call +func ParseDeleteListItemResponse(rsp *http.Response) (*DeleteListItemResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) defer func() { _ = rsp.Body.Close() }() if err != nil { return nil, err } - response := &ReadListResponse{ + response := &DeleteListItemResponse{ Body: bodyBytes, HTTPResponse: rsp, } switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityListsAPIList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: var dest struct { union json.RawMessage } if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParsePatchListResponse parses an HTTP response from a PatchListWithResponse call -func ParsePatchListResponse(rsp *http.Response) (*PatchListResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PatchListResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityListsAPIList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } response.JSON200 = &dest case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: @@ -154650,22 +154644,24 @@ func ParsePatchListResponse(rsp *http.Response) (*PatchListResponse, error) { return response, nil } -// ParseCreateListResponse parses an HTTP response from a CreateListWithResponse call -func ParseCreateListResponse(rsp *http.Response) (*CreateListResponse, error) { +// ParseReadListItemResponse parses an HTTP response from a ReadListItemWithResponse call +func ParseReadListItemResponse(rsp *http.Response) (*ReadListItemResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) defer func() { _ = rsp.Body.Close() }() if err != nil { return nil, err } - response := &CreateListResponse{ + response := &ReadListItemResponse{ Body: bodyBytes, HTTPResponse: rsp, } switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityListsAPIList + var dest struct { + union json.RawMessage + } if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -154694,12 +154690,12 @@ func ParseCreateListResponse(rsp *http.Response) (*CreateListResponse, error) { } response.JSON403 = &dest - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: var dest SecurityListsAPISiemErrorResponse if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } - response.JSON409 = &dest + response.JSON404 = &dest case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: var dest SecurityListsAPISiemErrorResponse @@ -154713,473 +154709,22 @@ func ParseCreateListResponse(rsp *http.Response) (*CreateListResponse, error) { return response, nil } -// ParseUpdateListResponse parses an HTTP response from a UpdateListWithResponse call -func ParseUpdateListResponse(rsp *http.Response) (*UpdateListResponse, error) { +// ParsePatchListItemResponse parses an HTTP response from a PatchListItemWithResponse call +func ParsePatchListItemResponse(rsp *http.Response) (*PatchListItemResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) defer func() { _ = rsp.Body.Close() }() if err != nil { return nil, err } - response := &UpdateListResponse{ + response := &PatchListItemResponse{ Body: bodyBytes, HTTPResponse: rsp, } switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityListsAPIList - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseFindListsResponse parses an HTTP response from a FindListsWithResponse call -func ParseFindListsResponse(rsp *http.Response) (*FindListsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &FindListsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - Cursor SecurityListsAPIFindListsCursor `json:"cursor"` - Data []SecurityListsAPIList `json:"data"` - Page int `json:"page"` - PerPage int `json:"per_page"` - Total int `json:"total"` - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseDeleteListIndexResponse parses an HTTP response from a DeleteListIndexWithResponse call -func ParseDeleteListIndexResponse(rsp *http.Response) (*DeleteListIndexResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &DeleteListIndexResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - Acknowledged bool `json:"acknowledged"` - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseReadListIndexResponse parses an HTTP response from a ReadListIndexWithResponse call -func ParseReadListIndexResponse(rsp *http.Response) (*ReadListIndexResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &ReadListIndexResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - ListIndex bool `json:"list_index"` - ListItemIndex bool `json:"list_item_index"` - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseCreateListIndexResponse parses an HTTP response from a CreateListIndexWithResponse call -func ParseCreateListIndexResponse(rsp *http.Response) (*CreateListIndexResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &CreateListIndexResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - Acknowledged bool `json:"acknowledged"` - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON409 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseDeleteListItemResponse parses an HTTP response from a DeleteListItemWithResponse call -func ParseDeleteListItemResponse(rsp *http.Response) (*DeleteListItemResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &DeleteListItemResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParseReadListItemResponse parses an HTTP response from a ReadListItemWithResponse call -func ParseReadListItemResponse(rsp *http.Response) (*ReadListItemResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &ReadListItemResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest struct { - union json.RawMessage - } - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON401 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: - var dest SecurityListsAPIPlatformErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON403 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON404 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest SecurityListsAPISiemErrorResponse - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - -// ParsePatchListItemResponse parses an HTTP response from a PatchListItemWithResponse call -func ParsePatchListItemResponse(rsp *http.Response) (*PatchListItemResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &PatchListItemResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest SecurityListsAPIListItem + var dest SecurityListsAPIListItem if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -160725,6 +160270,517 @@ func ParseUpdateExceptionListItemResponse(rsp *http.Response) (*UpdateExceptionL return response, nil } +// ParseDeleteListResponse parses an HTTP response from a DeleteListWithResponse call +func ParseDeleteListResponse(rsp *http.Response) (*DeleteListResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &DeleteListResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityListsAPIList + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseReadListResponse parses an HTTP response from a ReadListWithResponse call +func ParseReadListResponse(rsp *http.Response) (*ReadListResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ReadListResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityListsAPIList + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParsePatchListResponse parses an HTTP response from a PatchListWithResponse call +func ParsePatchListResponse(rsp *http.Response) (*PatchListResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PatchListResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityListsAPIList + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseCreateListResponse parses an HTTP response from a CreateListWithResponse call +func ParseCreateListResponse(rsp *http.Response) (*CreateListResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &CreateListResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityListsAPIList + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON409 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseUpdateListResponse parses an HTTP response from a UpdateListWithResponse call +func ParseUpdateListResponse(rsp *http.Response) (*UpdateListResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &UpdateListResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SecurityListsAPIList + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseDeleteListIndexResponse parses an HTTP response from a DeleteListIndexWithResponse call +func ParseDeleteListIndexResponse(rsp *http.Response) (*DeleteListIndexResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &DeleteListIndexResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Acknowledged bool `json:"acknowledged"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseReadListIndexResponse parses an HTTP response from a ReadListIndexWithResponse call +func ParseReadListIndexResponse(rsp *http.Response) (*ReadListIndexResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ReadListIndexResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + ListIndex bool `json:"list_index"` + ListItemIndex bool `json:"list_item_index"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseCreateListIndexResponse parses an HTTP response from a CreateListIndexWithResponse call +func ParseCreateListIndexResponse(rsp *http.Response) (*CreateListIndexResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &CreateListIndexResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Acknowledged bool `json:"acknowledged"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + union json.RawMessage + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest SecurityListsAPIPlatformErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON409 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest SecurityListsAPISiemErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + // ParsePostMaintenanceWindowResponse parses an HTTP response from a PostMaintenanceWindowWithResponse call func ParsePostMaintenanceWindowResponse(rsp *http.Response) (*PostMaintenanceWindowResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) diff --git a/generated/kbapi/transform_schema.go b/generated/kbapi/transform_schema.go index 32db70360..888341188 100644 --- a/generated/kbapi/transform_schema.go +++ b/generated/kbapi/transform_schema.go @@ -693,6 +693,8 @@ func transformKibanaPaths(schema *Schema) { "/api/detection_engine/rules", "/api/exception_lists", "/api/exception_lists/items", + "/api/lists", + "/api/lists/index", } // Add a spaceId parameter if not already present diff --git a/internal/clients/kibana_oapi/security_lists.go b/internal/clients/kibana_oapi/security_lists.go new file mode 100644 index 000000000..4164ec610 --- /dev/null +++ b/internal/clients/kibana_oapi/security_lists.go @@ -0,0 +1,90 @@ +package kibana_oapi + +import ( + "context" + "net/http" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/diagutil" + "github.com/hashicorp/terraform-plugin-framework/diag" +) + +// CreateListIndex creates the .lists and .items data streams for a space if they don't exist. +// This is required before any list operations can be performed. +func CreateListIndex(ctx context.Context, client *Client, spaceId string) diag.Diagnostics { + resp, err := client.API.CreateListIndexWithResponse(ctx, kbapi.SpaceId(spaceId)) + if err != nil { + return diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return nil + default: + return reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// GetList reads a security list from the API by ID +func GetList(ctx context.Context, client *Client, spaceId string, params *kbapi.ReadListParams) (*kbapi.ReadListResponse, diag.Diagnostics) { + resp, err := client.API.ReadListWithResponse(ctx, kbapi.SpaceId(spaceId), params) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + case http.StatusNotFound: + return nil, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// CreateList creates a new security list. +func CreateList(ctx context.Context, client *Client, spaceId string, body kbapi.CreateListJSONRequestBody) (*kbapi.CreateListResponse, diag.Diagnostics) { + resp, err := client.API.CreateListWithResponse(ctx, kbapi.SpaceId(spaceId), body) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// UpdateList updates an existing security list. +func UpdateList(ctx context.Context, client *Client, spaceId string, body kbapi.UpdateListJSONRequestBody) (*kbapi.UpdateListResponse, diag.Diagnostics) { + resp, err := client.API.UpdateListWithResponse(ctx, kbapi.SpaceId(spaceId), body) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// DeleteList deletes an existing security list. +func DeleteList(ctx context.Context, client *Client, spaceId string, params *kbapi.DeleteListParams) diag.Diagnostics { + resp, err := client.API.DeleteListWithResponse(ctx, kbapi.SpaceId(spaceId), params) + if err != nil { + return diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return nil + case http.StatusNotFound: + return nil + default: + return reportUnknownError(resp.StatusCode(), resp.Body) + } +} diff --git a/internal/kibana/security/exception_item/acc_test.go b/internal/kibana/security/exception_item/acc_test.go index e169e7927..56c05dbac 100644 --- a/internal/kibana/security/exception_item/acc_test.go +++ b/internal/kibana/security/exception_item/acc_test.go @@ -195,34 +195,34 @@ func TestAccResourceExceptionItemEntryType_MatchAny(t *testing.T) { }) } -// func TestAccResourceExceptionItemEntryType_List(t *testing.T) { -// exceptionListID := fmt.Sprintf("test-exception-list-list-entry-%s", uuid.New().String()[:8]) -// itemID := fmt.Sprintf("test-exception-item-list-entry-%s", uuid.New().String()[:8]) -// valueListID := fmt.Sprintf("test-value-list-%s", uuid.New().String()[:8]) +func TestAccResourceExceptionItemEntryType_List(t *testing.T) { + exceptionListID := fmt.Sprintf("test-exception-list-list-entry-%s", uuid.New().String()[:8]) + itemID := fmt.Sprintf("test-exception-item-list-entry-%s", uuid.New().String()[:8]) + valueListID := fmt.Sprintf("test-value-list-%s", uuid.New().String()[:8]) -// resource.Test(t, resource.TestCase{ -// PreCheck: func() { acctest.PreCheck(t) }, -// Steps: []resource.TestStep{ -// { -// SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), -// ProtoV6ProviderFactories: acctest.Providers, -// ConfigDirectory: acctest.NamedTestCaseDirectory("list"), -// ConfigVariables: config.Variables{ -// "exception_list_id": config.StringVariable(exceptionListID), -// "item_id": config.StringVariable(itemID), -// "value_list_id": config.StringVariable(valueListID), -// }, -// Check: resource.ComposeTestCheckFunc( -// resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.type", "list"), -// resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.field", "source.ip"), -// resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.operator", "included"), -// resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.list.id", "test-value-list"), -// resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.list.type", "ip"), -// ), -// }, -// }, -// }) -// } + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("list"), + ConfigVariables: config.Variables{ + "exception_list_id": config.StringVariable(exceptionListID), + "item_id": config.StringVariable(itemID), + "value_list_id": config.StringVariable(valueListID), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.type", "list"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.field", "source.ip"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.operator", "included"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.list.id", valueListID), + resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.list.type", "ip"), + ), + }, + }, + }) +} func TestAccResourceExceptionItemEntryType_Exists(t *testing.T) { listID := fmt.Sprintf("test-exception-list-exists-%s", uuid.New().String()[:8]) diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf index c4cd67c9d..3f1738a78 100644 --- a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf @@ -27,12 +27,12 @@ resource "elasticstack_kibana_security_exception_list" "test" { } # Create a value list to reference in the exception item -resource "elasticstack_kibana_security_value_list" "test" { +resource "elasticstack_kibana_security_list" "test" { list_id = var.value_list_id name = "Test Value List" description = "Test value list for list entry type" type = "ip" - values = ["192.168.1.1", "192.168.1.2", "10.0.0.1"] + # values = ["192.168.1.1", "192.168.1.2", "10.0.0.1"] } resource "elasticstack_kibana_security_exception_item" "test" { @@ -48,7 +48,7 @@ resource "elasticstack_kibana_security_exception_item" "test" { field = "source.ip" operator = "included" list = { - id = elasticstack_kibana_security_value_list.test.list_id + id = elasticstack_kibana_security_list.test.list_id type = "ip" } } diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf index 15baf96b1..e1ad82dd8 100644 --- a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf @@ -30,8 +30,8 @@ resource "elasticstack_kibana_security_exception_item" "test" { namespace_type = "single" entries = [ { - type = "nested" - field = "parent.field" + type = "nested" + field = "parent.field" entries = [ { type = "match" diff --git a/internal/kibana/security/security_list/acc_test.go b/internal/kibana/security/security_list/acc_test.go new file mode 100644 index 000000000..c70472b88 --- /dev/null +++ b/internal/kibana/security/security_list/acc_test.go @@ -0,0 +1,105 @@ +package securitylist_test + +import ( + "context" + "testing" + + "github.com/elastic/terraform-provider-elasticstack/internal/acctest" + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func ensureListIndexExists(t *testing.T) { + client, err := clients.NewAcceptanceTestingClient() + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + kibanaClient, err := client.GetKibanaOapiClient() + if err != nil { + t.Fatalf("Failed to get Kibana client: %v", err) + } + + diags := kibana_oapi.CreateListIndex(context.Background(), kibanaClient, "default") + if diags.HasError() { + // It's OK if it already exists, we'll only fail on other errors + for _, d := range diags { + if d.Summary() != "Unexpected status code from server: got HTTP 409" { + t.Fatalf("Failed to create list index: %v", d.Detail()) + } + } + } +} + +func TestAccResourceSecurityList(t *testing.T) { + listID := "test-list-" + uuid.New().String() + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + ensureListIndexExists(t) + }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { // Create + ConfigDirectory: acctest.NamedTestCaseDirectory("create"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "name": config.StringVariable("Test Security List"), + "description": config.StringVariable("A test security list for IP addresses"), + "type": config.StringVariable("ip"), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list.test", "id"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "name", "Test Security List"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "description", "A test security list for IP addresses"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "type", "ip"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list.test", "created_at"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list.test", "created_by"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list.test", "updated_at"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list.test", "updated_by"), + ), + }, + { // Update + ConfigDirectory: acctest.NamedTestCaseDirectory("update"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "name": config.StringVariable("Updated Security List"), + "description": config.StringVariable("An updated test security list"), + "type": config.StringVariable("ip"), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "name", "Updated Security List"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "description", "An updated test security list"), + ), + }, + }, + }) +} + +func TestAccResourceSecurityList_KeywordType(t *testing.T) { + listID := "keyword-list-" + uuid.New().String() + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + ensureListIndexExists(t) + }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + ConfigDirectory: acctest.NamedTestCaseDirectory("keyword_type"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "name": config.StringVariable("Keyword Security List"), + "description": config.StringVariable("A test security list for keywords"), + "type": config.StringVariable("keyword"), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "type", "keyword"), + ), + }, + }, + }) +} diff --git a/internal/kibana/security/security_list/create.go b/internal/kibana/security/security_list/create.go new file mode 100644 index 000000000..03a035097 --- /dev/null +++ b/internal/kibana/security/security_list/create.go @@ -0,0 +1,69 @@ +package securitylist + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *securityListResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan SecurityListModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + // Get Kibana client + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Convert plan to API request + createReq, diags := plan.toCreateRequest() + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Create the list + spaceID := plan.SpaceID.ValueString() + createResp, diags := kibana_oapi.CreateList(ctx, client, spaceID, *createReq) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if createResp == nil || createResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to create security list", "API returned empty response") + return + } + + // Read the created list to populate state + readParams := &kbapi.ReadListParams{ + Id: createResp.JSON200.Id, + } + + readResp, diags := kibana_oapi.GetList(ctx, client, spaceID, readParams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Update state with read response + diags = plan.fromAPI(ctx, readResp.JSON200) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) +} diff --git a/internal/kibana/security/security_list/delete.go b/internal/kibana/security/security_list/delete.go new file mode 100644 index 000000000..327d7b276 --- /dev/null +++ b/internal/kibana/security/security_list/delete.go @@ -0,0 +1,33 @@ +package securitylist + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *securityListResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state SecurityListModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + spaceID := state.SpaceID.ValueString() + listID := state.ListID.ValueString() + + params := &kbapi.DeleteListParams{ + Id: kbapi.SecurityListsAPIListId(listID), + } + + diags := kibana_oapi.DeleteList(ctx, client, spaceID, params) + resp.Diagnostics.Append(diags...) +} diff --git a/internal/kibana/security/security_list/models.go b/internal/kibana/security/security_list/models.go new file mode 100644 index 000000000..98489c692 --- /dev/null +++ b/internal/kibana/security/security_list/models.go @@ -0,0 +1,154 @@ +package securitylist + +import ( + "context" + "encoding/json" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type SecurityListModel struct { + ID types.String `tfsdk:"id"` + SpaceID types.String `tfsdk:"space_id"` + ListID types.String `tfsdk:"list_id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Type types.String `tfsdk:"type"` + Deserializer types.String `tfsdk:"deserializer"` + Serializer types.String `tfsdk:"serializer"` + Meta types.String `tfsdk:"meta"` + Version types.Int64 `tfsdk:"version"` + VersionID types.String `tfsdk:"version_id"` + Immutable types.Bool `tfsdk:"immutable"` + CreatedAt types.String `tfsdk:"created_at"` + CreatedBy types.String `tfsdk:"created_by"` + UpdatedAt types.String `tfsdk:"updated_at"` + UpdatedBy types.String `tfsdk:"updated_by"` + TieBreakerID types.String `tfsdk:"tie_breaker_id"` +} + +// toCreateRequest converts the Terraform model to API create request +func (m *SecurityListModel) toCreateRequest() (*kbapi.CreateListJSONRequestBody, diag.Diagnostics) { + var diags diag.Diagnostics + req := &kbapi.CreateListJSONRequestBody{ + Name: kbapi.SecurityListsAPIListName(m.Name.ValueString()), + Description: kbapi.SecurityListsAPIListDescription(m.Description.ValueString()), + Type: kbapi.SecurityListsAPIListType(m.Type.ValueString()), + } + + // Set optional fields + if !m.ListID.IsNull() && !m.ListID.IsUnknown() { + id := kbapi.SecurityListsAPIListId(m.ListID.ValueString()) + req.Id = &id + } + + if !m.Deserializer.IsNull() && !m.Deserializer.IsUnknown() { + deserializer := kbapi.SecurityListsAPIListDeserializer(m.Deserializer.ValueString()) + req.Deserializer = &deserializer + } + + if !m.Serializer.IsNull() && !m.Serializer.IsUnknown() { + serializer := kbapi.SecurityListsAPIListSerializer(m.Serializer.ValueString()) + req.Serializer = &serializer + } + + if !m.Meta.IsNull() && !m.Meta.IsUnknown() { + var metaMap kbapi.SecurityListsAPIListMetadata + if err := json.Unmarshal([]byte(m.Meta.ValueString()), &metaMap); err != nil { + diags.AddError("Invalid meta JSON", err.Error()) + return nil, diags + } + req.Meta = &metaMap + } + + if !m.Version.IsNull() && !m.Version.IsUnknown() { + version := int(m.Version.ValueInt64()) + req.Version = &version + } + + return req, diags +} + +// toUpdateRequest converts the Terraform model to API update request +func (m *SecurityListModel) toUpdateRequest() (*kbapi.UpdateListJSONRequestBody, diag.Diagnostics) { + var diags diag.Diagnostics + req := &kbapi.UpdateListJSONRequestBody{ + Id: kbapi.SecurityListsAPIListId(m.ListID.ValueString()), + Name: kbapi.SecurityListsAPIListName(m.Name.ValueString()), + Description: kbapi.SecurityListsAPIListDescription(m.Description.ValueString()), + } + + // Set optional fields + if !m.VersionID.IsNull() && !m.VersionID.IsUnknown() { + versionID := kbapi.SecurityListsAPIListVersionId(m.VersionID.ValueString()) + req.UnderscoreVersion = &versionID + } + + if !m.Meta.IsNull() && !m.Meta.IsUnknown() { + var metaMap kbapi.SecurityListsAPIListMetadata + if err := json.Unmarshal([]byte(m.Meta.ValueString()), &metaMap); err != nil { + diags.AddError("Invalid meta JSON", err.Error()) + return nil, diags + } + req.Meta = &metaMap + } + + if !m.Version.IsNull() && !m.Version.IsUnknown() { + version := kbapi.SecurityListsAPIListVersion(m.Version.ValueInt64()) + req.Version = &version + } + + return req, diags +} + +// fromAPI converts the API response to Terraform model +func (m *SecurityListModel) fromAPI(ctx context.Context, apiList *kbapi.SecurityListsAPIList) diag.Diagnostics { + var diags diag.Diagnostics + + m.ID = types.StringValue(string(apiList.Id)) + m.ListID = types.StringValue(string(apiList.Id)) + m.Name = types.StringValue(string(apiList.Name)) + m.Description = types.StringValue(string(apiList.Description)) + m.Type = types.StringValue(string(apiList.Type)) + m.Immutable = types.BoolValue(apiList.Immutable) + m.Version = types.Int64Value(int64(apiList.Version)) + m.TieBreakerID = types.StringValue(apiList.TieBreakerId) + m.CreatedAt = types.StringValue(apiList.CreatedAt.String()) + m.CreatedBy = types.StringValue(apiList.CreatedBy) + m.UpdatedAt = types.StringValue(apiList.UpdatedAt.String()) + m.UpdatedBy = types.StringValue(apiList.UpdatedBy) + + // Set optional _version field + if apiList.UnderscoreVersion != nil { + m.VersionID = types.StringValue(string(*apiList.UnderscoreVersion)) + } else { + m.VersionID = types.StringNull() + } + + if apiList.Deserializer != nil { + m.Deserializer = types.StringValue(string(*apiList.Deserializer)) + } else { + m.Deserializer = types.StringNull() + } + + if apiList.Serializer != nil { + m.Serializer = types.StringValue(string(*apiList.Serializer)) + } else { + m.Serializer = types.StringNull() + } + + if apiList.Meta != nil { + metaBytes, err := json.Marshal(apiList.Meta) + if err != nil { + diags.AddError("Failed to marshal meta", err.Error()) + return diags + } + m.Meta = types.StringValue(string(metaBytes)) + } else { + m.Meta = types.StringNull() + } + + return diags +} diff --git a/internal/kibana/security/security_list/read.go b/internal/kibana/security/security_list/read.go new file mode 100644 index 000000000..c16d2815e --- /dev/null +++ b/internal/kibana/security/security_list/read.go @@ -0,0 +1,50 @@ +package securitylist + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *securityListResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state SecurityListModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + spaceID := state.SpaceID.ValueString() + listID := state.ListID.ValueString() + + params := &kbapi.ReadListParams{ + Id: kbapi.SecurityListsAPIListId(listID), + } + + readResp, diags := kibana_oapi.GetList(ctx, client, spaceID, params) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Convert API response to model + diags = state.fromAPI(ctx, readResp.JSON200) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, state)...) +} diff --git a/internal/kibana/security/security_list/resource-description.md b/internal/kibana/security/security_list/resource-description.md new file mode 100644 index 000000000..9b67b4e12 --- /dev/null +++ b/internal/kibana/security/security_list/resource-description.md @@ -0,0 +1,27 @@ +Manages Kibana security lists (also known as value lists). Security lists are used by exception items to define sets of values for matching or excluding in security rules. + +## Example Usage + +```terraform +resource "elasticstack_kibana_security_list" "ip_list" { + space_id = "default" + name = "Trusted IP Addresses" + description = "List of trusted IP addresses for security rules" + type = "ip" +} + +resource "elasticstack_kibana_security_list" "keyword_list" { + space_id = "security" + list_id = "custom-keywords" + name = "Custom Keywords" + description = "Custom keyword list for detection rules" + type = "keyword" +} +``` + +## Notes + +- Security lists define the type of data they can contain via the `type` attribute +- Once created, the `type` of a list cannot be changed +- Lists can be referenced by exception items to create more sophisticated matching rules +- The `list_id` is auto-generated if not provided diff --git a/internal/kibana/security/security_list/resource.go b/internal/kibana/security/security_list/resource.go new file mode 100644 index 000000000..ce1678457 --- /dev/null +++ b/internal/kibana/security/security_list/resource.go @@ -0,0 +1,38 @@ +package securitylist + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &securityListResource{} + _ resource.ResourceWithConfigure = &securityListResource{} + _ resource.ResourceWithImportState = &securityListResource{} +) + +func NewResource() resource.Resource { + return &securityListResource{} +} + +type securityListResource struct { + client *clients.ApiClient +} + +func (r *securityListResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_kibana_security_list" +} + +func (r *securityListResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + client, diags := clients.ConvertProviderData(req.ProviderData) + resp.Diagnostics.Append(diags...) + r.client = client +} + +func (r *securityListResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response) +} diff --git a/internal/kibana/security/security_list/schema.go b/internal/kibana/security/security_list/schema.go new file mode 100644 index 000000000..88102f489 --- /dev/null +++ b/internal/kibana/security/security_list/schema.go @@ -0,0 +1,122 @@ +package securitylist + +import ( + "context" + _ "embed" + + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +//go:embed resource-description.md +var securityListResourceDescription string + +func (r *securityListResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: securityListResourceDescription, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The unique identifier of the security list (auto-generated by Kibana if not specified).", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), + }, + }, + "space_id": schema.StringAttribute{ + MarkdownDescription: "An identifier for the space. If space_id is not provided, the default space is used.", + Optional: true, + Computed: true, + Default: stringdefault.StaticString("default"), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "list_id": schema.StringAttribute{ + MarkdownDescription: "The value list's human-readable identifier.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), + }, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "The name of the security list.", + Required: true, + }, + "description": schema.StringAttribute{ + MarkdownDescription: "Describes the security list.", + Required: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "Specifies the Elasticsearch data type of values the list contains. Valid values include: `binary`, `boolean`, `byte`, `date`, `date_nanos`, `date_range`, `double`, `double_range`, `float`, `float_range`, `geo_point`, `geo_shape`, `half_float`, `integer`, `integer_range`, `ip`, `ip_range`, `keyword`, `long`, `long_range`, `shape`, `short`, `text`.", + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf( + "binary", "boolean", "byte", "date", "date_nanos", "date_range", + "double", "double_range", "float", "float_range", "geo_point", "geo_shape", + "half_float", "integer", "integer_range", "ip", "ip_range", "keyword", + "long", "long_range", "shape", "short", "text", + ), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "deserializer": schema.StringAttribute{ + MarkdownDescription: "Determines how retrieved list item values are presented. By default, list items are presented using Handlebars expressions based on the type.", + Optional: true, + Computed: true, + }, + "serializer": schema.StringAttribute{ + MarkdownDescription: "Determines how uploaded list item values are parsed. By default, list items are parsed using named regex groups based on the type.", + Optional: true, + Computed: true, + }, + "meta": schema.StringAttribute{ + MarkdownDescription: "Placeholder for metadata about the value list as JSON string.", + Optional: true, + }, + "version": schema.Int64Attribute{ + MarkdownDescription: "The document version number.", + Optional: true, + Computed: true, + }, + "version_id": schema.StringAttribute{ + MarkdownDescription: "The version id, normally returned by the API when the document is retrieved.", + Computed: true, + }, + "immutable": schema.BoolAttribute{ + MarkdownDescription: "Whether the list is immutable.", + Computed: true, + }, + "created_at": schema.StringAttribute{ + MarkdownDescription: "The timestamp of when the list was created.", + Computed: true, + }, + "created_by": schema.StringAttribute{ + MarkdownDescription: "The user who created the list.", + Computed: true, + }, + "updated_at": schema.StringAttribute{ + MarkdownDescription: "The timestamp of when the list was last updated.", + Computed: true, + }, + "updated_by": schema.StringAttribute{ + MarkdownDescription: "The user who last updated the list.", + Computed: true, + }, + "tie_breaker_id": schema.StringAttribute{ + MarkdownDescription: "Field used in search to ensure all containers are sorted and returned correctly.", + Computed: true, + }, + }, + } +} diff --git a/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/create/main.tf b/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/create/main.tf new file mode 100644 index 000000000..8d7acc2eb --- /dev/null +++ b/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/create/main.tf @@ -0,0 +1,22 @@ +variable "list_id" { + type = string +} + +variable "name" { + type = string +} + +variable "description" { + type = string +} + +variable "type" { + type = string +} + +resource "elasticstack_kibana_security_list" "test" { + list_id = var.list_id + name = var.name + description = var.description + type = var.type +} diff --git a/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/update/main.tf b/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/update/main.tf new file mode 100644 index 000000000..8d7acc2eb --- /dev/null +++ b/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/update/main.tf @@ -0,0 +1,22 @@ +variable "list_id" { + type = string +} + +variable "name" { + type = string +} + +variable "description" { + type = string +} + +variable "type" { + type = string +} + +resource "elasticstack_kibana_security_list" "test" { + list_id = var.list_id + name = var.name + description = var.description + type = var.type +} diff --git a/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList_KeywordType/keyword_type/main.tf b/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList_KeywordType/keyword_type/main.tf new file mode 100644 index 000000000..8d7acc2eb --- /dev/null +++ b/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList_KeywordType/keyword_type/main.tf @@ -0,0 +1,22 @@ +variable "list_id" { + type = string +} + +variable "name" { + type = string +} + +variable "description" { + type = string +} + +variable "type" { + type = string +} + +resource "elasticstack_kibana_security_list" "test" { + list_id = var.list_id + name = var.name + description = var.description + type = var.type +} diff --git a/internal/kibana/security/security_list/update.go b/internal/kibana/security/security_list/update.go new file mode 100644 index 000000000..b0681ff35 --- /dev/null +++ b/internal/kibana/security/security_list/update.go @@ -0,0 +1,80 @@ +package securitylist + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *securityListResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan SecurityListModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + var state SecurityListModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + // Preserve version_id from state for optimistic locking + if state.VersionID.ValueString() != "" { + plan.VersionID = state.VersionID + } + + // Convert plan to API request + updateReq, diags := plan.toUpdateRequest() + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Get Kibana client + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Update the list + spaceID := plan.SpaceID.ValueString() + updateResp, diags := kibana_oapi.UpdateList(ctx, client, spaceID, *updateReq) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if updateResp == nil || updateResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to update security list", "API returned empty response") + return + } + + // Read the updated list to populate state + readParams := &kbapi.ReadListParams{ + Id: updateResp.JSON200.Id, + } + + readResp, diags := kibana_oapi.GetList(ctx, client, spaceID, readParams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Update state with read response + diags = plan.fromAPI(ctx, readResp.JSON200) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) +} diff --git a/provider/plugin_framework.go b/provider/plugin_framework.go index a9baa3162..f0f5897db 100644 --- a/provider/plugin_framework.go +++ b/provider/plugin_framework.go @@ -32,6 +32,7 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/kibana/maintenance_window" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/exception_item" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/exception_list" + securitylist "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/security_list" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security_detection_rule" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/spaces" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/synthetics/monitor" @@ -132,6 +133,7 @@ func (p *Provider) Resources(ctx context.Context) []func() resource.Resource { security_detection_rule.NewSecurityDetectionRuleResource, exception_list.NewResource, exception_item.NewResource, + securitylist.NewResource, job_state.NewMLJobStateResource, datafeed_state.NewMLDatafeedStateResource, } From 2d6c2ef12ad45a8b658d48631ba32dee23007efd Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Mon, 24 Nov 2025 11:41:35 -0700 Subject: [PATCH 16/21] Add resource template --- .../resources/kibana_security_list.md.tmpl | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 templates/resources/kibana_security_list.md.tmpl diff --git a/templates/resources/kibana_security_list.md.tmpl b/templates/resources/kibana_security_list.md.tmpl new file mode 100644 index 000000000..1c8f1ea33 --- /dev/null +++ b/templates/resources/kibana_security_list.md.tmpl @@ -0,0 +1,49 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" +subcategory: "Kibana" +description: |- +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +### IP address list + +{{ tffile "examples/resources/elasticstack_kibana_security_list/resource.tf" }} + +### Keyword list with custom list_id + +{{ tffile "examples/resources/elasticstack_kibana_security_list/resource_keyword.tf" }} + +{{ .SchemaMarkdown | trimspace }} +{{- if or .HasImport .HasImportIDConfig .HasImportIdentityConfig }} + +## Import + +Import is supported using the following syntax: +{{- end }} +{{- if .HasImportIdentityConfig }} + +In Terraform v1.12.0 and later, the [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used with the `identity` attribute, for example: + +{{tffile .ImportIdentityConfigFile }} + +{{ .IdentitySchemaMarkdown | trimspace }} +{{- end }} +{{- if .HasImportIDConfig }} + +In Terraform v1.5.0 and later, the [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used with the `id` attribute, for example: + +{{tffile .ImportIDConfigFile }} +{{- end }} +{{- if .HasImport }} + +The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example: + +{{codefile "shell" .ImportFile }} +{{- end }} From 084d79fd34f2aa85c4ab9dee0841731c84c710d9 Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Mon, 24 Nov 2025 14:30:53 -0700 Subject: [PATCH 17/21] Add kibana security list --- .../kibana_security_exception_item.md | 2 +- docs/resources/kibana_security_list_item.md | 197 ++++++++++++++++++ .../resource.tf | 13 ++ .../resource_ip.tf | 13 ++ .../resource_with_meta.tf | 18 ++ .../clients/kibana_oapi/security_lists.go | 72 +++++++ .../security/exception_item/acc_test.go | 2 + .../list/exception_item.tf | 9 +- .../security/security_list_item/acc_test.go | 73 +++++++ .../security/security_list_item/create.go | 77 +++++++ .../security/security_list_item/delete.go | 33 +++ .../security/security_list_item/models.go | 113 ++++++++++ .../security/security_list_item/read.go | 59 ++++++ .../resource-description.md | 57 +++++ .../security/security_list_item/resource.go | 38 ++++ .../security/security_list_item/schema.go | 76 +++++++ .../create/main.tf | 16 ++ .../update/main.tf | 16 ++ .../security/security_list_item/update.go | 77 +++++++ provider/plugin_framework.go | 2 + .../kibana_security_list_item.md.tmpl | 48 +++++ 21 files changed, 1009 insertions(+), 2 deletions(-) create mode 100644 docs/resources/kibana_security_list_item.md create mode 100644 examples/resources/elasticstack_kibana_security_list_item/resource.tf create mode 100644 examples/resources/elasticstack_kibana_security_list_item/resource_ip.tf create mode 100644 examples/resources/elasticstack_kibana_security_list_item/resource_with_meta.tf create mode 100644 internal/kibana/security/security_list_item/acc_test.go create mode 100644 internal/kibana/security/security_list_item/create.go create mode 100644 internal/kibana/security/security_list_item/delete.go create mode 100644 internal/kibana/security/security_list_item/models.go create mode 100644 internal/kibana/security/security_list_item/read.go create mode 100644 internal/kibana/security/security_list_item/resource-description.md create mode 100644 internal/kibana/security/security_list_item/resource.go create mode 100644 internal/kibana/security/security_list_item/schema.go create mode 100644 internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/create/main.tf create mode 100644 internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/update/main.tf create mode 100644 internal/kibana/security/security_list_item/update.go create mode 100644 templates/resources/kibana_security_list_item.md.tmpl diff --git a/docs/resources/kibana_security_exception_item.md b/docs/resources/kibana_security_exception_item.md index 523ba6808..2289a6ddf 100644 --- a/docs/resources/kibana_security_exception_item.md +++ b/docs/resources/kibana_security_exception_item.md @@ -126,13 +126,13 @@ resource "elasticstack_kibana_security_exception_item" "complex_entry" { Required: - `field` (String) The field name. Required for all entry types. -- `operator` (String) The operator to use. Valid values: `included`, `excluded`. - `type` (String) The type of entry. Valid values: `match`, `match_any`, `list`, `exists`, `nested`, `wildcard`. Optional: - `entries` (Attributes List) Nested entries (for `nested` type). Only `match`, `match_any`, and `exists` entry types are allowed as nested entries. (see [below for nested schema](#nestedatt--entries--entries)) - `list` (Attributes) Value list reference (for `list` type). (see [below for nested schema](#nestedatt--entries--list)) +- `operator` (String) The operator to use. Valid values: `included`, `excluded`. Note: The operator field is not supported for nested entry types and will be ignored if specified. - `value` (String) The value to match (for `match` and `wildcard` types). - `values` (List of String) Array of values to match (for `match_any` type). diff --git a/docs/resources/kibana_security_list_item.md b/docs/resources/kibana_security_list_item.md new file mode 100644 index 000000000..14645968f --- /dev/null +++ b/docs/resources/kibana_security_list_item.md @@ -0,0 +1,197 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "elasticstack_kibana_security_list_item Resource - terraform-provider-elasticstack" +subcategory: "Kibana" +description: |- + subcategory: "Kibana" + layout: "" + page_title: "Elasticstack: elasticstack_kibana_security_list_item Resource" + description: |- + Manages items within Kibana security value lists. + Resource: elasticstack_kibana_security_list_item + Manages items within Kibana security value lists. Value lists are containers for values that can be used within exception lists to define conditions. This resource allows you to add, update, and remove individual values (items) in those lists. + Value list items are used to store data values that match the type of their parent security list (e.g., IP addresses, keywords, etc.). These items can then be referenced in exception list entries to define exception conditions. + Example Usage + + # First create a security list + resource "elasticstack_kibana_security_list" "ip_list" { + list_id = "allowed_ips" + name = "Allowed IP Addresses" + description = "List of IP addresses that are allowed" + type = "ip" + } + + # Add an IP address to the list + resource "elasticstack_kibana_security_list_item" "ip_item_1" { + list_id = elasticstack_kibana_security_list.ip_list.list_id + value = "192.168.1.1" + } + + # Add another IP address + resource "elasticstack_kibana_security_list_item" "ip_item_2" { + list_id = elasticstack_kibana_security_list.ip_list.list_id + value = "10.0.0.1" + } + + # Add a keyword item with metadata + resource "elasticstack_kibana_security_list" "keyword_list" { + list_id = "allowed_domains" + name = "Allowed Domains" + description = "List of domains that are allowed" + type = "keyword" + } + + resource "elasticstack_kibana_security_list_item" "domain_item" { + list_id = elasticstack_kibana_security_list.keyword_list.list_id + value = "example.com" + meta = jsonencode({ + note = "Primary corporate domain" + }) + } + + Note on Space Support + Important: The generated Kibana API client does not currently support space_id for list item operations. While the space_id attribute is available in the schema for future compatibility, list items currently operate in the default space only. This is a known limitation that will be addressed in a future update when the API client is regenerated with proper space support. +--- + +# elasticstack_kibana_security_list_item (Resource) + +--- +subcategory: "Kibana" +layout: "" +page_title: "Elasticstack: elasticstack_kibana_security_list_item Resource" +description: |- + Manages items within Kibana security value lists. +--- + +# Resource: elasticstack_kibana_security_list_item + +Manages items within Kibana security value lists. Value lists are containers for values that can be used within exception lists to define conditions. This resource allows you to add, update, and remove individual values (items) in those lists. + +Value list items are used to store data values that match the type of their parent security list (e.g., IP addresses, keywords, etc.). These items can then be referenced in exception list entries to define exception conditions. + +## Example Usage + +```terraform +# First create a security list +resource "elasticstack_kibana_security_list" "ip_list" { + list_id = "allowed_ips" + name = "Allowed IP Addresses" + description = "List of IP addresses that are allowed" + type = "ip" +} + +# Add an IP address to the list +resource "elasticstack_kibana_security_list_item" "ip_item_1" { + list_id = elasticstack_kibana_security_list.ip_list.list_id + value = "192.168.1.1" +} + +# Add another IP address +resource "elasticstack_kibana_security_list_item" "ip_item_2" { + list_id = elasticstack_kibana_security_list.ip_list.list_id + value = "10.0.0.1" +} + +# Add a keyword item with metadata +resource "elasticstack_kibana_security_list" "keyword_list" { + list_id = "allowed_domains" + name = "Allowed Domains" + description = "List of domains that are allowed" + type = "keyword" +} + +resource "elasticstack_kibana_security_list_item" "domain_item" { + list_id = elasticstack_kibana_security_list.keyword_list.list_id + value = "example.com" + meta = jsonencode({ + note = "Primary corporate domain" + }) +} +``` + +## Note on Space Support + +**Important**: The generated Kibana API client does not currently support space_id for list item operations. While the `space_id` attribute is available in the schema for future compatibility, list items currently operate in the default space only. This is a known limitation that will be addressed in a future update when the API client is regenerated with proper space support. + +## Example Usage + +### Basic keyword value + +```terraform +# First create a security list +resource "elasticstack_kibana_security_list" "my_list" { + list_id = "allowed_domains" + name = "Allowed Domains" + description = "List of allowed domains" + type = "keyword" +} + +# Add an item to the list +resource "elasticstack_kibana_security_list_item" "domain_example" { + list_id = elasticstack_kibana_security_list.my_list.list_id + value = "example.com" +} +``` + +### IP address value + +```terraform +# First create an IP address list +resource "elasticstack_kibana_security_list" "ip_list" { + list_id = "allowed_ips" + name = "Allowed IP Addresses" + description = "List of allowed IP addresses" + type = "ip" +} + +# Add an IP address to the list +resource "elasticstack_kibana_security_list_item" "ip_example" { + list_id = elasticstack_kibana_security_list.ip_list.list_id + value = "192.168.1.1" +} +``` + +### Value with metadata + +```terraform +# First create a security list +resource "elasticstack_kibana_security_list" "tagged_domains" { + list_id = "tagged_domains" + name = "Tagged Domains" + description = "Domains with associated metadata" + type = "keyword" +} + +# Add an item with metadata +resource "elasticstack_kibana_security_list_item" "domain_with_meta" { + list_id = elasticstack_kibana_security_list.tagged_domains.list_id + value = "internal.example.com" + meta = jsonencode({ + category = "internal" + owner = "infrastructure-team" + note = "Primary internal domain" + }) +} +``` + + +## Schema + +### Required + +- `list_id` (String) The value list's identifier that this item belongs to. +- `value` (String) The value used to evaluate exceptions. The value's data type must match the list's type. + +### Optional + +- `id` (String) The value list item's identifier (auto-generated by Kibana if not specified). +- `meta` (String) Placeholder for metadata about the value list item as JSON string. +- `space_id` (String) An identifier for the space. If space_id is not provided, the default space is used. + +### Read-Only + +- `created_at` (String) The timestamp of when the list item was created. +- `created_by` (String) The user who created the list item. +- `updated_at` (String) The timestamp of when the list item was last updated. +- `updated_by` (String) The user who last updated the list item. +- `version` (String) The version id, normally returned by the API when the document is retrieved. Used to ensure updates are done against the latest version. diff --git a/examples/resources/elasticstack_kibana_security_list_item/resource.tf b/examples/resources/elasticstack_kibana_security_list_item/resource.tf new file mode 100644 index 000000000..705311869 --- /dev/null +++ b/examples/resources/elasticstack_kibana_security_list_item/resource.tf @@ -0,0 +1,13 @@ +# First create a security list +resource "elasticstack_kibana_security_list" "my_list" { + list_id = "allowed_domains" + name = "Allowed Domains" + description = "List of allowed domains" + type = "keyword" +} + +# Add an item to the list +resource "elasticstack_kibana_security_list_item" "domain_example" { + list_id = elasticstack_kibana_security_list.my_list.list_id + value = "example.com" +} diff --git a/examples/resources/elasticstack_kibana_security_list_item/resource_ip.tf b/examples/resources/elasticstack_kibana_security_list_item/resource_ip.tf new file mode 100644 index 000000000..d306ef013 --- /dev/null +++ b/examples/resources/elasticstack_kibana_security_list_item/resource_ip.tf @@ -0,0 +1,13 @@ +# First create an IP address list +resource "elasticstack_kibana_security_list" "ip_list" { + list_id = "allowed_ips" + name = "Allowed IP Addresses" + description = "List of allowed IP addresses" + type = "ip" +} + +# Add an IP address to the list +resource "elasticstack_kibana_security_list_item" "ip_example" { + list_id = elasticstack_kibana_security_list.ip_list.list_id + value = "192.168.1.1" +} diff --git a/examples/resources/elasticstack_kibana_security_list_item/resource_with_meta.tf b/examples/resources/elasticstack_kibana_security_list_item/resource_with_meta.tf new file mode 100644 index 000000000..03131f882 --- /dev/null +++ b/examples/resources/elasticstack_kibana_security_list_item/resource_with_meta.tf @@ -0,0 +1,18 @@ +# First create a security list +resource "elasticstack_kibana_security_list" "tagged_domains" { + list_id = "tagged_domains" + name = "Tagged Domains" + description = "Domains with associated metadata" + type = "keyword" +} + +# Add an item with metadata +resource "elasticstack_kibana_security_list_item" "domain_with_meta" { + list_id = elasticstack_kibana_security_list.tagged_domains.list_id + value = "internal.example.com" + meta = jsonencode({ + category = "internal" + owner = "infrastructure-team" + note = "Primary internal domain" + }) +} diff --git a/internal/clients/kibana_oapi/security_lists.go b/internal/clients/kibana_oapi/security_lists.go index 4164ec610..f6f09f133 100644 --- a/internal/clients/kibana_oapi/security_lists.go +++ b/internal/clients/kibana_oapi/security_lists.go @@ -88,3 +88,75 @@ func DeleteList(ctx context.Context, client *Client, spaceId string, params *kba return reportUnknownError(resp.StatusCode(), resp.Body) } } + +// GetListItem reads a security list item from the API by ID or list_id and value +// Note: The generated Kibana API client does not support space_id for list items yet, +// so this function operates in the default space only. +func GetListItem(ctx context.Context, client *Client, params *kbapi.ReadListItemParams) (*kbapi.ReadListItemResponse, diag.Diagnostics) { + resp, err := client.API.ReadListItemWithResponse(ctx, params) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + case http.StatusNotFound: + return nil, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// CreateListItem creates a new security list item. +// Note: The generated Kibana API client does not support space_id for list items yet, +// so this function operates in the default space only. +func CreateListItem(ctx context.Context, client *Client, body kbapi.CreateListItemJSONRequestBody) (*kbapi.CreateListItemResponse, diag.Diagnostics) { + resp, err := client.API.CreateListItemWithResponse(ctx, body) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// UpdateListItem updates an existing security list item. +// Note: The generated Kibana API client does not support space_id for list items yet, +// so this function operates in the default space only. +func UpdateListItem(ctx context.Context, client *Client, body kbapi.UpdateListItemJSONRequestBody) (*kbapi.UpdateListItemResponse, diag.Diagnostics) { + resp, err := client.API.UpdateListItemWithResponse(ctx, body) + if err != nil { + return nil, diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// DeleteListItem deletes an existing security list item. +// Note: The generated Kibana API client does not support space_id for list items yet, +// so this function operates in the default space only. +func DeleteListItem(ctx context.Context, client *Client, params *kbapi.DeleteListItemParams) diag.Diagnostics { + resp, err := client.API.DeleteListItemWithResponse(ctx, params) + if err != nil { + return diagutil.FrameworkDiagFromError(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return nil + case http.StatusNotFound: + return nil + default: + return reportUnknownError(resp.StatusCode(), resp.Body) + } +} diff --git a/internal/kibana/security/exception_item/acc_test.go b/internal/kibana/security/exception_item/acc_test.go index 56c05dbac..73a8ecdd4 100644 --- a/internal/kibana/security/exception_item/acc_test.go +++ b/internal/kibana/security/exception_item/acc_test.go @@ -199,6 +199,7 @@ func TestAccResourceExceptionItemEntryType_List(t *testing.T) { exceptionListID := fmt.Sprintf("test-exception-list-list-entry-%s", uuid.New().String()[:8]) itemID := fmt.Sprintf("test-exception-item-list-entry-%s", uuid.New().String()[:8]) valueListID := fmt.Sprintf("test-value-list-%s", uuid.New().String()[:8]) + valueListValue := "192.168.1.1" resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -211,6 +212,7 @@ func TestAccResourceExceptionItemEntryType_List(t *testing.T) { "exception_list_id": config.StringVariable(exceptionListID), "item_id": config.StringVariable(itemID), "value_list_id": config.StringVariable(valueListID), + "value_list_value": config.StringVariable(valueListValue), }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_security_exception_item.test", "entries.0.type", "list"), diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf index 3f1738a78..caed9f9d5 100644 --- a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf @@ -12,6 +12,10 @@ variable "value_list_id" { description = "The value list ID" type = string } +variable "value_list_value" { + description = "The value list value" + type = string +} provider "elasticstack" { elasticsearch {} @@ -25,6 +29,10 @@ resource "elasticstack_kibana_security_exception_list" "test" { type = "detection" namespace_type = "single" } +resource "elasticstack_kibana_security_list_item" "test-item" { + list_id = elasticstack_kibana_security_list.test.list_id + value = var.value_list_value +} # Create a value list to reference in the exception item resource "elasticstack_kibana_security_list" "test" { @@ -32,7 +40,6 @@ resource "elasticstack_kibana_security_list" "test" { name = "Test Value List" description = "Test value list for list entry type" type = "ip" - # values = ["192.168.1.1", "192.168.1.2", "10.0.0.1"] } resource "elasticstack_kibana_security_exception_item" "test" { diff --git a/internal/kibana/security/security_list_item/acc_test.go b/internal/kibana/security/security_list_item/acc_test.go new file mode 100644 index 000000000..859c90fd7 --- /dev/null +++ b/internal/kibana/security/security_list_item/acc_test.go @@ -0,0 +1,73 @@ +package securitylistitem_test + +import ( + "context" + "testing" + + "github.com/elastic/terraform-provider-elasticstack/internal/acctest" + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func ensureListIndexExists(t *testing.T) { + client, err := clients.NewAcceptanceTestingClient() + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + kibanaClient, err := client.GetKibanaOapiClient() + if err != nil { + t.Fatalf("Failed to get Kibana client: %v", err) + } + + diags := kibana_oapi.CreateListIndex(context.Background(), kibanaClient, "default") + if diags.HasError() { + // It's OK if it already exists, we'll only fail on other errors + for _, d := range diags { + if d.Summary() != "Unexpected status code from server: got HTTP 409" { + t.Fatalf("Failed to create list index: %v", d.Detail()) + } + } + } +} + +func TestAccResourceSecurityListItem(t *testing.T) { + listID := "test-list-items-" + uuid.New().String() + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + ensureListIndexExists(t) + }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { // Create + ConfigDirectory: acctest.NamedTestCaseDirectory("create"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "value": config.StringVariable("test-value-1"), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list_item.test", "id"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_list_item.test", "value", "test-value-1"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list_item.test", "created_at"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list_item.test", "created_by"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list_item.test", "updated_at"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list_item.test", "updated_by"), + ), + }, + { // Update + ConfigDirectory: acctest.NamedTestCaseDirectory("update"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "value": config.StringVariable("test-value-updated"), + }, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_list_item.test", "value", "test-value-updated"), + ), + }, + }, + }) +} diff --git a/internal/kibana/security/security_list_item/create.go b/internal/kibana/security/security_list_item/create.go new file mode 100644 index 000000000..654ae25af --- /dev/null +++ b/internal/kibana/security/security_list_item/create.go @@ -0,0 +1,77 @@ +package securitylistitem + +import ( + "context" + "encoding/json" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *securityListItemResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan SecurityListItemModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + // Get Kibana client + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Convert plan to API request + createReq, diags := plan.toAPICreateModel(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Create the list item + createResp, diags := kibana_oapi.CreateListItem(ctx, client, *createReq) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if createResp == nil || createResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to create security list item", "API returned empty response") + return + } + + // Read the created list item to populate state + id := kbapi.SecurityListsAPIListId(createResp.JSON200.Id) + readParams := &kbapi.ReadListItemParams{ + Id: &id, + } + + readResp, diags := kibana_oapi.GetListItem(ctx, client, readParams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Unmarshal the response body to get the list item + var listItem kbapi.SecurityListsAPIListItem + if err := json.Unmarshal(readResp.Body, &listItem); err != nil { + resp.Diagnostics.AddError("Failed to parse list item response", err.Error()) + return + } + + // Update state with read response + diags = plan.fromAPIModel(ctx, &listItem) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) +} diff --git a/internal/kibana/security/security_list_item/delete.go b/internal/kibana/security/security_list_item/delete.go new file mode 100644 index 000000000..1600c94af --- /dev/null +++ b/internal/kibana/security/security_list_item/delete.go @@ -0,0 +1,33 @@ +package securitylistitem + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *securityListItemResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state SecurityListItemModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + // Get Kibana client + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Delete by ID + id := kbapi.SecurityListsAPIListItemId(state.ID.ValueString()) + params := &kbapi.DeleteListItemParams{ + Id: &id, + } + + diags := kibana_oapi.DeleteListItem(ctx, client, params) + resp.Diagnostics.Append(diags...) +} diff --git a/internal/kibana/security/security_list_item/models.go b/internal/kibana/security/security_list_item/models.go new file mode 100644 index 000000000..84f1f2b04 --- /dev/null +++ b/internal/kibana/security/security_list_item/models.go @@ -0,0 +1,113 @@ +package securitylistitem + +import ( + "context" + "encoding/json" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type SecurityListItemModel struct { + ID types.String `tfsdk:"id"` + SpaceID types.String `tfsdk:"space_id"` + ListID types.String `tfsdk:"list_id"` + Value types.String `tfsdk:"value"` + Meta types.String `tfsdk:"meta"` + CreatedAt types.String `tfsdk:"created_at"` + CreatedBy types.String `tfsdk:"created_by"` + UpdatedAt types.String `tfsdk:"updated_at"` + UpdatedBy types.String `tfsdk:"updated_by"` + Version types.String `tfsdk:"version"` +} + +// toAPICreateModel converts the Terraform model to the API create request body +func (m *SecurityListItemModel) toAPICreateModel(ctx context.Context) (*kbapi.CreateListItemJSONRequestBody, diag.Diagnostics) { + var diags diag.Diagnostics + + body := &kbapi.CreateListItemJSONRequestBody{ + ListId: kbapi.SecurityListsAPIListId(m.ListID.ValueString()), + Value: kbapi.SecurityListsAPIListItemValue(m.Value.ValueString()), + } + + // Set optional ID if specified + if !m.ID.IsNull() && !m.ID.IsUnknown() { + id := kbapi.SecurityListsAPIListItemId(m.ID.ValueString()) + body.Id = &id + } + + // Set optional meta if specified + if !m.Meta.IsNull() && !m.Meta.IsUnknown() { + var meta kbapi.SecurityListsAPIListItemMetadata + if err := json.Unmarshal([]byte(m.Meta.ValueString()), &meta); err != nil { + diags.AddError("Failed to parse meta JSON", err.Error()) + return nil, diags + } + body.Meta = &meta + } + + return body, diags +} + +// toAPIUpdateModel converts the Terraform model to the API update request body +func (m *SecurityListItemModel) toAPIUpdateModel(ctx context.Context) (*kbapi.UpdateListItemJSONRequestBody, diag.Diagnostics) { + var diags diag.Diagnostics + + body := &kbapi.UpdateListItemJSONRequestBody{ + Id: kbapi.SecurityListsAPIListItemId(m.ID.ValueString()), + Value: kbapi.SecurityListsAPIListItemValue(m.Value.ValueString()), + } + + // Set optional version if available + if !m.Version.IsNull() && !m.Version.IsUnknown() { + version := kbapi.SecurityListsAPIListVersionId(m.Version.ValueString()) + body.UnderscoreVersion = &version + } + + // Set optional meta if specified + if !m.Meta.IsNull() && !m.Meta.IsUnknown() { + var meta kbapi.SecurityListsAPIListItemMetadata + if err := json.Unmarshal([]byte(m.Meta.ValueString()), &meta); err != nil { + diags.AddError("Failed to parse meta JSON", err.Error()) + return nil, diags + } + body.Meta = &meta + } + + return body, diags +} + +// fromAPIModel populates the Terraform model from an API response +func (m *SecurityListItemModel) fromAPIModel(ctx context.Context, apiItem *kbapi.SecurityListsAPIListItem) diag.Diagnostics { + var diags diag.Diagnostics + + m.ID = types.StringValue(string(apiItem.Id)) + m.ListID = types.StringValue(string(apiItem.ListId)) + m.Value = types.StringValue(string(apiItem.Value)) + m.CreatedAt = types.StringValue(apiItem.CreatedAt.Format("2006-01-02T15:04:05.000Z")) + m.CreatedBy = types.StringValue(apiItem.CreatedBy) + m.UpdatedAt = types.StringValue(apiItem.UpdatedAt.Format("2006-01-02T15:04:05.000Z")) + m.UpdatedBy = types.StringValue(apiItem.UpdatedBy) + + // Set version if available + if apiItem.UnderscoreVersion != nil { + m.Version = types.StringValue(string(*apiItem.UnderscoreVersion)) + } else { + m.Version = types.StringNull() + } + + // Set meta if available + if apiItem.Meta != nil { + metaJSON, err := json.Marshal(apiItem.Meta) + if err != nil { + diags.AddError("Failed to serialize meta", err.Error()) + return diags + } + m.Meta = types.StringValue(string(metaJSON)) + } else { + m.Meta = types.StringNull() + } + + return diags +} diff --git a/internal/kibana/security/security_list_item/read.go b/internal/kibana/security/security_list_item/read.go new file mode 100644 index 000000000..7bad0296a --- /dev/null +++ b/internal/kibana/security/security_list_item/read.go @@ -0,0 +1,59 @@ +package securitylistitem + +import ( + "context" + "encoding/json" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *securityListItemResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state SecurityListItemModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + // Get Kibana client + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Read by ID + id := kbapi.SecurityListsAPIListId(state.ID.ValueString()) + params := &kbapi.ReadListItemParams{ + Id: &id, + } + + readResp, diags := kibana_oapi.GetListItem(ctx, client, params) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // The response can be a single item or an array, so we need to unmarshal from the body + // When querying by ID, we expect a single item + var listItem kbapi.SecurityListsAPIListItem + if err := json.Unmarshal(readResp.Body, &listItem); err != nil { + resp.Diagnostics.AddError("Failed to parse list item response", err.Error()) + return + } + + // Update state with response + diags = state.fromAPIModel(ctx, &listItem) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, state)...) +} diff --git a/internal/kibana/security/security_list_item/resource-description.md b/internal/kibana/security/security_list_item/resource-description.md new file mode 100644 index 000000000..d00e14915 --- /dev/null +++ b/internal/kibana/security/security_list_item/resource-description.md @@ -0,0 +1,57 @@ +--- +subcategory: "Kibana" +layout: "" +page_title: "Elasticstack: elasticstack_kibana_security_list_item Resource" +description: |- + Manages items within Kibana security value lists. +--- + +# Resource: elasticstack_kibana_security_list_item + +Manages items within Kibana security value lists. Value lists are containers for values that can be used within exception lists to define conditions. This resource allows you to add, update, and remove individual values (items) in those lists. + +Value list items are used to store data values that match the type of their parent security list (e.g., IP addresses, keywords, etc.). These items can then be referenced in exception list entries to define exception conditions. + +## Example Usage + +```terraform +# First create a security list +resource "elasticstack_kibana_security_list" "ip_list" { + list_id = "allowed_ips" + name = "Allowed IP Addresses" + description = "List of IP addresses that are allowed" + type = "ip" +} + +# Add an IP address to the list +resource "elasticstack_kibana_security_list_item" "ip_item_1" { + list_id = elasticstack_kibana_security_list.ip_list.list_id + value = "192.168.1.1" +} + +# Add another IP address +resource "elasticstack_kibana_security_list_item" "ip_item_2" { + list_id = elasticstack_kibana_security_list.ip_list.list_id + value = "10.0.0.1" +} + +# Add a keyword item with metadata +resource "elasticstack_kibana_security_list" "keyword_list" { + list_id = "allowed_domains" + name = "Allowed Domains" + description = "List of domains that are allowed" + type = "keyword" +} + +resource "elasticstack_kibana_security_list_item" "domain_item" { + list_id = elasticstack_kibana_security_list.keyword_list.list_id + value = "example.com" + meta = jsonencode({ + note = "Primary corporate domain" + }) +} +``` + +## Note on Space Support + +**Important**: The generated Kibana API client does not currently support space_id for list item operations. While the `space_id` attribute is available in the schema for future compatibility, list items currently operate in the default space only. This is a known limitation that will be addressed in a future update when the API client is regenerated with proper space support. diff --git a/internal/kibana/security/security_list_item/resource.go b/internal/kibana/security/security_list_item/resource.go new file mode 100644 index 000000000..1148cb862 --- /dev/null +++ b/internal/kibana/security/security_list_item/resource.go @@ -0,0 +1,38 @@ +package securitylistitem + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &securityListItemResource{} + _ resource.ResourceWithConfigure = &securityListItemResource{} + _ resource.ResourceWithImportState = &securityListItemResource{} +) + +func NewResource() resource.Resource { + return &securityListItemResource{} +} + +type securityListItemResource struct { + client *clients.ApiClient +} + +func (r *securityListItemResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_kibana_security_list_item" +} + +func (r *securityListItemResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + client, diags := clients.ConvertProviderData(req.ProviderData) + resp.Diagnostics.Append(diags...) + r.client = client +} + +func (r *securityListItemResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response) +} diff --git a/internal/kibana/security/security_list_item/schema.go b/internal/kibana/security/security_list_item/schema.go new file mode 100644 index 000000000..e790fa2bf --- /dev/null +++ b/internal/kibana/security/security_list_item/schema.go @@ -0,0 +1,76 @@ +package securitylistitem + +import ( + "context" + _ "embed" + + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" +) + +//go:embed resource-description.md +var securityListItemResourceDescription string + +func (r *securityListItemResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: securityListItemResourceDescription, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The value list item's identifier (auto-generated by Kibana if not specified).", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), + }, + }, + "space_id": schema.StringAttribute{ + MarkdownDescription: "An identifier for the space. If space_id is not provided, the default space is used.", + Optional: true, + Computed: true, + Default: stringdefault.StaticString("default"), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "list_id": schema.StringAttribute{ + MarkdownDescription: "The value list's identifier that this item belongs to.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "value": schema.StringAttribute{ + MarkdownDescription: "The value used to evaluate exceptions. The value's data type must match the list's type.", + Required: true, + }, + "meta": schema.StringAttribute{ + MarkdownDescription: "Placeholder for metadata about the value list item as JSON string.", + Optional: true, + }, + "version": schema.StringAttribute{ + MarkdownDescription: "The version id, normally returned by the API when the document is retrieved. Used to ensure updates are done against the latest version.", + Computed: true, + }, + "created_at": schema.StringAttribute{ + MarkdownDescription: "The timestamp of when the list item was created.", + Computed: true, + }, + "created_by": schema.StringAttribute{ + MarkdownDescription: "The user who created the list item.", + Computed: true, + }, + "updated_at": schema.StringAttribute{ + MarkdownDescription: "The timestamp of when the list item was last updated.", + Computed: true, + }, + "updated_by": schema.StringAttribute{ + MarkdownDescription: "The user who last updated the list item.", + Computed: true, + }, + }, + } +} diff --git a/internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/create/main.tf b/internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/create/main.tf new file mode 100644 index 000000000..246c973a6 --- /dev/null +++ b/internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/create/main.tf @@ -0,0 +1,16 @@ +variable "list_id" {} +variable "value" {} + +# First create a security list to put items in +resource "elasticstack_kibana_security_list" "test" { + list_id = var.list_id + name = "Test List for Items" + description = "A test security list for IP addresses" + type = "keyword" +} + +# Create a list item +resource "elasticstack_kibana_security_list_item" "test" { + list_id = elasticstack_kibana_security_list.test.list_id + value = var.value +} diff --git a/internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/update/main.tf b/internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/update/main.tf new file mode 100644 index 000000000..df1d6c668 --- /dev/null +++ b/internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/update/main.tf @@ -0,0 +1,16 @@ +variable "list_id" {} +variable "value" {} + +# First create a security list to put items in +resource "elasticstack_kibana_security_list" "test" { + list_id = var.list_id + name = "Test List for Items" + description = "A test security list for IP addresses" + type = "keyword" +} + +# Create a list item with updated value +resource "elasticstack_kibana_security_list_item" "test" { + list_id = elasticstack_kibana_security_list.test.list_id + value = var.value +} diff --git a/internal/kibana/security/security_list_item/update.go b/internal/kibana/security/security_list_item/update.go new file mode 100644 index 000000000..bfd362f38 --- /dev/null +++ b/internal/kibana/security/security_list_item/update.go @@ -0,0 +1,77 @@ +package securitylistitem + +import ( + "context" + "encoding/json" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +func (r *securityListItemResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan SecurityListItemModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + // Get Kibana client + client, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Failed to get Kibana client", err.Error()) + return + } + + // Convert plan to API request + updateReq, diags := plan.toAPIUpdateModel(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Update the list item + updateResp, diags := kibana_oapi.UpdateListItem(ctx, client, *updateReq) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if updateResp == nil || updateResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to update security list item", "API returned empty response") + return + } + + // Read the updated list item to populate state + id := kbapi.SecurityListsAPIListId(updateResp.JSON200.Id) + readParams := &kbapi.ReadListItemParams{ + Id: &id, + } + + readResp, diags := kibana_oapi.GetListItem(ctx, client, readParams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if readResp == nil || readResp.JSON200 == nil { + resp.State.RemoveResource(ctx) + return + } + + // Unmarshal the response body to get the list item + var listItem kbapi.SecurityListsAPIListItem + if err := json.Unmarshal(readResp.Body, &listItem); err != nil { + resp.Diagnostics.AddError("Failed to parse list item response", err.Error()) + return + } + + // Update state with read response + diags = plan.fromAPIModel(ctx, &listItem) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) +} diff --git a/provider/plugin_framework.go b/provider/plugin_framework.go index f0f5897db..f3068d86c 100644 --- a/provider/plugin_framework.go +++ b/provider/plugin_framework.go @@ -33,6 +33,7 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/exception_item" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/exception_list" securitylist "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/security_list" + securitylistitem "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/security_list_item" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security_detection_rule" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/spaces" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/synthetics/monitor" @@ -134,6 +135,7 @@ func (p *Provider) Resources(ctx context.Context) []func() resource.Resource { exception_list.NewResource, exception_item.NewResource, securitylist.NewResource, + securitylistitem.NewResource, job_state.NewMLJobStateResource, datafeed_state.NewMLDatafeedStateResource, } diff --git a/templates/resources/kibana_security_list_item.md.tmpl b/templates/resources/kibana_security_list_item.md.tmpl new file mode 100644 index 000000000..a69108d49 --- /dev/null +++ b/templates/resources/kibana_security_list_item.md.tmpl @@ -0,0 +1,48 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" +subcategory: "Kibana" +description: |- +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +### Basic keyword value + +{{ tffile "examples/resources/elasticstack_kibana_security_list_item/resource.tf" }} + +### IP address value + +{{ tffile "examples/resources/elasticstack_kibana_security_list_item/resource_ip.tf" }} + +### Value with metadata + +{{ tffile "examples/resources/elasticstack_kibana_security_list_item/resource_with_meta.tf" }} + +{{ .SchemaMarkdown | trimspace }} +{{- if or .HasImport .HasImportIDConfig .HasImportIdentityConfig }} + +## Import + +Import is supported using the following syntax: +{{- end }} +{{- if .HasImportIdentityConfig }} + +{{ codefile "sh" .ImportIdentityConfig }} + +{{- end }} +{{- if .HasImportIDConfig }} + +{{ codefile "sh" .ImportIDConfig }} + +{{- end }} +{{- if .HasImport }} + +{{ codefile "sh" .ImportFile }} + +{{- end }} From a3c2efd78eaff9e772d1482fe04e876741969ac7 Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Tue, 25 Nov 2025 11:16:29 -0700 Subject: [PATCH 18/21] Add validations for security exceptions --- .../security/exception_item/resource.go | 7 +- .../kibana/security/exception_item/schema.go | 26 -- .../security/exception_item/validate.go | 226 ++++++++++++++++++ 3 files changed, 230 insertions(+), 29 deletions(-) create mode 100644 internal/kibana/security/exception_item/validate.go diff --git a/internal/kibana/security/exception_item/resource.go b/internal/kibana/security/exception_item/resource.go index 5eea3137e..247fdbddc 100644 --- a/internal/kibana/security/exception_item/resource.go +++ b/internal/kibana/security/exception_item/resource.go @@ -10,9 +10,10 @@ import ( ) var ( - _ resource.Resource = &ExceptionItemResource{} - _ resource.ResourceWithConfigure = &ExceptionItemResource{} - _ resource.ResourceWithImportState = &ExceptionItemResource{} + _ resource.Resource = &ExceptionItemResource{} + _ resource.ResourceWithConfigure = &ExceptionItemResource{} + _ resource.ResourceWithImportState = &ExceptionItemResource{} + _ resource.ResourceWithValidateConfig = &ExceptionItemResource{} ) // NewResource is a helper function to simplify the provider implementation. diff --git a/internal/kibana/security/exception_item/schema.go b/internal/kibana/security/exception_item/schema.go index 3e99ac38e..a2651d1a4 100644 --- a/internal/kibana/security/exception_item/schema.go +++ b/internal/kibana/security/exception_item/schema.go @@ -119,14 +119,6 @@ func (r *ExceptionItemResource) Schema(_ context.Context, _ resource.SchemaReque MarkdownDescription: "The operator to use. Valid values: `included`, `excluded`. Note: The operator field is not supported for nested entry types and will be ignored if specified.", Optional: true, Validators: []validator.String{ - validators.ForbiddenIfDependentPathOneOf( - path.Root("type"), - []string{"nested"}, - ), - validators.RequiredIfDependentPathOneOf( - path.Root("type"), - []string{"match", "match_any", "list", "exists", "wildcard"}, - ), stringvalidator.OneOf("included", "excluded"), }, }, @@ -144,22 +136,10 @@ func (r *ExceptionItemResource) Schema(_ context.Context, _ resource.SchemaReque ElementType: types.StringType, MarkdownDescription: "Array of values to match (for `match_any` type).", Optional: true, - Validators: []validator.List{ - validators.RequiredIfDependentPathOneOf( - path.Root("type"), - []string{"match_any"}, - ), - }, }, "list": schema.SingleNestedAttribute{ MarkdownDescription: "Value list reference (for `list` type).", Optional: true, - Validators: []validator.Object{ - validators.RequiredIfDependentPathOneOf( - path.Root("type"), - []string{"list"}, - ), - }, Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ MarkdownDescription: "The value list ID.", @@ -174,12 +154,6 @@ func (r *ExceptionItemResource) Schema(_ context.Context, _ resource.SchemaReque "entries": schema.ListNestedAttribute{ MarkdownDescription: "Nested entries (for `nested` type). Only `match`, `match_any`, and `exists` entry types are allowed as nested entries.", Optional: true, - Validators: []validator.List{ - validators.RequiredIfDependentPathOneOf( - path.Root("type"), - []string{"nested"}, - ), - }, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "type": schema.StringAttribute{ diff --git a/internal/kibana/security/exception_item/validate.go b/internal/kibana/security/exception_item/validate.go new file mode 100644 index 000000000..cfda8e467 --- /dev/null +++ b/internal/kibana/security/exception_item/validate.go @@ -0,0 +1,226 @@ +package exception_item + +import ( + "context" + "fmt" + + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// ValidateConfig validates the configuration for an exception item resource. +// It ensures that entries are properly configured based on their type: +// +// - For "match" and "wildcard" types: 'value' must be set +// - For "match_any" type: 'values' must be set +// - For "list" type: 'list' object must be set with 'id' and 'type' +// - For "exists" type: only 'field' and 'operator' are required +// - For "nested" type: 'entries' must be set and validated recursively +// - The 'operator' field is required for all types except "nested" +// +// Validation only runs on known values. Values that are unknown (e.g., references to +// other resources that haven't been created yet) are skipped. +// +// The function adds appropriate error diagnostics if validation fails. +func (r *ExceptionItemResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + var data ExceptionItemModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + // Validate entries + if !utils.IsKnown(data.Entries) { + return + } + + var entries []EntryModel + resp.Diagnostics.Append(data.Entries.ElementsAs(ctx, &entries, false)...) + if resp.Diagnostics.HasError() { + return + } + + for i, entry := range entries { + validateEntry(ctx, entry, i, &resp.Diagnostics, "entries") + } +} + +// validateEntry validates a single entry based on its type +func validateEntry(ctx context.Context, entry EntryModel, index int, diags *diag.Diagnostics, path string) { + if !utils.IsKnown(entry.Type) { + return + } + + entryType := entry.Type.ValueString() + entryPath := fmt.Sprintf("%s[%d]", path, index) + + switch entryType { + case "match", "wildcard": + // 'value' is required (only validate if not unknown) + if entry.Value.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Entry type '%s' requires 'value' to be set at %s.", entryType, entryPath), + ) + } + // 'operator' is required (only validate if not unknown) + if entry.Operator.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Entry type '%s' requires 'operator' to be set at %s.", entryType, entryPath), + ) + } + + case "match_any": + // 'values' is required (only validate if not unknown) + if entry.Values.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Entry type 'match_any' requires 'values' to be set at %s.", entryPath), + ) + } + // 'operator' is required (only validate if not unknown) + if entry.Operator.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Entry type 'match_any' requires 'operator' to be set at %s.", entryPath), + ) + } + + case "list": + // 'list' object is required (only validate if not unknown) + if entry.List.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Entry type 'list' requires 'list' object to be set at %s.", entryPath), + ) + } else if !entry.List.IsUnknown() { + // Only validate list contents if the list object itself is known + var listModel EntryListModel + d := entry.List.As(ctx, &listModel, basetypes.ObjectAsOptions{}) + if d.HasError() { + diags.Append(d...) + } else { + // Only validate if the values are not unknown + if listModel.ID.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Entry type 'list' requires 'list.id' to be set at %s.", entryPath), + ) + } + + if listModel.Type.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Entry type 'list' requires 'list.type' to be set at %s.", entryPath), + ) + } + } + } + // 'operator' is required (only validate if not unknown) + if entry.Operator.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Entry type 'list' requires 'operator' to be set at %s.", entryPath), + ) + } + + case "exists": + // Only 'field' and 'operator' are required (already handled by schema) + // 'operator' is required (only validate if not unknown) + if entry.Operator.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Entry type 'exists' requires 'operator' to be set at %s.", entryPath), + ) + } + + case "nested": + // 'entries' is required for nested type (only validate if not unknown) + if entry.Entries.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Entry type 'nested' requires 'entries' to be set at %s.", entryPath), + ) + return + } + + // Skip validation if entries are unknown + if entry.Entries.IsUnknown() { + return + } + + // 'operator' should NOT be set for nested type + if utils.IsKnown(entry.Operator) { + diags.AddWarning( + "Ignored Field", + fmt.Sprintf("Entry type 'nested' does not support 'operator'. This field will be ignored at %s.", entryPath), + ) + } + + // Validate nested entries + var nestedEntries []NestedEntryModel + d := entry.Entries.ElementsAs(ctx, &nestedEntries, false) + if d.HasError() { + diags.Append(d...) + return + } + + for j, nestedEntry := range nestedEntries { + validateNestedEntry(ctx, nestedEntry, j, diags, fmt.Sprintf("%s.entries", entryPath)) + } + } +} + +// validateNestedEntry validates a nested entry within a "nested" type entry +func validateNestedEntry(ctx context.Context, entry NestedEntryModel, index int, diags *diag.Diagnostics, path string) { + if !utils.IsKnown(entry.Type) { + return + } + + entryType := entry.Type.ValueString() + entryPath := fmt.Sprintf("%s[%d]", path, index) + + // Nested entries can only be: match, match_any, or exists + switch entryType { + case "match": + // 'value' is required (only validate if not unknown) + if entry.Value.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Nested entry type 'match' requires 'value' to be set at %s.", entryPath), + ) + } + + case "match_any": + // 'values' is required (only validate if not unknown) + if entry.Values.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Nested entry type 'match_any' requires 'values' to be set at %s.", entryPath), + ) + } + + case "exists": + // Only 'field' and 'operator' are required (already handled by schema) + // Nothing additional to validate + + default: + diags.AddError( + "Invalid Entry Type", + fmt.Sprintf("Nested entry at %s has invalid type '%s'. Only 'match', 'match_any', and 'exists' are allowed for nested entries.", entryPath, entryType), + ) + } + + // 'operator' is always required for nested entries (only validate if not unknown) + if entry.Operator.IsNull() { + diags.AddError( + "Missing Required Field", + fmt.Sprintf("Nested entry requires 'operator' to be set at %s.", entryPath), + ) + } +} From 8770ac158036b08e76c96f53dcda8245d53a0fcc Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Tue, 25 Nov 2025 11:31:19 -0700 Subject: [PATCH 19/21] Add tests for schema validations --- .../security/exception_item/acc_test.go | 168 ++++++++++++++++++ .../exception_item.tf | 38 ++++ .../exception_item.tf | 42 +++++ .../exception_item.tf | 39 ++++ .../exception_item.tf | 42 +++++ .../exception_item.tf | 39 ++++ .../exception_item.tf | 39 ++++ .../exception_item.tf | 39 ++++ .../exception_item.tf | 39 ++++ .../exception_item.tf | 45 +++++ .../exception_item.tf | 45 +++++ .../exception_item.tf | 45 +++++ .../exception_item.tf | 38 ++++ .../exception_item.tf | 39 ++++ 14 files changed, 697 insertions(+) create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_exists_missing_operator/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_id/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_object/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_type/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_operator/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_values/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_operator/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_value/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_operator/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_value/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_invalid_entry_type/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_missing_entries/exception_item.tf create mode 100644 internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_wildcard_missing_value/exception_item.tf diff --git a/internal/kibana/security/exception_item/acc_test.go b/internal/kibana/security/exception_item/acc_test.go index 73a8ecdd4..76d0d1991 100644 --- a/internal/kibana/security/exception_item/acc_test.go +++ b/internal/kibana/security/exception_item/acc_test.go @@ -2,6 +2,7 @@ package exception_item_test import ( "fmt" + "regexp" "testing" "github.com/elastic/terraform-provider-elasticstack/internal/acctest" @@ -304,3 +305,170 @@ func TestAccResourceExceptionItemEntryType_Wildcard(t *testing.T) { }, }) } + +func TestAccResourceExceptionItemValidation(t *testing.T) { + listID := fmt.Sprintf("test-exception-list-validation-%s", uuid.New().String()[:8]) + itemID := fmt.Sprintf("test-exception-item-validation-%s", uuid.New().String()[:8]) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + Steps: []resource.TestStep{ + // Test 1: Match entry missing value + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_match_missing_value"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile("Entry type 'match' requires 'value' to be set"), + PlanOnly: true, + }, + // Test 2: Match entry missing operator + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_match_missing_operator"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile("Entry type 'match' requires 'operator' to be set"), + PlanOnly: true, + }, + // Test 3: Wildcard entry missing value + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_wildcard_missing_value"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile("Entry type 'wildcard' requires 'value' to be set"), + PlanOnly: true, + }, + // Test 4: MatchAny entry missing values + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_match_any_missing_values"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile("Entry type 'match_any' requires 'values' to be set"), + PlanOnly: true, + }, + // Test 5: MatchAny entry missing operator + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_match_any_missing_operator"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile("Entry type 'match_any' requires 'operator' to be set"), + PlanOnly: true, + }, + // Test 6: List entry missing list object + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_list_missing_list_object"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile("Entry type 'list' requires 'list' object to be set"), + PlanOnly: true, + }, + // Test 7: List entry missing list.id + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_list_missing_list_id"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile(`attribute "id" is required`), + PlanOnly: true, + }, + // Test 8: List entry missing list.type + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_list_missing_list_type"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile(`attribute "type" is required`), + PlanOnly: true, + }, + // Test 9: Exists entry missing operator + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_exists_missing_operator"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile("Entry type 'exists' requires 'operator' to be set"), + PlanOnly: true, + }, + // Test 10: Nested entry missing entries + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_nested_missing_entries"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile("Entry type 'nested' requires 'entries' to be set"), + PlanOnly: true, + }, + // Test 11: Nested entry with invalid entry type + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_nested_invalid_entry_type"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile(`(Nested entry .* has invalid type|value must be one of:.*"match".*"match_any".*"exists")`), + PlanOnly: true, + }, + // Test 12: Nested match entry missing value + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_nested_entry_missing_value"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile("Nested entry type 'match' requires 'value' to be set"), + PlanOnly: true, + }, + // Test 13: Nested entry missing operator + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minExceptionItemAPISupport), + ProtoV6ProviderFactories: acctest.Providers, + ConfigDirectory: acctest.NamedTestCaseDirectory("validation_nested_entry_missing_operator"), + ConfigVariables: config.Variables{ + "list_id": config.StringVariable(listID), + "item_id": config.StringVariable(itemID), + }, + ExpectError: regexp.MustCompile(`(Nested entry requires 'operator' to be set|attribute "operator" is required)`), + PlanOnly: true, + }, + }, + }) +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_exists_missing_operator/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_exists_missing_operator/exception_item.tf new file mode 100644 index 000000000..7567268fc --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_exists_missing_operator/exception_item.tf @@ -0,0 +1,38 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Exists Missing Operator" + description = "Test validation: exists entry without operator" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "exists" + field = "file.hash.sha256" + # Missing operator - should trigger validation error + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_id/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_id/exception_item.tf new file mode 100644 index 000000000..f7e0e0f0d --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_id/exception_item.tf @@ -0,0 +1,42 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - List Missing List ID" + description = "Test validation: list entry without list.id" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "list" + field = "source.ip" + operator = "included" + list = { + type = "ip" + # Missing id - should trigger validation error + } + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_object/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_object/exception_item.tf new file mode 100644 index 000000000..009f9397d --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_object/exception_item.tf @@ -0,0 +1,39 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - List Missing List Object" + description = "Test validation: list entry without list object" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "list" + field = "source.ip" + operator = "included" + # Missing list object - should trigger validation error + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_type/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_type/exception_item.tf new file mode 100644 index 000000000..4e5b32275 --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_type/exception_item.tf @@ -0,0 +1,42 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - List Missing List Type" + description = "Test validation: list entry without list.type" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "list" + field = "source.ip" + operator = "included" + list = { + id = "test-value-list" + # Missing type - should trigger validation error + } + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_operator/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_operator/exception_item.tf new file mode 100644 index 000000000..268dc730f --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_operator/exception_item.tf @@ -0,0 +1,39 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - MatchAny Missing Operator" + description = "Test validation: match_any entry without operator" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "match_any" + field = "process.name" + values = ["process1", "process2"] + # Missing operator - should trigger validation error + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_values/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_values/exception_item.tf new file mode 100644 index 000000000..1b9618eb4 --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_values/exception_item.tf @@ -0,0 +1,39 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - MatchAny Missing Values" + description = "Test validation: match_any entry without values" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "match_any" + field = "process.name" + operator = "included" + # Missing values - should trigger validation error + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_operator/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_operator/exception_item.tf new file mode 100644 index 000000000..f7ffd3fde --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_operator/exception_item.tf @@ -0,0 +1,39 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Match Missing Operator" + description = "Test validation: match entry without operator" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "match" + field = "process.name" + value = "test-process" + # Missing operator - should trigger validation error + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_value/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_value/exception_item.tf new file mode 100644 index 000000000..e21b8daae --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_value/exception_item.tf @@ -0,0 +1,39 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Match Missing Value" + description = "Test validation: match entry without value" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "match" + field = "process.name" + operator = "included" + # Missing value - should trigger validation error + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_operator/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_operator/exception_item.tf new file mode 100644 index 000000000..0408f440c --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_operator/exception_item.tf @@ -0,0 +1,45 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Nested Entry Missing Operator" + description = "Test validation: nested match entry without operator" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "nested" + field = "parent.field" + entries = [ + { + type = "match" + field = "nested.field" + value = "test-value" + # Missing operator - should trigger validation error + } + ] + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_value/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_value/exception_item.tf new file mode 100644 index 000000000..0a293ec6c --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_value/exception_item.tf @@ -0,0 +1,45 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Nested Entry Missing Value" + description = "Test validation: nested match entry without value" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "nested" + field = "parent.field" + entries = [ + { + type = "match" + field = "nested.field" + operator = "included" + # Missing value - should trigger validation error + } + ] + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_invalid_entry_type/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_invalid_entry_type/exception_item.tf new file mode 100644 index 000000000..bcbbfaa94 --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_invalid_entry_type/exception_item.tf @@ -0,0 +1,45 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Nested Invalid Entry Type" + description = "Test validation: nested entry with invalid nested entry type (wildcard)" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "nested" + field = "parent.field" + entries = [ + { + type = "wildcard" + field = "nested.field" + operator = "included" + value = "test*" + } + ] + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_missing_entries/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_missing_entries/exception_item.tf new file mode 100644 index 000000000..ce02051eb --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_missing_entries/exception_item.tf @@ -0,0 +1,38 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Nested Missing Entries" + description = "Test validation: nested entry without entries" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "nested" + field = "parent.field" + # Missing entries - should trigger validation error + } + ] +} diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_wildcard_missing_value/exception_item.tf b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_wildcard_missing_value/exception_item.tf new file mode 100644 index 000000000..de6fc230d --- /dev/null +++ b/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_wildcard_missing_value/exception_item.tf @@ -0,0 +1,39 @@ +variable "list_id" { + description = "The exception list ID" + type = string +} + +variable "item_id" { + description = "The exception item ID" + type = string +} + +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_exception_list" "test" { + list_id = var.list_id + name = "Test Exception List" + description = "Test exception list for validation" + type = "detection" + namespace_type = "single" +} + +resource "elasticstack_kibana_security_exception_item" "test" { + list_id = elasticstack_kibana_security_exception_list.test.list_id + item_id = var.item_id + name = "Test Exception Item - Wildcard Missing Value" + description = "Test validation: wildcard entry without value" + type = "simple" + namespace_type = "single" + entries = [ + { + type = "wildcard" + field = "file.path" + operator = "included" + # Missing value - should trigger validation error + } + ] +} From c1bfe072ddca27c077102dcdcb5fb0b2c7953f6c Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Tue, 25 Nov 2025 11:47:22 -0700 Subject: [PATCH 20/21] Refactor to use separate directories instead of security/ --- internal/kibana/security_detection_rule/schema.go | 1 + .../exception_item => security_exception_item}/acc_test.go | 2 +- .../exception_item => security_exception_item}/create.go | 2 +- .../exception_item => security_exception_item}/delete.go | 2 +- .../exception_item => security_exception_item}/models.go | 2 +- .../exception_item => security_exception_item}/read.go | 2 +- .../resource-description.md | 0 .../exception_item => security_exception_item}/resource.go | 2 +- .../exception_item => security_exception_item}/schema.go | 2 +- .../TestAccResourceExceptionItem/create/exception_item.tf | 0 .../TestAccResourceExceptionItem/update/exception_item.tf | 0 .../exists/exception_item.tf | 0 .../list/exception_item.tf | 0 .../match/exception_item.tf | 0 .../match_any/exception_item.tf | 0 .../nested/exception_item.tf | 0 .../wildcard/exception_item.tf | 0 .../validation_exists_missing_operator/exception_item.tf | 0 .../validation_list_missing_list_id/exception_item.tf | 0 .../validation_list_missing_list_object/exception_item.tf | 0 .../validation_list_missing_list_type/exception_item.tf | 0 .../validation_match_any_missing_operator/exception_item.tf | 0 .../validation_match_any_missing_values/exception_item.tf | 0 .../validation_match_missing_operator/exception_item.tf | 0 .../validation_match_missing_value/exception_item.tf | 0 .../validation_nested_entry_missing_operator/exception_item.tf | 0 .../validation_nested_entry_missing_value/exception_item.tf | 0 .../validation_nested_invalid_entry_type/exception_item.tf | 0 .../validation_nested_missing_entries/exception_item.tf | 0 .../validation_wildcard_missing_value/exception_item.tf | 0 .../create/exception_item.tf | 0 .../update/exception_item.tf | 0 .../exception_item => security_exception_item}/update.go | 2 +- .../exception_item => security_exception_item}/validate.go | 2 +- .../exception_list => security_exception_list}/acc_test.go | 2 +- .../exception_list => security_exception_list}/create.go | 2 +- .../exception_list => security_exception_list}/delete.go | 2 +- .../exception_list => security_exception_list}/models.go | 2 +- .../exception_list => security_exception_list}/read.go | 2 +- .../resource-description.md | 0 .../exception_list => security_exception_list}/resource.go | 2 +- .../exception_list => security_exception_list}/schema.go | 2 +- .../TestAccResourceExceptionList/create/exception_list.tf | 0 .../TestAccResourceExceptionList/update/exception_list.tf | 0 .../create/exception_list.tf | 0 .../update/exception_list.tf | 0 .../exception_list => security_exception_list}/update.go | 2 +- internal/kibana/{security => }/security_list/acc_test.go | 2 +- internal/kibana/{security => }/security_list/create.go | 2 +- internal/kibana/{security => }/security_list/delete.go | 2 +- internal/kibana/{security => }/security_list/models.go | 2 +- internal/kibana/{security => }/security_list/read.go | 2 +- .../kibana/{security => }/security_list/resource-description.md | 0 internal/kibana/{security => }/security_list/resource.go | 2 +- internal/kibana/{security => }/security_list/schema.go | 2 +- .../testdata/TestAccResourceSecurityList/create/main.tf | 0 .../testdata/TestAccResourceSecurityList/update/main.tf | 0 .../keyword_type/main.tf | 0 internal/kibana/{security => }/security_list/update.go | 2 +- internal/kibana/{security => }/security_list_item/acc_test.go | 2 +- internal/kibana/{security => }/security_list_item/create.go | 2 +- internal/kibana/{security => }/security_list_item/delete.go | 2 +- internal/kibana/{security => }/security_list_item/models.go | 2 +- internal/kibana/{security => }/security_list_item/read.go | 2 +- .../{security => }/security_list_item/resource-description.md | 0 internal/kibana/{security => }/security_list_item/resource.go | 2 +- internal/kibana/{security => }/security_list_item/schema.go | 2 +- .../testdata/TestAccResourceSecurityListItem/create/main.tf | 0 .../testdata/TestAccResourceSecurityListItem/update/main.tf | 0 internal/kibana/{security => }/security_list_item/update.go | 2 +- 70 files changed, 34 insertions(+), 33 deletions(-) rename internal/kibana/{security/exception_item => security_exception_item}/acc_test.go (99%) rename internal/kibana/{security/exception_item => security_exception_item}/create.go (99%) rename internal/kibana/{security/exception_item => security_exception_item}/delete.go (96%) rename internal/kibana/{security/exception_item => security_exception_item}/models.go (99%) rename internal/kibana/{security/exception_item => security_exception_item}/read.go (97%) rename internal/kibana/{security/exception_item => security_exception_item}/resource-description.md (100%) rename internal/kibana/{security/exception_item => security_exception_item}/resource.go (97%) rename internal/kibana/{security/exception_item => security_exception_item}/schema.go (99%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItem/create/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItem/update/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemEntryType_Exists/exists/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemEntryType_Match/match/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemEntryType_MatchAny/match_any/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemEntryType_Wildcard/wildcard/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_exists_missing_operator/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_id/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_object/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_type/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_operator/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_values/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_operator/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_value/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_operator/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_value/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_nested_invalid_entry_type/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_nested_missing_entries/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemValidation/validation_wildcard_missing_value/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf (100%) rename internal/kibana/{security/exception_item => security_exception_item}/update.go (99%) rename internal/kibana/{security/exception_item => security_exception_item}/validate.go (99%) rename internal/kibana/{security/exception_list => security_exception_list}/acc_test.go (99%) rename internal/kibana/{security/exception_list => security_exception_list}/create.go (99%) rename internal/kibana/{security/exception_list => security_exception_list}/delete.go (96%) rename internal/kibana/{security/exception_list => security_exception_list}/models.go (96%) rename internal/kibana/{security/exception_list => security_exception_list}/read.go (97%) rename internal/kibana/{security/exception_list => security_exception_list}/resource-description.md (100%) rename internal/kibana/{security/exception_list => security_exception_list}/resource.go (97%) rename internal/kibana/{security/exception_list => security_exception_list}/schema.go (99%) rename internal/kibana/{security/exception_list => security_exception_list}/testdata/TestAccResourceExceptionList/create/exception_list.tf (100%) rename internal/kibana/{security/exception_list => security_exception_list}/testdata/TestAccResourceExceptionList/update/exception_list.tf (100%) rename internal/kibana/{security/exception_list => security_exception_list}/testdata/TestAccResourceExceptionListWithSpace/create/exception_list.tf (100%) rename internal/kibana/{security/exception_list => security_exception_list}/testdata/TestAccResourceExceptionListWithSpace/update/exception_list.tf (100%) rename internal/kibana/{security/exception_list => security_exception_list}/update.go (99%) rename internal/kibana/{security => }/security_list/acc_test.go (99%) rename internal/kibana/{security => }/security_list/create.go (98%) rename internal/kibana/{security => }/security_list/delete.go (97%) rename internal/kibana/{security => }/security_list/models.go (99%) rename internal/kibana/{security => }/security_list/read.go (98%) rename internal/kibana/{security => }/security_list/resource-description.md (100%) rename internal/kibana/{security => }/security_list/resource.go (98%) rename internal/kibana/{security => }/security_list/schema.go (99%) rename internal/kibana/{security => }/security_list/testdata/TestAccResourceSecurityList/create/main.tf (100%) rename internal/kibana/{security => }/security_list/testdata/TestAccResourceSecurityList/update/main.tf (100%) rename internal/kibana/{security => }/security_list/testdata/TestAccResourceSecurityList_KeywordType/keyword_type/main.tf (100%) rename internal/kibana/{security => }/security_list/update.go (98%) rename internal/kibana/{security => }/security_list_item/acc_test.go (98%) rename internal/kibana/{security => }/security_list_item/create.go (98%) rename internal/kibana/{security => }/security_list_item/delete.go (97%) rename internal/kibana/{security => }/security_list_item/models.go (99%) rename internal/kibana/{security => }/security_list_item/read.go (98%) rename internal/kibana/{security => }/security_list_item/resource-description.md (100%) rename internal/kibana/{security => }/security_list_item/resource.go (97%) rename internal/kibana/{security => }/security_list_item/schema.go (99%) rename internal/kibana/{security => }/security_list_item/testdata/TestAccResourceSecurityListItem/create/main.tf (100%) rename internal/kibana/{security => }/security_list_item/testdata/TestAccResourceSecurityListItem/update/main.tf (100%) rename internal/kibana/{security => }/security_list_item/update.go (98%) diff --git a/internal/kibana/security_detection_rule/schema.go b/internal/kibana/security_detection_rule/schema.go index 0dab25047..8ea3c75b9 100644 --- a/internal/kibana/security_detection_rule/schema.go +++ b/internal/kibana/security_detection_rule/schema.go @@ -970,6 +970,7 @@ func (r securityDetectionRuleResource) ValidateConfig(ctx context.Context, req r } + // TODO unknown is allowed if we are referencing values that are not yet known if !utils.IsKnown(data.Index) && !utils.IsKnown(data.DataViewId) { resp.Diagnostics.AddError( "Invalid Configuration", diff --git a/internal/kibana/security/exception_item/acc_test.go b/internal/kibana/security_exception_item/acc_test.go similarity index 99% rename from internal/kibana/security/exception_item/acc_test.go rename to internal/kibana/security_exception_item/acc_test.go index 76d0d1991..d5ad643ac 100644 --- a/internal/kibana/security/exception_item/acc_test.go +++ b/internal/kibana/security_exception_item/acc_test.go @@ -1,4 +1,4 @@ -package exception_item_test +package security_exception_item_test import ( "fmt" diff --git a/internal/kibana/security/exception_item/create.go b/internal/kibana/security_exception_item/create.go similarity index 99% rename from internal/kibana/security/exception_item/create.go rename to internal/kibana/security_exception_item/create.go index 5a704cca6..d826f2732 100644 --- a/internal/kibana/security/exception_item/create.go +++ b/internal/kibana/security_exception_item/create.go @@ -1,4 +1,4 @@ -package exception_item +package security_exception_item import ( "context" diff --git a/internal/kibana/security/exception_item/delete.go b/internal/kibana/security_exception_item/delete.go similarity index 96% rename from internal/kibana/security/exception_item/delete.go rename to internal/kibana/security_exception_item/delete.go index de2148bd3..3b834b756 100644 --- a/internal/kibana/security/exception_item/delete.go +++ b/internal/kibana/security_exception_item/delete.go @@ -1,4 +1,4 @@ -package exception_item +package security_exception_item import ( "context" diff --git a/internal/kibana/security/exception_item/models.go b/internal/kibana/security_exception_item/models.go similarity index 99% rename from internal/kibana/security/exception_item/models.go rename to internal/kibana/security_exception_item/models.go index 05758f60f..5e4ab2499 100644 --- a/internal/kibana/security/exception_item/models.go +++ b/internal/kibana/security_exception_item/models.go @@ -1,4 +1,4 @@ -package exception_item +package security_exception_item import ( "context" diff --git a/internal/kibana/security/exception_item/read.go b/internal/kibana/security_exception_item/read.go similarity index 97% rename from internal/kibana/security/exception_item/read.go rename to internal/kibana/security_exception_item/read.go index 63c534fdf..2f2b24880 100644 --- a/internal/kibana/security/exception_item/read.go +++ b/internal/kibana/security_exception_item/read.go @@ -1,4 +1,4 @@ -package exception_item +package security_exception_item import ( "context" diff --git a/internal/kibana/security/exception_item/resource-description.md b/internal/kibana/security_exception_item/resource-description.md similarity index 100% rename from internal/kibana/security/exception_item/resource-description.md rename to internal/kibana/security_exception_item/resource-description.md diff --git a/internal/kibana/security/exception_item/resource.go b/internal/kibana/security_exception_item/resource.go similarity index 97% rename from internal/kibana/security/exception_item/resource.go rename to internal/kibana/security_exception_item/resource.go index 247fdbddc..c03b7f15e 100644 --- a/internal/kibana/security/exception_item/resource.go +++ b/internal/kibana/security_exception_item/resource.go @@ -1,4 +1,4 @@ -package exception_item +package security_exception_item import ( "context" diff --git a/internal/kibana/security/exception_item/schema.go b/internal/kibana/security_exception_item/schema.go similarity index 99% rename from internal/kibana/security/exception_item/schema.go rename to internal/kibana/security_exception_item/schema.go index a2651d1a4..86d5d81e0 100644 --- a/internal/kibana/security/exception_item/schema.go +++ b/internal/kibana/security_exception_item/schema.go @@ -1,4 +1,4 @@ -package exception_item +package security_exception_item import ( "context" diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItem/create/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItem/update/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Exists/exists/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_Exists/exists/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Exists/exists/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_Exists/exists/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_List/list/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Match/match/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_Match/match/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Match/match/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_Match/match/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_MatchAny/match_any/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_MatchAny/match_any/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_MatchAny/match_any/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_MatchAny/match_any/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_Nested/nested/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Wildcard/wildcard/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_Wildcard/wildcard/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemEntryType_Wildcard/wildcard/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemEntryType_Wildcard/wildcard/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_exists_missing_operator/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_exists_missing_operator/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_exists_missing_operator/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_exists_missing_operator/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_id/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_id/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_id/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_id/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_object/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_object/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_object/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_object/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_type/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_type/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_type/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_list_missing_list_type/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_operator/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_operator/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_operator/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_operator/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_values/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_values/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_values/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_any_missing_values/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_operator/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_operator/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_operator/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_operator/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_value/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_value/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_value/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_match_missing_value/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_operator/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_operator/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_operator/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_operator/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_value/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_value/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_value/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_entry_missing_value/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_invalid_entry_type/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_invalid_entry_type/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_invalid_entry_type/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_invalid_entry_type/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_missing_entries/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_missing_entries/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_missing_entries/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_nested_missing_entries/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_wildcard_missing_value/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_wildcard_missing_value/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemValidation/validation_wildcard_missing_value/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemValidation/validation_wildcard_missing_value/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemWithSpace/create/exception_item.tf diff --git a/internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf b/internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf similarity index 100% rename from internal/kibana/security/exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf rename to internal/kibana/security_exception_item/testdata/TestAccResourceExceptionItemWithSpace/update/exception_item.tf diff --git a/internal/kibana/security/exception_item/update.go b/internal/kibana/security_exception_item/update.go similarity index 99% rename from internal/kibana/security/exception_item/update.go rename to internal/kibana/security_exception_item/update.go index f57ff75c3..abebae6c2 100644 --- a/internal/kibana/security/exception_item/update.go +++ b/internal/kibana/security_exception_item/update.go @@ -1,4 +1,4 @@ -package exception_item +package security_exception_item import ( "context" diff --git a/internal/kibana/security/exception_item/validate.go b/internal/kibana/security_exception_item/validate.go similarity index 99% rename from internal/kibana/security/exception_item/validate.go rename to internal/kibana/security_exception_item/validate.go index cfda8e467..77d060e6a 100644 --- a/internal/kibana/security/exception_item/validate.go +++ b/internal/kibana/security_exception_item/validate.go @@ -1,4 +1,4 @@ -package exception_item +package security_exception_item import ( "context" diff --git a/internal/kibana/security/exception_list/acc_test.go b/internal/kibana/security_exception_list/acc_test.go similarity index 99% rename from internal/kibana/security/exception_list/acc_test.go rename to internal/kibana/security_exception_list/acc_test.go index 0c57cc100..89059330d 100644 --- a/internal/kibana/security/exception_list/acc_test.go +++ b/internal/kibana/security_exception_list/acc_test.go @@ -1,4 +1,4 @@ -package exception_list_test +package security_exception_list_test import ( "fmt" diff --git a/internal/kibana/security/exception_list/create.go b/internal/kibana/security_exception_list/create.go similarity index 99% rename from internal/kibana/security/exception_list/create.go rename to internal/kibana/security_exception_list/create.go index c1e5d6b6f..93a34a38c 100644 --- a/internal/kibana/security/exception_list/create.go +++ b/internal/kibana/security_exception_list/create.go @@ -1,4 +1,4 @@ -package exception_list +package security_exception_list import ( "context" diff --git a/internal/kibana/security/exception_list/delete.go b/internal/kibana/security_exception_list/delete.go similarity index 96% rename from internal/kibana/security/exception_list/delete.go rename to internal/kibana/security_exception_list/delete.go index 8ff642223..0c2b34b96 100644 --- a/internal/kibana/security/exception_list/delete.go +++ b/internal/kibana/security_exception_list/delete.go @@ -1,4 +1,4 @@ -package exception_list +package security_exception_list import ( "context" diff --git a/internal/kibana/security/exception_list/models.go b/internal/kibana/security_exception_list/models.go similarity index 96% rename from internal/kibana/security/exception_list/models.go rename to internal/kibana/security_exception_list/models.go index 29bb77ff2..5e97aa9f9 100644 --- a/internal/kibana/security/exception_list/models.go +++ b/internal/kibana/security_exception_list/models.go @@ -1,4 +1,4 @@ -package exception_list +package security_exception_list import ( "github.com/hashicorp/terraform-plugin-framework/types" diff --git a/internal/kibana/security/exception_list/read.go b/internal/kibana/security_exception_list/read.go similarity index 97% rename from internal/kibana/security/exception_list/read.go rename to internal/kibana/security_exception_list/read.go index b44386b17..1ace40cb5 100644 --- a/internal/kibana/security/exception_list/read.go +++ b/internal/kibana/security_exception_list/read.go @@ -1,4 +1,4 @@ -package exception_list +package security_exception_list import ( "context" diff --git a/internal/kibana/security/exception_list/resource-description.md b/internal/kibana/security_exception_list/resource-description.md similarity index 100% rename from internal/kibana/security/exception_list/resource-description.md rename to internal/kibana/security_exception_list/resource-description.md diff --git a/internal/kibana/security/exception_list/resource.go b/internal/kibana/security_exception_list/resource.go similarity index 97% rename from internal/kibana/security/exception_list/resource.go rename to internal/kibana/security_exception_list/resource.go index 2ed91ad91..03b5c3a71 100644 --- a/internal/kibana/security/exception_list/resource.go +++ b/internal/kibana/security_exception_list/resource.go @@ -1,4 +1,4 @@ -package exception_list +package security_exception_list import ( "context" diff --git a/internal/kibana/security/exception_list/schema.go b/internal/kibana/security_exception_list/schema.go similarity index 99% rename from internal/kibana/security/exception_list/schema.go rename to internal/kibana/security_exception_list/schema.go index 32121b7b3..8d1f934a6 100644 --- a/internal/kibana/security/exception_list/schema.go +++ b/internal/kibana/security_exception_list/schema.go @@ -1,4 +1,4 @@ -package exception_list +package security_exception_list import ( "context" diff --git a/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/create/exception_list.tf b/internal/kibana/security_exception_list/testdata/TestAccResourceExceptionList/create/exception_list.tf similarity index 100% rename from internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/create/exception_list.tf rename to internal/kibana/security_exception_list/testdata/TestAccResourceExceptionList/create/exception_list.tf diff --git a/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/update/exception_list.tf b/internal/kibana/security_exception_list/testdata/TestAccResourceExceptionList/update/exception_list.tf similarity index 100% rename from internal/kibana/security/exception_list/testdata/TestAccResourceExceptionList/update/exception_list.tf rename to internal/kibana/security_exception_list/testdata/TestAccResourceExceptionList/update/exception_list.tf diff --git a/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/create/exception_list.tf b/internal/kibana/security_exception_list/testdata/TestAccResourceExceptionListWithSpace/create/exception_list.tf similarity index 100% rename from internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/create/exception_list.tf rename to internal/kibana/security_exception_list/testdata/TestAccResourceExceptionListWithSpace/create/exception_list.tf diff --git a/internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/update/exception_list.tf b/internal/kibana/security_exception_list/testdata/TestAccResourceExceptionListWithSpace/update/exception_list.tf similarity index 100% rename from internal/kibana/security/exception_list/testdata/TestAccResourceExceptionListWithSpace/update/exception_list.tf rename to internal/kibana/security_exception_list/testdata/TestAccResourceExceptionListWithSpace/update/exception_list.tf diff --git a/internal/kibana/security/exception_list/update.go b/internal/kibana/security_exception_list/update.go similarity index 99% rename from internal/kibana/security/exception_list/update.go rename to internal/kibana/security_exception_list/update.go index 07a59269b..328e9c37f 100644 --- a/internal/kibana/security/exception_list/update.go +++ b/internal/kibana/security_exception_list/update.go @@ -1,4 +1,4 @@ -package exception_list +package security_exception_list import ( "context" diff --git a/internal/kibana/security/security_list/acc_test.go b/internal/kibana/security_list/acc_test.go similarity index 99% rename from internal/kibana/security/security_list/acc_test.go rename to internal/kibana/security_list/acc_test.go index c70472b88..e9dc7c1d7 100644 --- a/internal/kibana/security/security_list/acc_test.go +++ b/internal/kibana/security_list/acc_test.go @@ -1,4 +1,4 @@ -package securitylist_test +package security_list_test import ( "context" diff --git a/internal/kibana/security/security_list/create.go b/internal/kibana/security_list/create.go similarity index 98% rename from internal/kibana/security/security_list/create.go rename to internal/kibana/security_list/create.go index 03a035097..969e09567 100644 --- a/internal/kibana/security/security_list/create.go +++ b/internal/kibana/security_list/create.go @@ -1,4 +1,4 @@ -package securitylist +package security_list import ( "context" diff --git a/internal/kibana/security/security_list/delete.go b/internal/kibana/security_list/delete.go similarity index 97% rename from internal/kibana/security/security_list/delete.go rename to internal/kibana/security_list/delete.go index 327d7b276..a532b38f3 100644 --- a/internal/kibana/security/security_list/delete.go +++ b/internal/kibana/security_list/delete.go @@ -1,4 +1,4 @@ -package securitylist +package security_list import ( "context" diff --git a/internal/kibana/security/security_list/models.go b/internal/kibana/security_list/models.go similarity index 99% rename from internal/kibana/security/security_list/models.go rename to internal/kibana/security_list/models.go index 98489c692..f2524bd3c 100644 --- a/internal/kibana/security/security_list/models.go +++ b/internal/kibana/security_list/models.go @@ -1,4 +1,4 @@ -package securitylist +package security_list import ( "context" diff --git a/internal/kibana/security/security_list/read.go b/internal/kibana/security_list/read.go similarity index 98% rename from internal/kibana/security/security_list/read.go rename to internal/kibana/security_list/read.go index c16d2815e..b5027401e 100644 --- a/internal/kibana/security/security_list/read.go +++ b/internal/kibana/security_list/read.go @@ -1,4 +1,4 @@ -package securitylist +package security_list import ( "context" diff --git a/internal/kibana/security/security_list/resource-description.md b/internal/kibana/security_list/resource-description.md similarity index 100% rename from internal/kibana/security/security_list/resource-description.md rename to internal/kibana/security_list/resource-description.md diff --git a/internal/kibana/security/security_list/resource.go b/internal/kibana/security_list/resource.go similarity index 98% rename from internal/kibana/security/security_list/resource.go rename to internal/kibana/security_list/resource.go index ce1678457..51d6ad1a6 100644 --- a/internal/kibana/security/security_list/resource.go +++ b/internal/kibana/security_list/resource.go @@ -1,4 +1,4 @@ -package securitylist +package security_list import ( "context" diff --git a/internal/kibana/security/security_list/schema.go b/internal/kibana/security_list/schema.go similarity index 99% rename from internal/kibana/security/security_list/schema.go rename to internal/kibana/security_list/schema.go index 88102f489..318dd87d8 100644 --- a/internal/kibana/security/security_list/schema.go +++ b/internal/kibana/security_list/schema.go @@ -1,4 +1,4 @@ -package securitylist +package security_list import ( "context" diff --git a/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/create/main.tf b/internal/kibana/security_list/testdata/TestAccResourceSecurityList/create/main.tf similarity index 100% rename from internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/create/main.tf rename to internal/kibana/security_list/testdata/TestAccResourceSecurityList/create/main.tf diff --git a/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/update/main.tf b/internal/kibana/security_list/testdata/TestAccResourceSecurityList/update/main.tf similarity index 100% rename from internal/kibana/security/security_list/testdata/TestAccResourceSecurityList/update/main.tf rename to internal/kibana/security_list/testdata/TestAccResourceSecurityList/update/main.tf diff --git a/internal/kibana/security/security_list/testdata/TestAccResourceSecurityList_KeywordType/keyword_type/main.tf b/internal/kibana/security_list/testdata/TestAccResourceSecurityList_KeywordType/keyword_type/main.tf similarity index 100% rename from internal/kibana/security/security_list/testdata/TestAccResourceSecurityList_KeywordType/keyword_type/main.tf rename to internal/kibana/security_list/testdata/TestAccResourceSecurityList_KeywordType/keyword_type/main.tf diff --git a/internal/kibana/security/security_list/update.go b/internal/kibana/security_list/update.go similarity index 98% rename from internal/kibana/security/security_list/update.go rename to internal/kibana/security_list/update.go index b0681ff35..d545d92da 100644 --- a/internal/kibana/security/security_list/update.go +++ b/internal/kibana/security_list/update.go @@ -1,4 +1,4 @@ -package securitylist +package security_list import ( "context" diff --git a/internal/kibana/security/security_list_item/acc_test.go b/internal/kibana/security_list_item/acc_test.go similarity index 98% rename from internal/kibana/security/security_list_item/acc_test.go rename to internal/kibana/security_list_item/acc_test.go index 859c90fd7..34168a453 100644 --- a/internal/kibana/security/security_list_item/acc_test.go +++ b/internal/kibana/security_list_item/acc_test.go @@ -1,4 +1,4 @@ -package securitylistitem_test +package security_list_item_test import ( "context" diff --git a/internal/kibana/security/security_list_item/create.go b/internal/kibana/security_list_item/create.go similarity index 98% rename from internal/kibana/security/security_list_item/create.go rename to internal/kibana/security_list_item/create.go index 654ae25af..59dc7a1e6 100644 --- a/internal/kibana/security/security_list_item/create.go +++ b/internal/kibana/security_list_item/create.go @@ -1,4 +1,4 @@ -package securitylistitem +package security_list_item import ( "context" diff --git a/internal/kibana/security/security_list_item/delete.go b/internal/kibana/security_list_item/delete.go similarity index 97% rename from internal/kibana/security/security_list_item/delete.go rename to internal/kibana/security_list_item/delete.go index 1600c94af..3feafbb54 100644 --- a/internal/kibana/security/security_list_item/delete.go +++ b/internal/kibana/security_list_item/delete.go @@ -1,4 +1,4 @@ -package securitylistitem +package security_list_item import ( "context" diff --git a/internal/kibana/security/security_list_item/models.go b/internal/kibana/security_list_item/models.go similarity index 99% rename from internal/kibana/security/security_list_item/models.go rename to internal/kibana/security_list_item/models.go index 84f1f2b04..cf2438f2b 100644 --- a/internal/kibana/security/security_list_item/models.go +++ b/internal/kibana/security_list_item/models.go @@ -1,4 +1,4 @@ -package securitylistitem +package security_list_item import ( "context" diff --git a/internal/kibana/security/security_list_item/read.go b/internal/kibana/security_list_item/read.go similarity index 98% rename from internal/kibana/security/security_list_item/read.go rename to internal/kibana/security_list_item/read.go index 7bad0296a..498b9ee04 100644 --- a/internal/kibana/security/security_list_item/read.go +++ b/internal/kibana/security_list_item/read.go @@ -1,4 +1,4 @@ -package securitylistitem +package security_list_item import ( "context" diff --git a/internal/kibana/security/security_list_item/resource-description.md b/internal/kibana/security_list_item/resource-description.md similarity index 100% rename from internal/kibana/security/security_list_item/resource-description.md rename to internal/kibana/security_list_item/resource-description.md diff --git a/internal/kibana/security/security_list_item/resource.go b/internal/kibana/security_list_item/resource.go similarity index 97% rename from internal/kibana/security/security_list_item/resource.go rename to internal/kibana/security_list_item/resource.go index 1148cb862..0f9402be3 100644 --- a/internal/kibana/security/security_list_item/resource.go +++ b/internal/kibana/security_list_item/resource.go @@ -1,4 +1,4 @@ -package securitylistitem +package security_list_item import ( "context" diff --git a/internal/kibana/security/security_list_item/schema.go b/internal/kibana/security_list_item/schema.go similarity index 99% rename from internal/kibana/security/security_list_item/schema.go rename to internal/kibana/security_list_item/schema.go index e790fa2bf..3315e715f 100644 --- a/internal/kibana/security/security_list_item/schema.go +++ b/internal/kibana/security_list_item/schema.go @@ -1,4 +1,4 @@ -package securitylistitem +package security_list_item import ( "context" diff --git a/internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/create/main.tf b/internal/kibana/security_list_item/testdata/TestAccResourceSecurityListItem/create/main.tf similarity index 100% rename from internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/create/main.tf rename to internal/kibana/security_list_item/testdata/TestAccResourceSecurityListItem/create/main.tf diff --git a/internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/update/main.tf b/internal/kibana/security_list_item/testdata/TestAccResourceSecurityListItem/update/main.tf similarity index 100% rename from internal/kibana/security/security_list_item/testdata/TestAccResourceSecurityListItem/update/main.tf rename to internal/kibana/security_list_item/testdata/TestAccResourceSecurityListItem/update/main.tf diff --git a/internal/kibana/security/security_list_item/update.go b/internal/kibana/security_list_item/update.go similarity index 98% rename from internal/kibana/security/security_list_item/update.go rename to internal/kibana/security_list_item/update.go index bfd362f38..b8d6cbf62 100644 --- a/internal/kibana/security/security_list_item/update.go +++ b/internal/kibana/security_list_item/update.go @@ -1,4 +1,4 @@ -package securitylistitem +package security_list_item import ( "context" From 99187408651c9354340d63c7fd11a49a3126fd9e Mon Sep 17 00:00:00 2001 From: Nick Benoit Date: Tue, 25 Nov 2025 11:48:11 -0700 Subject: [PATCH 21/21] Update provider --- provider/plugin_framework.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/provider/plugin_framework.go b/provider/plugin_framework.go index f3068d86c..b24562863 100644 --- a/provider/plugin_framework.go +++ b/provider/plugin_framework.go @@ -30,11 +30,11 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/kibana/export_saved_objects" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/import_saved_objects" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/maintenance_window" - "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/exception_item" - "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/exception_list" - securitylist "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/security_list" - securitylistitem "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security/security_list_item" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security_detection_rule" + "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security_exception_item" + "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security_exception_list" + "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security_list" + "github.com/elastic/terraform-provider-elasticstack/internal/kibana/security_list_item" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/spaces" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/synthetics/monitor" "github.com/elastic/terraform-provider-elasticstack/internal/kibana/synthetics/parameter" @@ -132,10 +132,10 @@ func (p *Provider) Resources(ctx context.Context) []func() resource.Resource { datafeed.NewDatafeedResource, anomaly_detection_job.NewAnomalyDetectionJobResource, security_detection_rule.NewSecurityDetectionRuleResource, - exception_list.NewResource, - exception_item.NewResource, - securitylist.NewResource, - securitylistitem.NewResource, + security_exception_list.NewResource, + security_exception_item.NewResource, + security_list.NewResource, + security_list_item.NewResource, job_state.NewMLJobStateResource, datafeed_state.NewMLDatafeedStateResource, }