diff --git a/internal/clients/config/fleet.go b/internal/clients/config/fleet.go index 893642387..a3db97a05 100644 --- a/internal/clients/config/fleet.go +++ b/internal/clients/config/fleet.go @@ -13,8 +13,24 @@ import ( type fleetConfig fleet.Config +// Structure to keep track of which keys were explicitly set in the config. +// This allows us to determine the difference between explicitly set empty +// values and values that were not set at all. Building this intermediate +// representation allows for compatibility with plugin framework and sdkv2. +type fleetConfigKeys struct { + URL bool + Username bool + Password bool + APIKey bool + Insecure bool + CACerts bool +} + func newFleetConfigFromSDK(d *schema.ResourceData, kibanaCfg kibanaOapiConfig) (fleetConfig, sdkdiags.Diagnostics) { - config := kibanaCfg.toFleetConfig() + config := fleetConfig{} + + // Keep track of keys that are explicitly set in the config. + knownKeys := fleetConfigKeys{} // Set variables from resource config. if fleetDataRaw, ok := d.GetOk("fleet"); ok { @@ -31,15 +47,19 @@ func newFleetConfigFromSDK(d *schema.ResourceData, kibanaCfg kibanaOapiConfig) ( } if v, ok := fleetData["endpoint"].(string); ok && v != "" { config.URL = v + knownKeys.URL = true } if v, ok := fleetData["username"].(string); ok && v != "" { config.Username = v + knownKeys.Username = true } if v, ok := fleetData["password"].(string); ok && v != "" { config.Password = v + knownKeys.Password = true } if v, ok := fleetData["api_key"].(string); ok && v != "" { config.APIKey = v + knownKeys.APIKey = true } if v, ok := fleetData["ca_certs"].([]interface{}); ok && len(v) > 0 { for _, elem := range v { @@ -47,35 +67,44 @@ func newFleetConfigFromSDK(d *schema.ResourceData, kibanaCfg kibanaOapiConfig) ( config.CACerts = append(config.CACerts, vStr) } } + knownKeys.CACerts = true } if v, ok := fleetData["insecure"].(bool); ok { config.Insecure = v + knownKeys.Insecure = true } } - return config.withEnvironmentOverrides(), nil + return config.withEnvironmentOverrides().withDefaultsApplied(kibanaCfg.toFleetConfig(), knownKeys), nil } func newFleetConfigFromFramework(ctx context.Context, cfg ProviderConfiguration, kibanaCfg kibanaOapiConfig) (fleetConfig, fwdiags.Diagnostics) { - config := kibanaCfg.toFleetConfig() + config := fleetConfig{} + // Keep track of keys that are explicitly set in the config + knownKeys := fleetConfigKeys{} if len(cfg.Fleet) > 0 { fleetCfg := cfg.Fleet[0] if fleetCfg.Username.ValueString() != "" { config.Username = fleetCfg.Username.ValueString() + knownKeys.Username = true } if fleetCfg.Password.ValueString() != "" { config.Password = fleetCfg.Password.ValueString() + knownKeys.Password = true } if fleetCfg.Endpoint.ValueString() != "" { config.URL = fleetCfg.Endpoint.ValueString() + knownKeys.URL = true } if fleetCfg.APIKey.ValueString() != "" { config.APIKey = fleetCfg.APIKey.ValueString() + knownKeys.APIKey = true } if !fleetCfg.Insecure.IsNull() && !fleetCfg.Insecure.IsUnknown() { config.Insecure = fleetCfg.Insecure.ValueBool() + knownKeys.Insecure = true } var caCerts []string @@ -86,10 +115,41 @@ func newFleetConfigFromFramework(ctx context.Context, cfg ProviderConfiguration, if len(caCerts) > 0 { config.CACerts = caCerts + knownKeys.CACerts = true } } - return config.withEnvironmentOverrides(), nil + return config.withEnvironmentOverrides().withDefaultsApplied(kibanaCfg.toFleetConfig(), knownKeys), nil +} + +func (config fleetConfig) withDefaultsApplied(defaults fleetConfig, knownKeys fleetConfigKeys) fleetConfig { + + // Apply defaults for non-auth fields + if !knownKeys.URL { + config.URL = defaults.URL + } + if !knownKeys.Insecure { + config.Insecure = defaults.Insecure + } + + if !knownKeys.CACerts { + config.CACerts = defaults.CACerts + } + + // Handle auth defaults. APIKey and Username are mutually exclusive. If one is already set don't apply any auth defaults + if knownKeys.APIKey || knownKeys.Username { + return config + } + + // Only apply a single provided auth default + if defaults.APIKey != "" { + config.APIKey = defaults.APIKey + } else if defaults.Username != "" { + config.Username = defaults.Username + config.Password = defaults.Password + } + + return config } func (c fleetConfig) withEnvironmentOverrides() fleetConfig { diff --git a/internal/clients/config/fleet_test.go b/internal/clients/config/fleet_test.go index 021b746fd..63ea7af1f 100644 --- a/internal/clients/config/fleet_test.go +++ b/internal/clients/config/fleet_test.go @@ -120,6 +120,185 @@ func Test_newFleetConfigFromSDK(t *testing.T) { } }, }, + { + name: "should fallback to kibana username/password when no fleet credentials provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + Username: "kibana-user", + Password: "kibana-password", + Insecure: false, + } + + return args{ + kibanaCfg: kibanaCfg, + resourceData: map[string]interface{}{ + "fleet": []interface{}{ + map[string]interface{}{ + "endpoint": "example.com/fleet", + // No username/password provided in fleet config + "ca_certs": []interface{}{"internal"}, + "insecure": false, + }, + }, + }, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + Username: "kibana-user", // Falls back to kibana credentials + Password: "kibana-password", // Falls back to kibana credentials + CACerts: []string{"internal"}, + Insecure: false, + }, + } + }, + }, + { + name: "should fallback to kibana api_key when no fleet credentials provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + APIKey: "kibana-api-key-123", + Insecure: true, + } + + return args{ + kibanaCfg: kibanaCfg, + resourceData: map[string]interface{}{ + "fleet": []interface{}{ + map[string]interface{}{ + "endpoint": "example.com/fleet", + // No api_key provided in fleet config + "insecure": true, + }, + }, + }, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + APIKey: "kibana-api-key-123", // Falls back to kibana api_key + Insecure: true, + }, + } + }, + }, + { + name: "should not override fleet credentials when they are explicitly provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + Username: "kibana-user", + Password: "kibana-password", + Insecure: false, + } + + return args{ + kibanaCfg: kibanaCfg, + resourceData: map[string]interface{}{ + "fleet": []interface{}{ + map[string]interface{}{ + "endpoint": "example.com/fleet", + "username": "fleet-user", + "password": "fleet-password", + "insecure": false, + }, + }, + }, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + Username: "fleet-user", // Uses fleet-specific credentials + Password: "fleet-password", // Uses fleet-specific credentials + Insecure: false, + }, + } + }, + }, + { + name: "should not override fleet api_key when explicitly provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + APIKey: "kibana-api-key-123", + Insecure: false, + } + + return args{ + kibanaCfg: kibanaCfg, + resourceData: map[string]interface{}{ + "fleet": []interface{}{ + map[string]interface{}{ + "endpoint": "example.com/fleet", + "api_key": "fleet-api-key-456", + "insecure": false, + }, + }, + }, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + APIKey: "fleet-api-key-456", // Uses fleet-specific api_key + Insecure: false, + }, + } + }, + }, + { + name: "should not add kibana api key when fleet credentials are explicitly provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + APIKey: "kibana-api-key-123", + Insecure: false, + } + + return args{ + kibanaCfg: kibanaCfg, + resourceData: map[string]interface{}{ + "fleet": []interface{}{ + map[string]interface{}{ + "endpoint": "example.com/fleet", + "username": "fleet-user", + "password": "fleet-password", + "insecure": false, + }, + }, + }, + env: map[string]string{}, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + Username: "fleet-user", // Uses fleet-specific credentials + Password: "fleet-password", // Uses fleet-specific credentials + Insecure: false, + }, + } + }, + }, + { + name: "should not add kibana credentials when fleet api key is explicitly provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + Username: "kibana-user", + Password: "kibana-password", + Insecure: false, + } + + return args{ + kibanaCfg: kibanaCfg, + resourceData: map[string]interface{}{ + "fleet": []interface{}{ + map[string]interface{}{ + "endpoint": "example.com/fleet", + "insecure": false, + "api_key": "fleet-api-key-123", + }, + }, + }, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + APIKey: "fleet-api-key-123", + Insecure: false, + }, + } + }, + }, } for _, tt := range tests { @@ -259,6 +438,192 @@ func Test_newFleetConfigFromFramework(t *testing.T) { } }, }, + { + name: "should fallback to kibana username/password when no fleet credentials provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + Username: "kibana-user", + Password: "kibana-password", + Insecure: false, + } + + return args{ + kibanaCfg: kibanaCfg, + providerConfig: ProviderConfiguration{ + Fleet: []FleetConnection{ + { + Endpoint: types.StringValue("example.com/fleet"), + // No username/password provided in fleet config + CACerts: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("internal"), + }), + Insecure: types.BoolValue(false), + }, + }, + }, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + Username: "kibana-user", // Falls back to kibana credentials + Password: "kibana-password", // Falls back to kibana credentials + CACerts: []string{"internal"}, + Insecure: false, + }, + } + }, + }, + { + name: "should fallback to kibana api_key when no fleet credentials provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + APIKey: "kibana-api-key-123", + Insecure: true, + } + + return args{ + kibanaCfg: kibanaCfg, + providerConfig: ProviderConfiguration{ + Fleet: []FleetConnection{ + { + Endpoint: types.StringValue("example.com/fleet"), + // No api_key provided in fleet config + CACerts: types.ListValueMust(types.StringType, []attr.Value{}), + Insecure: types.BoolValue(true), + }, + }, + }, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + APIKey: "kibana-api-key-123", // Falls back to kibana api_key + Insecure: true, + }, + } + }, + }, + { + name: "should not override fleet credentials when they are explicitly provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + Username: "kibana-user", + Password: "kibana-password", + Insecure: false, + } + + return args{ + kibanaCfg: kibanaCfg, + providerConfig: ProviderConfiguration{ + Fleet: []FleetConnection{ + { + Username: types.StringValue("fleet-user"), + Password: types.StringValue("fleet-password"), + Endpoint: types.StringValue("example.com/fleet"), + CACerts: types.ListValueMust(types.StringType, []attr.Value{}), + Insecure: types.BoolValue(false), + }, + }, + }, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + Username: "fleet-user", // Uses fleet-specific credentials + Password: "fleet-password", // Uses fleet-specific credentials + Insecure: false, + }, + } + }, + }, + { + name: "should not override fleet api_key when explicitly provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + APIKey: "kibana-api-key-123", + Insecure: false, + } + + return args{ + kibanaCfg: kibanaCfg, + providerConfig: ProviderConfiguration{ + Fleet: []FleetConnection{ + { + APIKey: types.StringValue("fleet-api-key-456"), + Endpoint: types.StringValue("example.com/fleet"), + CACerts: types.ListValueMust(types.StringType, []attr.Value{}), + Insecure: types.BoolValue(false), + }, + }, + }, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + APIKey: "fleet-api-key-456", // Uses fleet-specific api_key + Insecure: false, + }, + } + }, + }, + { + name: "should not add kibana api key when fleet credentials are explicitly provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + APIKey: "kibana-api-key-123", + Insecure: false, + } + + return args{ + kibanaCfg: kibanaCfg, + providerConfig: ProviderConfiguration{ + Fleet: []FleetConnection{ + { + Username: types.StringValue("fleet-user"), + Password: types.StringValue("fleet-password"), + Endpoint: types.StringValue("example.com/fleet"), + CACerts: types.ListValueMust(types.StringType, []attr.Value{}), + Insecure: types.BoolValue(false), + }, + }, + }, + env: map[string]string{}, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + Username: "fleet-user", // Uses fleet-specific credentials + Password: "fleet-password", // Uses fleet-specific credentials + Insecure: false, + }, + } + }, + }, + { + name: "should not add kibana credentials when fleet api key is explicitly provided", + args: func() args { + kibanaCfg := kibanaOapiConfig{ + URL: "example.com/kibana", + Username: "kibana-user", + Password: "kibana-password", + Insecure: false, + } + + return args{ + kibanaCfg: kibanaCfg, + providerConfig: ProviderConfiguration{ + Fleet: []FleetConnection{ + { + APIKey: types.StringValue("fleet-api-key-456"), + Endpoint: types.StringValue("example.com/fleet"), + CACerts: types.ListValueMust(types.StringType, []attr.Value{}), + Insecure: types.BoolValue(false), + }, + }, + }, + expectedConfig: fleetConfig{ + URL: "example.com/fleet", + APIKey: "fleet-api-key-456", + Insecure: false, + }, + } + }, + }, } for _, tt := range tests { diff --git a/internal/clients/config/kibana.go b/internal/clients/config/kibana.go index e7a8529f7..30a9e5c5e 100644 --- a/internal/clients/config/kibana.go +++ b/internal/clients/config/kibana.go @@ -14,14 +14,31 @@ import ( type kibanaConfig kibana.Config +// Structure to keep track of which keys were explicitly set in the config. +// This allows us to determine the difference between explicitly set empty +// values and values that were not set at all. Building this intermediate +// representation allows for compatibility with plugin framework and sdkv2. +type kibanaConfigKeys struct { + Address bool + Username bool + Password bool + ApiKey bool + DisableVerifySSL bool + CAs bool +} + func newKibanaConfigFromSDK(d *schema.ResourceData, base baseConfig) (kibanaConfig, sdkdiags.Diagnostics) { var diags sdkdiags.Diagnostics // Use ES details by default - config := base.toKibanaConfig() + config := kibanaConfig{} + + // Keep track of keys that are explicitly set in the config. + knownKeys := kibanaConfigKeys{} + kibConn, ok := d.GetOk("kibana") if !ok { - return config, diags + return config.withDefaultsApplied(base.toKibanaConfig(), knownKeys), diags } // if defined, then we only have a single entry @@ -30,19 +47,23 @@ func newKibanaConfigFromSDK(d *schema.ResourceData, base baseConfig) (kibanaConf if username, ok := kibConfig["username"]; ok && username != "" { config.Username = username.(string) + knownKeys.Username = true } if password, ok := kibConfig["password"]; ok && password != "" { config.Password = password.(string) + knownKeys.Password = true } if apiKey, ok := kibConfig["api_key"]; ok && apiKey != "" { config.ApiKey = apiKey.(string) + knownKeys.ApiKey = true } if endpoints, ok := kibConfig["endpoints"]; ok && len(endpoints.([]interface{})) > 0 { // We're curently limited by the API to a single endpoint if endpoint := endpoints.([]interface{})[0]; endpoint != nil { config.Address = endpoint.(string) + knownKeys.Address = true } } @@ -52,29 +73,35 @@ func newKibanaConfigFromSDK(d *schema.ResourceData, base baseConfig) (kibanaConf config.CAs = append(config.CAs, vStr) } } + knownKeys.CAs = true } if insecure, ok := kibConfig["insecure"]; ok && insecure.(bool) { config.DisableVerifySSL = true + knownKeys.DisableVerifySSL = true } } - return config.withEnvironmentOverrides(), nil + return config.withEnvironmentOverrides().withDefaultsApplied(base.toKibanaConfig(), knownKeys), nil } func newKibanaConfigFromFramework(ctx context.Context, cfg ProviderConfiguration, base baseConfig) (kibanaConfig, fwdiags.Diagnostics) { - config := base.toKibanaConfig() + config := kibanaConfig{} + knownKeys := kibanaConfigKeys{} if len(cfg.Kibana) > 0 { kibConfig := cfg.Kibana[0] if kibConfig.Username.ValueString() != "" { config.Username = kibConfig.Username.ValueString() + knownKeys.Username = true } if kibConfig.Password.ValueString() != "" { config.Password = kibConfig.Password.ValueString() + knownKeys.Password = true } if kibConfig.ApiKey.ValueString() != "" { config.ApiKey = kibConfig.ApiKey.ValueString() + knownKeys.ApiKey = true } var endpoints []string diags := kibConfig.Endpoints.ElementsAs(ctx, &endpoints, true) @@ -87,16 +114,47 @@ func newKibanaConfigFromFramework(ctx context.Context, cfg ProviderConfiguration if len(endpoints) > 0 { config.Address = endpoints[0] + knownKeys.Address = true } if len(cas) > 0 { config.CAs = cas + knownKeys.CAs = true } config.DisableVerifySSL = kibConfig.Insecure.ValueBool() + knownKeys.DisableVerifySSL = true + } + return config.withEnvironmentOverrides().withDefaultsApplied(base.toKibanaConfig(), knownKeys), nil +} + +func (config kibanaConfig) withDefaultsApplied(defaults kibanaConfig, knownKeys kibanaConfigKeys) kibanaConfig { + + // Apply defaults for non-auth fields + if !knownKeys.Address { + config.Address = defaults.Address } + if !knownKeys.DisableVerifySSL { + config.DisableVerifySSL = defaults.DisableVerifySSL + } + if !knownKeys.CAs { + config.CAs = defaults.CAs + } + + // Handle auth defaults. ApiKey and Username are mutually exclusive. If one is already set don't apply any auth defaults + if knownKeys.ApiKey || knownKeys.Username { + return config + } + + if defaults.ApiKey != "" { + config.ApiKey = defaults.ApiKey + } else if defaults.Username != "" { + config.Username = defaults.Username + config.Password = defaults.Password + } + + return config - return config.withEnvironmentOverrides(), nil } func (k kibanaConfig) withEnvironmentOverrides() kibanaConfig { diff --git a/internal/clients/config/kibana_test.go b/internal/clients/config/kibana_test.go index c5dc22352..5e4a92bab 100644 --- a/internal/clients/config/kibana_test.go +++ b/internal/clients/config/kibana_test.go @@ -110,6 +110,173 @@ func Test_newKibanaConfigFromSDK(t *testing.T) { } }, }, + { + name: "should fallback to elasticsearch username/password when no kibana credentials provided", + args: func() args { + baseCfg := baseConfig{ + Username: "es-user", + Password: "es-password", + } + + return args{ + baseCfg: baseCfg, + resourceData: map[string]interface{}{ + "kibana": []interface{}{ + map[string]interface{}{ + "endpoints": []interface{}{"example.com/kibana"}, + // No username/password provided in kibana config + "ca_certs": []interface{}{"internal"}, + "insecure": false, + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + Username: "es-user", // Falls back to ES credentials + Password: "es-password", // Falls back to ES credentials + CAs: []string{"internal"}, + DisableVerifySSL: false, + }, + } + }, + }, + { + name: "should fallback to elasticsearch api_key when no kibana credentials provided", + args: func() args { + baseCfg := baseConfig{ + ApiKey: "es-api-key-123", + } + + return args{ + baseCfg: baseCfg, + resourceData: map[string]interface{}{ + "kibana": []interface{}{ + map[string]interface{}{ + "endpoints": []interface{}{"example.com/kibana"}, + // No api_key provided in kibana config + "insecure": true, + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + ApiKey: "es-api-key-123", // Falls back to ES api_key + DisableVerifySSL: true, + }, + } + }, + }, + { + name: "should not override kibana credentials when they are explicitly provided", + args: func() args { + baseCfg := baseConfig{ + Username: "es-user", + Password: "es-password", + } + + return args{ + baseCfg: baseCfg, + resourceData: map[string]interface{}{ + "kibana": []interface{}{ + map[string]interface{}{ + "endpoints": []interface{}{"example.com/kibana"}, + "username": "kibana-user", + "password": "kibana-password", + "insecure": false, + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + Username: "kibana-user", // Uses kibana-specific credentials + Password: "kibana-password", // Uses kibana-specific credentials + DisableVerifySSL: false, + }, + } + }, + }, + { + name: "should not override kibana api_key when explicitly provided", + args: func() args { + baseCfg := baseConfig{ + ApiKey: "es-api-key-123", + } + + return args{ + baseCfg: baseCfg, + resourceData: map[string]interface{}{ + "kibana": []interface{}{ + map[string]interface{}{ + "endpoints": []interface{}{"example.com/kibana"}, + "api_key": "es-api-key-456", + "insecure": false, + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + ApiKey: "es-api-key-456", // Uses kibana-specific api_key + DisableVerifySSL: false, + }, + } + }, + }, + { + name: "should not add elasticsearch api key when kibana credentials are explicitly provided", + args: func() args { + baseCfg := baseConfig{ + ApiKey: "es-api-key-123", + } + + return args{ + baseCfg: baseCfg, + resourceData: map[string]interface{}{ + "kibana": []interface{}{ + map[string]interface{}{ + "endpoints": []interface{}{"example.com/kibana"}, + "username": "kibana-user", + "password": "kibana-password", + "insecure": false, + }, + }, + }, + env: map[string]string{}, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + Username: "kibana-user", // Uses kibana-specific credentials + Password: "kibana-password", // Uses kibana-specific credentials + DisableVerifySSL: false, + }, + } + }, + }, + { + name: "should not add elasticsearch credentials when kibana api key are explicitly provided", + args: func() args { + baseCfg := baseConfig{ + Username: "es-user", + Password: "es-password", + } + + return args{ + baseCfg: baseCfg, + resourceData: map[string]interface{}{ + "kibana": []interface{}{ + map[string]interface{}{ + "endpoints": []interface{}{"example.com/kibana"}, + "insecure": false, + "api_key": "es-api-key-123", + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + ApiKey: "es-api-key-123", + DisableVerifySSL: false, + }, + } + }, + }, } for _, tt := range tests { @@ -273,6 +440,192 @@ func Test_newKibanaConfigFromFramework(t *testing.T) { } }, }, + { + name: "should fallback to elasticsearch username/password when no kibana credentials provided", + args: func() args { + baseCfg := baseConfig{ + Username: "es-user", + Password: "es-password", + } + + return args{ + baseCfg: baseCfg, + providerConfig: ProviderConfiguration{ + Kibana: []KibanaConnection{ + { + Endpoints: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("example.com/kibana"), + }), + // No username/password provided in kibana config + CACerts: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("internal"), + }), + Insecure: types.BoolValue(false), + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + Username: "es-user", // Falls back to ES credentials + Password: "es-password", // Falls back to ES credentials + CAs: []string{"internal"}, + DisableVerifySSL: false, + }, + } + }, + }, + { + name: "should fallback to elasticsearch api_key when no kibana credentials provided", + args: func() args { + baseCfg := baseConfig{ + ApiKey: "es-api-key-123", + } + + return args{ + baseCfg: baseCfg, + providerConfig: ProviderConfiguration{ + Kibana: []KibanaConnection{ + { + Endpoints: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("example.com/kibana"), + }), + // No api_key provided in kibana config + CACerts: types.ListValueMust(types.StringType, []attr.Value{}), + Insecure: types.BoolValue(true), + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + ApiKey: "es-api-key-123", // Falls back to ES api_key + DisableVerifySSL: true, + }, + } + }, + }, + { + name: "should not override kibana credentials when they are explicitly provided", + args: func() args { + baseCfg := baseConfig{ + Username: "es-user", + Password: "es-password", + } + + return args{ + baseCfg: baseCfg, + providerConfig: ProviderConfiguration{ + Kibana: []KibanaConnection{ + { + Username: types.StringValue("kibana-user"), + Password: types.StringValue("kibana-password"), + Endpoints: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("example.com/kibana"), + }), + CACerts: types.ListValueMust(types.StringType, []attr.Value{}), + Insecure: types.BoolValue(false), + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + Username: "kibana-user", // Uses kibana-specific credentials + Password: "kibana-password", // Uses kibana-specific credentials + DisableVerifySSL: false, + }, + } + }, + }, + { + name: "should not override kibana api_key when explicitly provided", + args: func() args { + baseCfg := baseConfig{ + ApiKey: "es-api-key-123", + } + + return args{ + baseCfg: baseCfg, + providerConfig: ProviderConfiguration{ + Kibana: []KibanaConnection{ + { + ApiKey: types.StringValue("kibana-api-key-456"), + Endpoints: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("example.com/kibana"), + }), + CACerts: types.ListValueMust(types.StringType, []attr.Value{}), + Insecure: types.BoolValue(false), + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + ApiKey: "kibana-api-key-456", // Uses kibana-specific api_key + DisableVerifySSL: false, + }, + } + }, + }, + { + name: "should not add elasticsearch api key when kibana credentials are explicitly provided", + args: func() args { + baseCfg := baseConfig{ + ApiKey: "es-api-key-123", + } + + return args{ + baseCfg: baseCfg, + providerConfig: ProviderConfiguration{ + Kibana: []KibanaConnection{ + { + Username: types.StringValue("kibana-user"), + Password: types.StringValue("kibana-password"), + Endpoints: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("example.com/kibana"), + }), + CACerts: types.ListValueMust(types.StringType, []attr.Value{}), + Insecure: types.BoolValue(false), + }, + }, + }, + env: map[string]string{}, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + Username: "kibana-user", // Uses kibana-specific credentials + Password: "kibana-password", // Uses kibana-specific credentials + DisableVerifySSL: false, + }, + } + }, + }, + { + name: "should not add elasticsearch credentials when kibana api key are explicitly provided", + args: func() args { + baseCfg := baseConfig{ + Username: "es-user", + Password: "es-password", + } + + return args{ + baseCfg: baseCfg, + providerConfig: ProviderConfiguration{ + Kibana: []KibanaConnection{ + { + ApiKey: types.StringValue("kibana-api-key-456"), + Endpoints: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("example.com/kibana"), + }), + CACerts: types.ListValueMust(types.StringType, []attr.Value{}), + Insecure: types.BoolValue(false), + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + ApiKey: "kibana-api-key-456", + DisableVerifySSL: false, + }, + } + }, + }, } for _, tt := range tests {