Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
350 changes: 316 additions & 34 deletions generated/kbapi/kibana.gen.go

Large diffs are not rendered by default.

50 changes: 35 additions & 15 deletions generated/kbapi/transform_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"strconv"
"strings"

"github.com/google/go-cmp/cmp"
"gopkg.in/yaml.v3"
)

Expand Down Expand Up @@ -348,7 +349,11 @@ func (m Map) CreateRef(schema *Schema, name string, key string) Map {
if reflect.DeepEqual(refTarget, existing) {
writeComponent = false
} else {
log.Panicf("Component schema key already in use and not an exact duplicate: %q", refPath)
log.Panicf(
"Component schema key already in use and not an exact duplicate: %q\n\n%s",
refPath,
cmp.Diff(existing, refTarget),
)
return nil
}
}
Expand Down Expand Up @@ -1108,31 +1113,46 @@ func transformFleetPaths(schema *Schema) {
epmPoliciesPath.Get.CreateRef(schema, "package_policy", "responses.200.content.application/json.schema.properties.items.items")
epmPoliciesPath.Post.CreateRef(schema, "package_policy", "responses.200.content.application/json.schema.properties.item")

epmPoliciesPath.Post.Move("requestBody.content.application/json.schema.anyOf.1", "requestBody.content.application/json.schema") // anyOf.0 is the deprecated array format
epmPolicyPath.Put.Move("requestBody.content.application/json.schema.anyOf.1", "requestBody.content.application/json.schema") // anyOf.0 is the deprecated array format
epmPoliciesPath.Post.CreateRef(schema, "package_policy_request", "requestBody.content.application/json.schema")
epmPolicyPath.Put.CreateRef(schema, "package_policy_request_typed_inputs", "requestBody.content.application/json.schema.anyOf.0")
epmPolicyPath.Put.CreateRef(schema, "package_policy_request_mapped_inputs", "requestBody.content.application/json.schema.anyOf.1")
epmPolicyPath.Put.CreateRef(schema, "package_policy_request", "requestBody.content.application/json.schema")

epmPoliciesPath.Post.Set("requestBody.content.application/json.schema", epmPolicyPath.Put.MustGetMap("requestBody.content.application/json.schema"))

epmPolicyPath.Get.CreateRef(schema, "package_policy", "responses.200.content.application/json.schema.properties.item")
epmPolicyPath.Put.CreateRef(schema, "package_policy", "responses.200.content.application/json.schema.properties.item")

schema.Components.CreateRef(schema, "package_policy_secret_ref", "schemas.package_policy.properties.secret_references.items")
schema.Components.Move("schemas.package_policy.properties.inputs.anyOf.1", "schemas.package_policy.properties.inputs") // anyOf.0 is the deprecated array format
schema.Components.CreateRef(schema, "package_policy_typed_inputs", "schemas.package_policy.properties.inputs.anyOf.0")
schema.Components.CreateRef(schema, "package_policy_mapped_inputs", "schemas.package_policy.properties.inputs.anyOf.1")
schema.Components.CreateRef(schema, "package_policy_typed_input", "schemas.package_policy_typed_inputs.items")
schema.Components.CreateRef(schema, "package_policy_mapped_input", "schemas.package_policy_mapped_inputs.additionalProperties")
schema.Components.CreateRef(schema, "package_policy_typed_input_stream", "schemas.package_policy_typed_input.properties.streams.items")
schema.Components.CreateRef(schema, "package_policy_mapped_input_stream", "schemas.package_policy_mapped_input.properties.streams.additionalProperties")

schema.Components.CreateRef(schema, "package_policy_request_package", "schemas.package_policy_request_mapped_inputs.properties.package")
schema.Components.CreateRef(schema, "package_policy_request_package", "schemas.package_policy_request_typed_inputs.properties.package")

schema.Components.CreateRef(schema, "package_policy_input", "schemas.package_policy.properties.inputs.additionalProperties")
schema.Components.CreateRef(schema, "package_policy_input_stream", "schemas.package_policy_input.properties.streams.additionalProperties")
schema.Components.CreateRef(schema, "package_policy_request_mapped_input", "schemas.package_policy_request_mapped_inputs.properties.inputs.additionalProperties")
schema.Components.CreateRef(schema, "package_policy_request_mapped_input_stream", "schemas.package_policy_request_mapped_input.properties.streams.additionalProperties")

schema.Components.CreateRef(schema, "package_policy_request_package", "schemas.package_policy_request.properties.package")
schema.Components.CreateRef(schema, "package_policy_request_input", "schemas.package_policy_request.properties.inputs.additionalProperties")
schema.Components.CreateRef(schema, "package_policy_request_input_stream", "schemas.package_policy_request_input.properties.streams.additionalProperties")
schema.Components.CreateRef(schema, "package_policy_request_typed_input", "schemas.package_policy_request_typed_inputs.properties.inputs.items")
schema.Components.CreateRef(schema, "package_policy_request_typed_input_stream", "schemas.package_policy_request_typed_input.properties.streams.items")

// Simplify all of the vars
schema.Components.Set("schemas.package_policy.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_input.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_input_stream.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request_input.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request_input_stream.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_typed_input.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_mapped_input.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_typed_input_stream.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_mapped_input_stream.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request_mapped_inputs.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request_mapped_input.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request_mapped_input_stream.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request_typed_inputs.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request_typed_input.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request_typed_input.properties.config", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request_typed_input_stream.properties.vars", Map{"type": "object"})
schema.Components.Set("schemas.package_policy_request_typed_input_stream.properties.config", Map{"type": "object"})
}

func setAllXOmitEmpty(key string, node Map) {
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/disaster37/go-kibana-rest/v8 v8.5.0
github.com/elastic/elastic-transport-go/v8 v8.8.0
github.com/elastic/go-elasticsearch/v8 v8.19.0
github.com/google/go-cmp v0.7.0
github.com/google/gofuzz v1.2.0
github.com/google/uuid v1.6.0
github.com/hashicorp/go-cty v1.5.0
Expand All @@ -25,6 +26,7 @@ require (
github.com/oapi-codegen/runtime v1.1.2
github.com/stretchr/testify v1.11.1
go.uber.org/mock v0.6.0
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand Down Expand Up @@ -205,7 +207,6 @@ require (
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/certificate-transparency-go v1.3.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-containerregistry v0.20.6 // indirect
github.com/google/go-github/v74 v74.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
Expand Down Expand Up @@ -409,7 +410,6 @@ require (
gopkg.in/mail.v2 v2.3.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/gotestsum v1.13.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
lukechampine.com/blake3 v1.2.1 // indirect
Expand Down
35 changes: 26 additions & 9 deletions internal/fleet/integration_policy/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,20 @@ func (model *integrationPolicyModel) populateFromAPI(ctx context.Context, data *
model.SpaceIds = types.SetNull(types.StringType)
}
// If originally set but API didn't return it, keep the original value

model.populateInputFromAPI(ctx, data.Inputs, &diags)
mappedInputs, err := data.Inputs.AsPackagePolicyMappedInputs()
if err != nil {
diags.AddError(
"Error reading integration policy inputs",
"Could not parse integration policy inputs from API response: "+err.Error(),
)
return diags
}
model.populateInputFromAPI(ctx, mappedInputs, &diags)

return diags
}

func (model *integrationPolicyModel) populateInputFromAPI(ctx context.Context, inputs map[string]kbapi.PackagePolicyInput, diags *diag.Diagnostics) {
func (model *integrationPolicyModel) populateInputFromAPI(ctx context.Context, inputs map[string]kbapi.PackagePolicyMappedInput, diags *diag.Diagnostics) {
// Handle input population based on context:
// 1. If model.Input is unknown: we're importing or reading fresh state → populate from API
// 2. If model.Input is known and null/empty: user explicitly didn't configure inputs → don't populate (avoid inconsistent state)
Expand All @@ -135,7 +142,7 @@ func (model *integrationPolicyModel) populateInputFromAPI(ctx context.Context, i
// Case 3: Known and not null/empty - user configured inputs, populate from API (continue below)

newInputs := utils.TransformMapToSlice(ctx, inputs, path.Root("input"), diags,
func(inputData kbapi.PackagePolicyInput, meta utils.MapMeta) integrationPolicyInputModel {
func(inputData kbapi.PackagePolicyMappedInput, meta utils.MapMeta) integrationPolicyInputModel {
return integrationPolicyInputModel{
InputID: types.StringValue(meta.Key),
Enabled: types.BoolPointerValue(inputData.Enabled),
Expand Down Expand Up @@ -186,7 +193,7 @@ func (model integrationPolicyModel) toAPIModel(ctx context.Context, isUpdate boo
}
}

body := kbapi.PackagePolicyRequest{
body := kbapi.PackagePolicyRequestMappedInputs{
Description: model.Description.ValueStringPointer(),
Force: model.Force.ValueBoolPointer(),
Name: model.Name.ValueString(),
Expand Down Expand Up @@ -219,17 +226,27 @@ func (model integrationPolicyModel) toAPIModel(ctx context.Context, isUpdate boo
}

body.Inputs = utils.MapRef(utils.ListTypeToMap(ctx, model.Input, path.Root("input"), &diags,
func(inputModel integrationPolicyInputModel, meta utils.ListMeta) (string, kbapi.PackagePolicyRequestInput) {
return inputModel.InputID.ValueString(), kbapi.PackagePolicyRequestInput{
func(inputModel integrationPolicyInputModel, meta utils.ListMeta) (string, kbapi.PackagePolicyRequestMappedInput) {
return inputModel.InputID.ValueString(), kbapi.PackagePolicyRequestMappedInput{
Enabled: inputModel.Enabled.ValueBoolPointer(),
Streams: utils.MapRef(utils.NormalizedTypeToMap[kbapi.PackagePolicyRequestInputStream](inputModel.StreamsJson, meta.Path.AtName("streams_json"), &diags)),
Streams: utils.MapRef(utils.NormalizedTypeToMap[kbapi.PackagePolicyRequestMappedInputStream](inputModel.StreamsJson, meta.Path.AtName("streams_json"), &diags)),
Vars: utils.MapRef(utils.NormalizedTypeToMap[any](inputModel.VarsJson, meta.Path.AtName("vars_json"), &diags)),
}
}))

// Note: space_ids is read-only for integration policies and inherited from the agent policy

return body, diags
var req kbapi.PackagePolicyRequest
err := req.FromPackagePolicyRequestMappedInputs(body)
if err != nil {
diags.AddError(
"Error constructing integration policy request",
"Could not convert integration policy to API request: "+err.Error(),
)
return kbapi.PackagePolicyRequest{}, diags
}

return req, diags
}

// sortInputs will sort the 'incoming' list of input definitions based on
Expand Down
10 changes: 8 additions & 2 deletions internal/fleet/integration_policy/models_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ func TestOutputIdHandling(t *testing.T) {
OutputId: &outputId,
}

// Initialize inputs union to an empty mapped set to avoid JSON parse errors
_ = data.Inputs.FromPackagePolicyMappedInputs(map[string]kbapi.PackagePolicyMappedInput{})

diags := model.populateFromAPI(context.Background(), data)
require.Empty(t, diags)
require.Equal(t, "test-output-id", model.OutputID.ValueString())
Expand All @@ -115,8 +118,11 @@ func TestOutputIdHandling(t *testing.T) {

result, diags := model.toAPIModel(context.Background(), false, feat)
require.Empty(t, diags)
require.NotNil(t, result.OutputId)
require.Equal(t, "test-output-id", *result.OutputId)

mappedResult, err := result.AsPackagePolicyRequestMappedInputs()
require.NoError(t, err)
require.NotNil(t, mappedResult.OutputId)
require.Equal(t, "test-output-id", *mappedResult.OutputId)
})

t.Run("toAPIModel_unsupported_version", func(t *testing.T) {
Expand Down
91 changes: 75 additions & 16 deletions internal/fleet/integration_policy/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package integration_policy
import (
"context"
"encoding/json"
"maps"

"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
"github.com/elastic/terraform-provider-elasticstack/internal/utils"
Expand Down Expand Up @@ -113,15 +114,46 @@ func HandleRespSecrets(ctx context.Context, resp *kbapi.PackagePolicy, private p
}

handleVars(utils.Deref(resp.Vars))
for _, input := range resp.Inputs {
handleVars(utils.Deref(input.Vars))
for _, stream := range utils.Deref(input.Streams) {
handleVars(utils.Deref(stream.Vars))

// Mapped inputs: extract, mutate, and write back
mappedInputs, _ := resp.Inputs.AsPackagePolicyMappedInputs()
typedInputs, _ := resp.Inputs.AsPackagePolicyTypedInputs()
Comment on lines +119 to +120
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error returns from AsPackagePolicyMappedInputs() and AsPackagePolicyTypedInputs() are silently ignored. If these conversions fail, the function proceeds without proper error handling, potentially leading to unexpected behavior. Add error checking and return appropriate diagnostics if conversion fails.

Suggested change
mappedInputs, _ := resp.Inputs.AsPackagePolicyMappedInputs()
typedInputs, _ := resp.Inputs.AsPackagePolicyTypedInputs()
mappedInputs, mappedErr := resp.Inputs.AsPackagePolicyMappedInputs()
typedInputs, typedErr := resp.Inputs.AsPackagePolicyTypedInputs()
if mappedErr != nil {
diags.AddError("could not convert inputs to mapped inputs", mappedErr.Error())
return diags
}
if typedErr != nil {
diags.AddError("could not convert inputs to typed inputs", typedErr.Error())
return diags
}

Copilot uses AI. Check for mistakes.
if mappedInputs != nil {
for _, input := range mappedInputs {
if input.Vars != nil {
handleVars(*input.Vars)
}

if input.Streams != nil {
for _, stream := range *input.Streams {
if stream.Vars != nil {
handleVars(*stream.Vars)
}
}
}
}
// Write back the mutated data
if err := resp.Inputs.FromPackagePolicyMappedInputs(mappedInputs); err != nil {
diags.AddError("could not write back mapped inputs", err.Error())
}
} else if typedInputs != nil {
// Typed inputs: mutate in place through pointers
for i := range typedInputs {
if typedInputs[i].Vars != nil {
handleVars(*typedInputs[i].Vars)
}
for j := range typedInputs[i].Streams {
if typedInputs[i].Streams[j].Vars != nil {
handleVars(*typedInputs[i].Streams[j].Vars)
}
}
}
if err := resp.Inputs.FromPackagePolicyTypedInputs(typedInputs); err != nil {
diags.AddError("could not write back typed inputs", err.Error())
}
}

nd = secrets.Save(ctx, private)
diags.Append(nd...)
diags.Append(secrets.Save(ctx, private)...)

return
}
Expand Down Expand Up @@ -188,19 +220,46 @@ func HandleReqRespSecrets(ctx context.Context, req kbapi.PackagePolicyRequest, r
}
}

handleVars(utils.Deref(req.Vars), utils.Deref(resp.Vars))
for inputID, inputReq := range utils.Deref(req.Inputs) {
inputResp := resp.Inputs[inputID]
handleVars(utils.Deref(inputReq.Vars), utils.Deref(inputResp.Vars))
streamsResp := utils.Deref(inputResp.Streams)
for streamID, streamReq := range utils.Deref(inputReq.Streams) {
streamResp := streamsResp[streamID]
handleVars(utils.Deref(streamReq.Vars), utils.Deref(streamResp.Vars))
mappedReq, _ := req.AsPackagePolicyRequestMappedInputs()
typedReq, _ := req.AsPackagePolicyRequestTypedInputs()
Comment on lines +223 to +224
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to HandleRespSecrets, the error returns are ignored here. Add error handling to ensure conversion failures are properly reported through diagnostics.

Suggested change
mappedReq, _ := req.AsPackagePolicyRequestMappedInputs()
typedReq, _ := req.AsPackagePolicyRequestTypedInputs()
mappedReq, err := req.AsPackagePolicyRequestMappedInputs()
if err != nil {
diags.AddError("failed to convert request mapped inputs", err.Error())
return
}
typedReq, err := req.AsPackagePolicyRequestTypedInputs()
if err != nil {
diags.AddError("failed to convert request typed inputs", err.Error())
return
}

Copilot uses AI. Check for mistakes.

reqVars := map[string]any{}
maps.Copy(reqVars, utils.Deref(mappedReq.Vars))
maps.Copy(reqVars, utils.Deref(typedReq.Vars))
// Policy-level vars
if resp.Vars != nil {
handleVars(reqVars, utils.Deref(resp.Vars))
}

respMappedInputs, _ := resp.Inputs.AsPackagePolicyMappedInputs()
respTypedInputs, _ := resp.Inputs.AsPackagePolicyTypedInputs()
if respMappedInputs != nil {
for inputID, inputReq := range utils.Deref(mappedReq.Inputs) {
inputResp := respMappedInputs[inputID]
handleVars(utils.Deref(inputReq.Vars), utils.Deref(inputResp.Vars))

streamsResp := utils.Deref(inputResp.Streams)
for streamID, streamReq := range utils.Deref(inputReq.Streams) {
handleVars(utils.Deref(streamReq.Vars), utils.Deref(streamsResp[streamID].Vars))
}
}
if err := resp.Inputs.FromPackagePolicyMappedInputs(respMappedInputs); err != nil {
diags.AddError("failed to update mapped inputs", err.Error())
}
} else if respTypedInputs != nil {
for inputIdx, inputReq := range utils.Deref(typedReq.Inputs) {
inputResp := respTypedInputs[inputIdx]
handleVars(utils.Deref(inputReq.Vars), utils.Deref(inputResp.Vars))
for streamIdx, streamReq := range utils.Deref(inputReq.Streams) {
handleVars(utils.Deref(streamReq.Vars), utils.Deref(inputResp.Streams[streamIdx].Vars))
}
}
if err := resp.Inputs.FromPackagePolicyTypedInputs(respTypedInputs); err != nil {
diags.AddError("failed to update typed inputs", err.Error())
}
}

nd = secrets.Save(ctx, private)
diags.Append(nd...)
diags.Append(secrets.Save(ctx, private)...)

return
}
Expand Down
Loading