From a40fbc557bf0cd5593e5fec5345026baab6f3136 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Fri, 28 Nov 2025 11:44:14 +0100 Subject: [PATCH 01/15] get axios instance with auth --- .../server/actions_client/actions_client.ts | 12 ++++ .../get_axios_instance/get_axios_instance.ts | 66 +++++++++++++++++++ .../methods/get_axios_instance/index.ts | 8 +++ .../methods/get_axios_instance/types/index.ts | 8 +++ .../methods/get_axios_instance/types/types.ts | 10 +++ .../actions/server/lib/action_executor.ts | 46 +++++++++++++ .../plugins/shared/actions/server/plugin.ts | 26 +++++--- 7 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts create mode 100644 x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/index.ts create mode 100644 x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/index.ts create mode 100644 x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/types.ts diff --git a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts index d85ee92d04049..4e6d4e4156c9d 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts @@ -81,6 +81,8 @@ import { isPreconfigured } from '../lib/is_preconfigured'; import { isSystemAction } from '../lib/is_system_action'; import type { ConnectorExecuteParams } from '../application/connector/methods/execute/types'; import { connectorFromInMemoryConnector } from '../application/connector/lib/connector_from_in_memory_connector'; +import { getAxiosInstance } from '../application/connector/methods/get_axios_instance'; +import { AxiosInstance } from 'axios'; export interface ConstructorOptions { logger: Logger; @@ -97,6 +99,7 @@ export interface ConstructorOptions { usageCounter?: UsageCounter; connectorTokenClient: ConnectorTokenClientContract; getEventLogClient: () => Promise; + getAxiosInstanceWithAuth: (validatedSecrets: Record) => Promise; } export interface ActionsClientContext { @@ -114,6 +117,7 @@ export interface ActionsClientContext { usageCounter?: UsageCounter; connectorTokenClient: ConnectorTokenClientContract; getEventLogClient: () => Promise; + getAxiosInstanceWithAuth: (validatedSecrets: Record) => Promise; } export class ActionsClient { @@ -134,6 +138,7 @@ export class ActionsClient { usageCounter, connectorTokenClient, getEventLogClient, + getAxiosInstanceWithAuth, }: ConstructorOptions) { this.context = { logger, @@ -150,6 +155,7 @@ export class ActionsClient { usageCounter, connectorTokenClient, getEventLogClient, + getAxiosInstanceWithAuth, }; } @@ -499,6 +505,12 @@ export class ActionsClient { return execute(this.context, connectorExecuteParams); } + public async getAxiosInstance( + connectorExecuteParams: ConnectorExecuteParams + ): Promise { + return getAxiosInstance(this.context, connectorExecuteParams); + } + public async bulkEnqueueExecution( options: EnqueueExecutionOptions[] ): Promise { diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts new file mode 100644 index 0000000000000..b0bbc39fa0b5f --- /dev/null +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RawAction } from '../../../../types'; +import { getActionKibanaPrivileges } from '../../../../lib/get_action_kibana_privileges'; +import { isPreconfigured } from '../../../../lib/is_preconfigured'; +import { isSystemAction } from '../../../../lib/is_system_action'; +import type { ConnectorExecuteParams } from './types'; +import { ACTION_SAVED_OBJECT_TYPE } from '../../../../constants/saved_objects'; +import type { ActionsClientContext } from '../../../../actions_client'; +import { AxiosInstance } from 'axios'; + +type ValidatedSecrets = Record; + +export type GetAxiosInstanceWithAuthFn = (secrets: ValidatedSecrets) => Promise; + +export async function getAxiosInstance( + context: ActionsClientContext, + connectorExecuteParams: ConnectorExecuteParams +): Promise { + const log = context.logger; + const { actionId, params, source } = connectorExecuteParams; + let actionTypeId: string | undefined; + + try { + if (isPreconfigured(context, actionId) || isSystemAction(context, actionId)) { + const connector = context.inMemoryConnectors.find( + (inMemoryConnector) => inMemoryConnector.id === actionId + ); + + actionTypeId = connector?.actionTypeId; + } else { + const { attributes } = await context.unsecuredSavedObjectsClient.get( + ACTION_SAVED_OBJECT_TYPE, + actionId + ); + + actionTypeId = attributes.actionTypeId; + } + } catch (err) { + log.debug(`Failed to retrieve actionTypeId for action [${actionId}]`, err); + } + + const additionalPrivileges = getActionKibanaPrivileges( + context, + actionTypeId, + params, + source?.type + ); + + await context.authorization.ensureAuthorized({ + operation: 'execute', + additionalPrivileges, + actionTypeId, + }); + + return context.actionExecutor.getAxiosInstance({ + actionId, + request: context.request, + getAxiosInstanceWithAuth: context.getAxiosInstanceWithAuth, + }); +} diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/index.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/index.ts new file mode 100644 index 0000000000000..5474c028635c3 --- /dev/null +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { getAxiosInstance } from './get_axios_instance'; diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/index.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/index.ts new file mode 100644 index 0000000000000..ff2bc6be97a80 --- /dev/null +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { ConnectorExecuteParams } from './types'; diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/types.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/types.ts new file mode 100644 index 0000000000000..cd53f4574bebc --- /dev/null +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/types.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ExecuteOptions } from '../../../../../lib/action_executor'; + +export type ConnectorExecuteParams = Omit; diff --git a/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts b/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts index d04df86a2f8f3..1111b4fa8e2b9 100644 --- a/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts +++ b/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts @@ -56,6 +56,7 @@ import { createActionEventLogRecordObject } from './create_action_event_log_reco import { ActionExecutionError, ActionExecutionErrorReason } from './errors/action_execution_error'; import type { ActionsAuthorization } from '../authorization/actions_authorization'; import type { ConnectorRateLimiter } from './connector_rate_limiter'; +import { AxiosInstance } from 'axios'; // 1,000,000 nanoseconds in 1 millisecond const Millis2Nanos = 1000 * 1000; @@ -101,6 +102,12 @@ type ExecuteHelperOptions = Omit, 'requ spaceId?: string; }; +type GetAxiosInstanceParams = { + actionId: string; + request: KibanaRequest; + getAxiosInstanceWithAuth: (validatedSecrets: Record) => Promise; +}; + type UnsecuredExecuteOptions = Pick< ExecuteOptions, 'actionExecutionId' | 'actionId' | 'params' | 'relatedSavedObjects' | 'source' @@ -194,6 +201,45 @@ export class ActionExecutor { }); } + public async getAxiosInstance({ + actionId, + request, + getAxiosInstanceWithAuth, + }: GetAxiosInstanceParams): Promise { + if (!this.isInitialized) { + throw new Error('ActionExecutor not initialized'); + } + + const { spaces, actionTypeRegistry } = this.actionExecutorContext!; + const spaceId = spaces && spaces.getSpaceId(request); + const namespace = spaceId && spaceId !== 'default' ? { namespace: spaceId } : {}; + + const actionInfo = await this.getActionInfoInternal(actionId, namespace.namespace); + + const { actionTypeId, secrets } = actionInfo; + + if (!this.actionInfo || this.actionInfo.actionId !== actionId) { + this.actionInfo = actionInfo; + } + + const actionType = actionTypeRegistry.get(actionTypeId); + const configurationUtilities = actionTypeRegistry.getUtils(); + + let validatedSecrets; + try { + validatedSecrets = validateSecrets(actionType, secrets, { configurationUtilities }); + } catch (err) { + throw new ActionExecutionError(err.message, ActionExecutionErrorReason.Validation, { + actionId, + status: 'error', + message: err.message, + errorSource: TaskErrorSource.FRAMEWORK, + }); + } + + return await getAxiosInstanceWithAuth(validatedSecrets); + } + public async executeUnsecured({ actionExecutionId, actionId, diff --git a/x-pack/platform/plugins/shared/actions/server/plugin.ts b/x-pack/platform/plugins/shared/actions/server/plugin.ts index 9ae0ec19df393..e0383773be529 100644 --- a/x-pack/platform/plugins/shared/actions/server/plugin.ts +++ b/x-pack/platform/plugins/shared/actions/server/plugin.ts @@ -378,15 +378,6 @@ export class ActionsPlugin usageCounter: this.usageCounter, }); - const getAxiosInstanceFn = getAxiosInstanceWithAuth({ - authTypeRegistry: this.authTypeRegistry!, - configurationUtilities: actionsConfigUtils, - logger: this.logger, - }); - const getAxiosInstanceWithAuthHelper = async (validatedSecrets: Record) => { - return await getAxiosInstanceFn(validatedSecrets); - }; - return { registerType: < Config extends ActionTypeConfig = ActionTypeConfig, @@ -407,7 +398,7 @@ export class ActionsPlugin ) => { subActionFramework.registerConnector(connector); }, - getAxiosInstanceWithAuth: getAxiosInstanceWithAuthHelper, + getAxiosInstanceWithAuth: this.getAxiosInstanceWithAuthHelper(actionsConfigUtils), isPreconfiguredConnector: (connectorId: string): boolean => { return !!this.inMemoryConnectors.find( (inMemoryConnector) => @@ -518,6 +509,7 @@ export class ActionsPlugin async getEventLogClient() { return plugins.eventLog.getClient(request); }, + getAxiosInstanceWithAuth: this.getAxiosInstanceWithAuthHelper(actionsConfigUtils), }); }; @@ -757,6 +749,7 @@ export class ActionsPlugin security, usageCounter, logger, + getAxiosInstanceWithAuthHelper, } = this; return async function actionsRouteHandlerContext(context, request) { @@ -807,6 +800,7 @@ export class ActionsPlugin async getEventLogClient() { return eventLog.getClient(request); }, + getAxiosInstanceWithAuth: getAxiosInstanceWithAuthHelper(actionsConfigUtils), }); }, listTypes: (featureId?: string) => { @@ -829,6 +823,18 @@ export class ActionsPlugin } }; + private getAxiosInstanceWithAuthHelper = (actionsConfigUtils: ActionsConfigurationUtilities) => { + const getAxiosInstanceFn = getAxiosInstanceWithAuth({ + authTypeRegistry: this.authTypeRegistry!, + configurationUtilities: actionsConfigUtils, + logger: this.logger, + }); + + return async (validatedSecrets: Record) => { + return await getAxiosInstanceFn(validatedSecrets); + }; + }; + public stop() { if (this.licenseState) { this.licenseState.clean(); From a86678906122533f08ea97d49b3a6a6eeb6338f6 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Fri, 28 Nov 2025 14:38:57 +0100 Subject: [PATCH 02/15] Stopped using the action executor --- .../server/actions_client/actions_client.ts | 20 ++++- .../get_axios_instance/get_axios_instance.ts | 81 ++++++++++++++----- .../plugins/shared/actions/server/plugin.ts | 17 +++- 3 files changed, 91 insertions(+), 27 deletions(-) diff --git a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts index 4e6d4e4156c9d..00629344d1911 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts @@ -83,12 +83,15 @@ import type { ConnectorExecuteParams } from '../application/connector/methods/ex import { connectorFromInMemoryConnector } from '../application/connector/lib/connector_from_in_memory_connector'; import { getAxiosInstance } from '../application/connector/methods/get_axios_instance'; import { AxiosInstance } from 'axios'; +import { SpacesServiceSetup } from '@kbn/spaces-plugin/server'; +import { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-shared'; export interface ConstructorOptions { logger: Logger; kibanaIndices: string[]; scopedClusterClient: IScopedClusterClient; actionTypeRegistry: ActionTypeRegistry; + encryptedSavedObjectsClient: EncryptedSavedObjectsClient; unsecuredSavedObjectsClient: SavedObjectsClientContract; inMemoryConnectors: InMemoryConnector[]; actionExecutor: ActionExecutorContract; @@ -100,12 +103,15 @@ export interface ConstructorOptions { connectorTokenClient: ConnectorTokenClientContract; getEventLogClient: () => Promise; getAxiosInstanceWithAuth: (validatedSecrets: Record) => Promise; + spaces?: SpacesServiceSetup; + isESOCanEncrypt: boolean; } export interface ActionsClientContext { logger: Logger; kibanaIndices: string[]; scopedClusterClient: IScopedClusterClient; + encryptedSavedObjectsClient: EncryptedSavedObjectsClient; unsecuredSavedObjectsClient: SavedObjectsClientContract; actionTypeRegistry: ActionTypeRegistry; inMemoryConnectors: InMemoryConnector[]; @@ -118,6 +124,8 @@ export interface ActionsClientContext { connectorTokenClient: ConnectorTokenClientContract; getEventLogClient: () => Promise; getAxiosInstanceWithAuth: (validatedSecrets: Record) => Promise; + spaces?: SpacesServiceSetup; + isESOCanEncrypt: boolean; } export class ActionsClient { @@ -128,6 +136,7 @@ export class ActionsClient { actionTypeRegistry, kibanaIndices, scopedClusterClient, + encryptedSavedObjectsClient, unsecuredSavedObjectsClient, inMemoryConnectors, actionExecutor, @@ -139,10 +148,13 @@ export class ActionsClient { connectorTokenClient, getEventLogClient, getAxiosInstanceWithAuth, + spaces, + isESOCanEncrypt, }: ConstructorOptions) { this.context = { logger, actionTypeRegistry, + encryptedSavedObjectsClient, unsecuredSavedObjectsClient, scopedClusterClient, kibanaIndices, @@ -156,6 +168,8 @@ export class ActionsClient { connectorTokenClient, getEventLogClient, getAxiosInstanceWithAuth, + spaces, + isESOCanEncrypt, }; } @@ -505,10 +519,8 @@ export class ActionsClient { return execute(this.context, connectorExecuteParams); } - public async getAxiosInstance( - connectorExecuteParams: ConnectorExecuteParams - ): Promise { - return getAxiosInstance(this.context, connectorExecuteParams); + public async getAxiosInstance(actionId: string): Promise { + return getAxiosInstance(this.context, actionId); } public async bulkEnqueueExecution( diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts index b0bbc39fa0b5f..fb9bdee97036f 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts @@ -9,10 +9,11 @@ import type { RawAction } from '../../../../types'; import { getActionKibanaPrivileges } from '../../../../lib/get_action_kibana_privileges'; import { isPreconfigured } from '../../../../lib/is_preconfigured'; import { isSystemAction } from '../../../../lib/is_system_action'; -import type { ConnectorExecuteParams } from './types'; import { ACTION_SAVED_OBJECT_TYPE } from '../../../../constants/saved_objects'; import type { ActionsClientContext } from '../../../../actions_client'; import { AxiosInstance } from 'axios'; +import { validateSecrets } from '@kbn/actions-plugin/server/lib'; +import { SavedObjectsErrorHelpers } from '@kbn/core/server'; type ValidatedSecrets = Record; @@ -20,21 +21,33 @@ export type GetAxiosInstanceWithAuthFn = (secrets: ValidatedSecrets) => Promise< export async function getAxiosInstance( context: ActionsClientContext, - connectorExecuteParams: ConnectorExecuteParams + actionId: string ): Promise { - const log = context.logger; - const { actionId, params, source } = connectorExecuteParams; + const { + actionTypeRegistry, + authorization, + encryptedSavedObjectsClient, + getAxiosInstanceWithAuth, + inMemoryConnectors, + isESOCanEncrypt, + logger: log, + request, + spaces, + unsecuredSavedObjectsClient, + } = context; + let actionTypeId: string | undefined; + let secrets; try { if (isPreconfigured(context, actionId) || isSystemAction(context, actionId)) { - const connector = context.inMemoryConnectors.find( + const connector = inMemoryConnectors.find( (inMemoryConnector) => inMemoryConnector.id === actionId ); actionTypeId = connector?.actionTypeId; } else { - const { attributes } = await context.unsecuredSavedObjectsClient.get( + const { attributes } = await unsecuredSavedObjectsClient.get( ACTION_SAVED_OBJECT_TYPE, actionId ); @@ -45,22 +58,50 @@ export async function getAxiosInstance( log.debug(`Failed to retrieve actionTypeId for action [${actionId}]`, err); } - const additionalPrivileges = getActionKibanaPrivileges( - context, - actionTypeId, - params, - source?.type - ); - - await context.authorization.ensureAuthorized({ + await authorization.ensureAuthorized({ operation: 'execute', - additionalPrivileges, + additionalPrivileges: getActionKibanaPrivileges(context, actionTypeId), actionTypeId, }); - return context.actionExecutor.getAxiosInstance({ - actionId, - request: context.request, - getAxiosInstanceWithAuth: context.getAxiosInstanceWithAuth, - }); + // check to see if it's in memory connector first + const inMemoryAction = inMemoryConnectors.find( + (inMemoryConnector) => inMemoryConnector.id === actionId + ); + + if (inMemoryAction) { + secrets = inMemoryAction.secrets; + } else { + if (!isESOCanEncrypt) { + throw new Error( + `Unable to get axios instance action because the Encrypted Saved Objects plugin is missing encryption key. Please set xpack.encryptedSavedObjects.encryptionKey in the kibana.yml or use the bin/kibana-encryption-keys command.` + ); + } + + try { + const spaceId = spaces && spaces.getSpaceId(request); + const rawAction = await encryptedSavedObjectsClient.getDecryptedAsInternalUser( + 'action', + actionId, + spaceId && spaceId !== 'default' ? { namespace: spaceId } : {} + ); + + secrets = rawAction.attributes.secrets; + } catch (err) { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + throw err; + } + throw err; + } + } + + try { + const actionType = actionTypeRegistry.get(actionTypeId!); + const configurationUtilities = actionTypeRegistry.getUtils(); + const validatedSecrets = validateSecrets(actionType, secrets, { configurationUtilities }); + + return await getAxiosInstanceWithAuth(validatedSecrets); + } catch (err) { + throw err; + } } diff --git a/x-pack/platform/plugins/shared/actions/server/plugin.ts b/x-pack/platform/plugins/shared/actions/server/plugin.ts index e0383773be529..ac1149acb4d07 100644 --- a/x-pack/platform/plugins/shared/actions/server/plugin.ts +++ b/x-pack/platform/plugins/shared/actions/server/plugin.ts @@ -216,6 +216,7 @@ export class ActionsPlugin private actionExecutor?: ActionExecutor; private licenseState: ILicenseState | null = null; private security?: SecurityPluginSetup; + private spaces?: SpacesPluginSetup; private eventLogService?: IEventLogService; private eventLogger?: IEventLogger; private isESOCanEncrypt?: boolean; @@ -304,6 +305,7 @@ export class ActionsPlugin this.actionTypeRegistry = actionTypeRegistry; this.actionExecutor = actionExecutor; this.security = plugins.security; + this.spaces = plugins.spaces; this.authTypeRegistry = new AuthTypeRegistry(); registerAuthTypes(this.authTypeRegistry); @@ -510,6 +512,9 @@ export class ActionsPlugin return plugins.eventLog.getClient(request); }, getAxiosInstanceWithAuth: this.getAxiosInstanceWithAuthHelper(actionsConfigUtils), + spaces: this.spaces?.spacesService, + isESOCanEncrypt: isESOCanEncrypt!, + encryptedSavedObjectsClient, }); }; @@ -750,6 +755,7 @@ export class ActionsPlugin usageCounter, logger, getAxiosInstanceWithAuthHelper, + spaces, } = this; return async function actionsRouteHandlerContext(context, request) { @@ -770,6 +776,10 @@ export class ActionsPlugin excludedExtensions: [SECURITY_EXTENSION_ID], includedHiddenTypes, }); + const encryptedSavedObjectsClient = encryptedSavedObjects.getClient({ + includedHiddenTypes, + }); + return new ActionsClient({ logger, unsecuredSavedObjectsClient, @@ -792,15 +802,16 @@ export class ActionsPlugin usageCounter, connectorTokenClient: new ConnectorTokenClient({ unsecuredSavedObjectsClient, - encryptedSavedObjectsClient: encryptedSavedObjects.getClient({ - includedHiddenTypes, - }), + encryptedSavedObjectsClient, logger, }), async getEventLogClient() { return eventLog.getClient(request); }, getAxiosInstanceWithAuth: getAxiosInstanceWithAuthHelper(actionsConfigUtils), + spaces: spaces?.spacesService, + isESOCanEncrypt: isESOCanEncrypt!, + encryptedSavedObjectsClient, }); }, listTypes: (featureId?: string) => { From ae62c6c78838b243919aada6f91c21281dcc69ea Mon Sep 17 00:00:00 2001 From: adcoelho Date: Fri, 28 Nov 2025 14:47:27 +0100 Subject: [PATCH 03/15] Error handling --- .../get_axios_instance/get_axios_instance.ts | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts index fb9bdee97036f..33bd8b007c312 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts @@ -13,7 +13,6 @@ import { ACTION_SAVED_OBJECT_TYPE } from '../../../../constants/saved_objects'; import type { ActionsClientContext } from '../../../../actions_client'; import { AxiosInstance } from 'axios'; import { validateSecrets } from '@kbn/actions-plugin/server/lib'; -import { SavedObjectsErrorHelpers } from '@kbn/core/server'; type ValidatedSecrets = Record; @@ -56,6 +55,7 @@ export async function getAxiosInstance( } } catch (err) { log.debug(`Failed to retrieve actionTypeId for action [${actionId}]`, err); + throw err; } await authorization.ensureAuthorized({ @@ -78,30 +78,19 @@ export async function getAxiosInstance( ); } - try { - const spaceId = spaces && spaces.getSpaceId(request); - const rawAction = await encryptedSavedObjectsClient.getDecryptedAsInternalUser( - 'action', - actionId, - spaceId && spaceId !== 'default' ? { namespace: spaceId } : {} - ); + const spaceId = spaces && spaces.getSpaceId(request); + const rawAction = await encryptedSavedObjectsClient.getDecryptedAsInternalUser( + 'action', + actionId, + spaceId && spaceId !== 'default' ? { namespace: spaceId } : {} + ); - secrets = rawAction.attributes.secrets; - } catch (err) { - if (SavedObjectsErrorHelpers.isNotFoundError(err)) { - throw err; - } - throw err; - } + secrets = rawAction.attributes.secrets; } - try { - const actionType = actionTypeRegistry.get(actionTypeId!); - const configurationUtilities = actionTypeRegistry.getUtils(); - const validatedSecrets = validateSecrets(actionType, secrets, { configurationUtilities }); + const actionType = actionTypeRegistry.get(actionTypeId!); + const configurationUtilities = actionTypeRegistry.getUtils(); + const validatedSecrets = validateSecrets(actionType, secrets, { configurationUtilities }); - return await getAxiosInstanceWithAuth(validatedSecrets); - } catch (err) { - throw err; - } + return await getAxiosInstanceWithAuth(validatedSecrets); } From 9bee84ff81bd14fd28cbdbec97187549a65ee2ef Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:58:13 +0000 Subject: [PATCH 04/15] Changes from node scripts/lint_ts_projects --fix --- x-pack/platform/plugins/shared/actions/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/platform/plugins/shared/actions/tsconfig.json b/x-pack/platform/plugins/shared/actions/tsconfig.json index 206c407956a1b..6fd2e1fa2c014 100644 --- a/x-pack/platform/plugins/shared/actions/tsconfig.json +++ b/x-pack/platform/plugins/shared/actions/tsconfig.json @@ -56,6 +56,7 @@ "@kbn/zod", "@kbn/connector-schemas", "@kbn/connector-specs", + "@kbn/encrypted-saved-objects-shared", ], "exclude": [ "target/**/*", From a222700b6ba9a7c38a699b8acddc1463f2aff5cc Mon Sep 17 00:00:00 2001 From: adcoelho Date: Mon, 1 Dec 2025 09:53:11 +0100 Subject: [PATCH 05/15] Fixing linting --- .../actions_client/actions_client.test.ts | 85 ++++++++++++++++++- .../actions_client_hooks.test.ts | 7 ++ .../connector/methods/get_all/get_all.test.ts | 34 ++++++++ .../methods/list_types/list_types.test.ts | 4 + 4 files changed, 129 insertions(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.test.ts b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.test.ts index 974b8afedc66c..8f82d15da1d47 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.test.ts @@ -92,6 +92,9 @@ const getEventLogClient = jest.fn(); const preSaveHook = jest.fn(); const postSaveHook = jest.fn(); const postDeleteHook = jest.fn(); +const encryptedSavedObjectsClient = encryptedSavedObjectsMock.createClient(); +const getAxiosInstanceWithAuth = jest.fn(); +const isESOCanEncrypt = true; let actionsClient: ActionsClient; let mockedLicenseState: jest.Mocked; @@ -147,6 +150,9 @@ beforeEach(() => { usageCounter: mockUsageCounter, connectorTokenClient, getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); (getOAuthJwtAccessToken as jest.Mock).mockResolvedValue(`Bearer jwttokentokentoken`); (getOAuthClientCredentialsAccessToken as jest.Mock).mockResolvedValue( @@ -564,6 +570,9 @@ describe('create()', () => { authorization: authorization as unknown as ActionsAuthorization, connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); const savedObjectCreateResult = { @@ -647,7 +656,9 @@ describe('create()', () => { }, }), ], - + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, actionExecutor, bulkExecutionEnqueuer, request, @@ -718,6 +729,9 @@ describe('create()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); await expect( @@ -780,6 +794,9 @@ describe('get()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); await actionsClient.get({ id: 'testPreconfigured' }); @@ -808,6 +825,9 @@ describe('get()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); await expect(actionsClient.get({ id: 'system-connector-.cases' })).rejects.toThrow(); @@ -866,6 +886,9 @@ describe('get()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); authorization.ensureAuthorized.mockRejectedValue( @@ -900,6 +923,9 @@ describe('get()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); authorization.ensureAuthorized.mockRejectedValue( @@ -1026,6 +1052,9 @@ describe('get()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); const result = await actionsClient.get({ id: 'testPreconfigured' }); @@ -1060,6 +1089,9 @@ describe('get()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); await expect( @@ -1088,6 +1120,9 @@ describe('get()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); expect( @@ -1154,6 +1189,9 @@ describe('getBulk()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); return actionsClient.getBulk({ ids: ['1', 'testPreconfigured'] }); } @@ -1299,6 +1337,9 @@ describe('getBulk()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); const result = await actionsClient.getBulk({ ids: ['1', 'testPreconfigured'] }); @@ -1378,6 +1419,9 @@ describe('getBulk()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); await expect( @@ -1444,6 +1488,9 @@ describe('getBulk()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); expect( @@ -1502,6 +1549,9 @@ describe('getOAuthAccessToken()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); return actionsClient.getOAuthAccessToken(requestBody, configurationUtilities); } @@ -1910,6 +1960,9 @@ describe('delete()', () => { authorization: authorization as unknown as ActionsAuthorization, connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); await expect( @@ -1940,6 +1993,9 @@ describe('delete()', () => { authorization: authorization as unknown as ActionsAuthorization, connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); await expect( @@ -2431,6 +2487,9 @@ describe('update()', () => { authorization: authorization as unknown as ActionsAuthorization, connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); await expect( @@ -2468,6 +2527,9 @@ describe('update()', () => { authorization: authorization as unknown as ActionsAuthorization, connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); await expect( @@ -2550,6 +2612,9 @@ describe('execute()', () => { usageCounter: mockUsageCounter, connectorTokenClient, getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); actionTypeRegistry.register( @@ -2606,6 +2671,9 @@ describe('execute()', () => { usageCounter: mockUsageCounter, connectorTokenClient, getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); actionTypeRegistry.register( @@ -2658,6 +2726,9 @@ describe('execute()', () => { usageCounter: mockUsageCounter, connectorTokenClient, getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); actionTypeRegistry.register( @@ -2942,6 +3013,9 @@ describe('isPreconfigured()', () => { logger, }), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); expect(actionsClient.isPreconfigured('testPreconfigured')).toEqual(true); @@ -2984,6 +3058,9 @@ describe('isPreconfigured()', () => { logger, }), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); expect(actionsClient.isPreconfigured(uuidv4())).toEqual(false); @@ -3028,6 +3105,9 @@ describe('isSystemAction()', () => { logger, }), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); expect(actionsClient.isSystemAction('system-connector-.cases')).toEqual(true); @@ -3070,6 +3150,9 @@ describe('isSystemAction()', () => { logger, }), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); expect(actionsClient.isSystemAction(uuidv4())).toEqual(false); diff --git a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client_hooks.test.ts b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client_hooks.test.ts index e050a14699940..710107f11a420 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client_hooks.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client_hooks.test.ts @@ -32,6 +32,7 @@ import { actionsAuthorizationMock } from '../authorization/actions_authorization import { connectorTokenClientMock } from '../lib/connector_token_client.mock'; import { inMemoryMetricsMock } from '../monitoring/in_memory_metrics.mock'; import { ConnectorRateLimiter } from '../lib/connector_rate_limiter'; +import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; jest.mock('uuid', () => ({ v4: () => ConnectorSavedObject.id, @@ -52,6 +53,9 @@ const getEventLogClient = jest.fn(); const preSaveHook = jest.fn(); const postSaveHook = jest.fn(); const postDeleteHook = jest.fn(); +const encryptedSavedObjectsClient = encryptedSavedObjectsMock.createClient(); +const getAxiosInstanceWithAuth = jest.fn(); +const isESOCanEncrypt = true; let actionsClient: ActionsClient; let mockedLicenseState: jest.Mocked; @@ -146,6 +150,9 @@ beforeEach(() => { usageCounter: mockUsageCounter, connectorTokenClient, getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); actionTypeRegistry.register({ diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_all/get_all.test.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_all/get_all.test.ts index bf07d7c1ecc7e..6ff08170ddc76 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_all/get_all.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_all/get_all.test.ts @@ -27,6 +27,7 @@ import type { ActionTypeRegistry } from '../../../../action_type_registry'; import { getAllUnsecured } from './get_all'; import type { InferenceInferenceEndpointInfo } from '@elastic/elasticsearch/lib/api/types'; import { createMockInMemoryConnector } from '../../mocks'; +import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; jest.mock('@kbn/core-saved-objects-utils-server', () => { const actual = jest.requireActual('@kbn/core-saved-objects-utils-server'); @@ -64,6 +65,9 @@ const eventLogClient = eventLogClientMock.create(); const getEventLogClient = jest.fn(); const connectorTokenClient = connectorTokenClientMock.create(); const internalSavedObjectsRepository = savedObjectsRepositoryMock.create(); +const encryptedSavedObjectsClient = encryptedSavedObjectsMock.createClient(); +const getAxiosInstanceWithAuth = jest.fn(); +const isESOCanEncrypt = true; let actionsClient: ActionsClient; const actionTypeRegistry: ActionTypeRegistry = jest.fn() as unknown as ActionTypeRegistry; @@ -87,6 +91,9 @@ describe('getAll()', () => { usageCounter: mockUsageCounter, connectorTokenClient, getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); (getOAuthJwtAccessToken as jest.Mock).mockResolvedValue(`Bearer jwttokentokentoken`); (getOAuthClientCredentialsAccessToken as jest.Mock).mockResolvedValue( @@ -151,6 +158,9 @@ describe('getAll()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); return actionsClient.getAll(); } @@ -304,6 +314,9 @@ describe('getAll()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); const result = await actionsClient.getAll(); @@ -388,6 +401,9 @@ describe('getAll()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); const result = await actionsClient.getAll({ includeSystemActions: true }); @@ -471,6 +487,9 @@ describe('getAll()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); const result = await actionsClient.getAll({ includeSystemActions: true }); @@ -545,6 +564,9 @@ describe('getAll()', () => { inMemoryConnectors: [], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); await actionsClient.getAll(); @@ -606,6 +628,9 @@ describe('getAll()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); const result = await actionsClient.getAll({ includeSystemActions: true }); @@ -677,6 +702,9 @@ describe('getAll()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); const result = await actionsClient.getAll({ includeSystemActions: true }); @@ -735,6 +763,9 @@ describe('getAll()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); return actionsClient.getAllSystemConnectors(); @@ -818,6 +849,9 @@ describe('getAll()', () => { ], connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, }); const result = await actionsClient.getAllSystemConnectors(); diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/list_types/list_types.test.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/list_types/list_types.test.ts index 88e4da37a9b7f..de51bcc53beda 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/list_types/list_types.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/list_types/list_types.test.ts @@ -27,6 +27,7 @@ import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ActionsClient } from '../../../../actions_client/actions_client'; import { ConnectorRateLimiter } from '../../../../lib/connector_rate_limiter'; import { getConnectorType } from '../../../../fixtures'; +import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; let mockedLicenseState: jest.Mocked; let actionTypeRegistryParams: ActionTypeRegistryOpts; @@ -68,6 +69,9 @@ describe('listTypes()', () => { authorization: actionsAuthorizationMock.create() as unknown as ActionsAuthorization, connectorTokenClient: connectorTokenClientMock.create(), getEventLogClient: jest.fn(), + encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(), + isESOCanEncrypt: true, + getAxiosInstanceWithAuth: jest.fn(), }); }); From 9c3d159e5ed119682364def86438b304b57c5f81 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:01:59 +0000 Subject: [PATCH 06/15] Changes from node scripts/regenerate_moon_projects.js --update --- x-pack/platform/plugins/shared/actions/moon.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/platform/plugins/shared/actions/moon.yml b/x-pack/platform/plugins/shared/actions/moon.yml index d2758350bffcc..128a5f42642a9 100644 --- a/x-pack/platform/plugins/shared/actions/moon.yml +++ b/x-pack/platform/plugins/shared/actions/moon.yml @@ -63,6 +63,7 @@ dependsOn: - '@kbn/zod' - '@kbn/connector-schemas' - '@kbn/connector-specs' + - '@kbn/encrypted-saved-objects-shared' tags: - plugin - prod From fe9e408c7f285f1babdfb529773e15c10b85c1b4 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:05:29 +0000 Subject: [PATCH 07/15] Changes from node scripts/eslint_all_files --no-cache --fix --- .../shared/actions/server/actions_client/actions_client.ts | 6 +++--- .../methods/get_axios_instance/get_axios_instance.ts | 4 ++-- .../plugins/shared/actions/server/lib/action_executor.ts | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts index 00629344d1911..d7473a53945bc 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts @@ -20,6 +20,9 @@ import type { import type { AuditLogger } from '@kbn/security-plugin/server'; import type { IEventLogClient } from '@kbn/event-log-plugin/server'; import type { KueryNode } from '@kbn/es-query'; +import type { AxiosInstance } from 'axios'; +import type { SpacesServiceSetup } from '@kbn/spaces-plugin/server'; +import type { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-shared'; import type { Connector, ConnectorWithExtraFindData } from '../application/connector/types'; import type { ConnectorType } from '../application/connector/types'; import { get } from '../application/connector/methods/get'; @@ -82,9 +85,6 @@ import { isSystemAction } from '../lib/is_system_action'; import type { ConnectorExecuteParams } from '../application/connector/methods/execute/types'; import { connectorFromInMemoryConnector } from '../application/connector/lib/connector_from_in_memory_connector'; import { getAxiosInstance } from '../application/connector/methods/get_axios_instance'; -import { AxiosInstance } from 'axios'; -import { SpacesServiceSetup } from '@kbn/spaces-plugin/server'; -import { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-shared'; export interface ConstructorOptions { logger: Logger; diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts index 33bd8b007c312..93ba8dc66480d 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts @@ -5,14 +5,14 @@ * 2.0. */ +import type { AxiosInstance } from 'axios'; import type { RawAction } from '../../../../types'; import { getActionKibanaPrivileges } from '../../../../lib/get_action_kibana_privileges'; import { isPreconfigured } from '../../../../lib/is_preconfigured'; import { isSystemAction } from '../../../../lib/is_system_action'; import { ACTION_SAVED_OBJECT_TYPE } from '../../../../constants/saved_objects'; import type { ActionsClientContext } from '../../../../actions_client'; -import { AxiosInstance } from 'axios'; -import { validateSecrets } from '@kbn/actions-plugin/server/lib'; +import { validateSecrets } from '../../../../lib'; type ValidatedSecrets = Record; diff --git a/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts b/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts index 1111b4fa8e2b9..76bed245384ca 100644 --- a/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts +++ b/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts @@ -21,6 +21,7 @@ import type { IEventLogger } from '@kbn/event-log-plugin/server'; import { SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/server'; import { createTaskRunError, TaskErrorSource } from '@kbn/task-manager-plugin/server'; import { getErrorSource } from '@kbn/task-manager-plugin/server/task_running'; +import type { AxiosInstance } from 'axios'; import { GEN_AI_TOKEN_COUNT_EVENT } from './event_based_telemetry'; import { ConnectorUsageCollector } from '../usage/connector_usage_collector'; import { @@ -56,7 +57,6 @@ import { createActionEventLogRecordObject } from './create_action_event_log_reco import { ActionExecutionError, ActionExecutionErrorReason } from './errors/action_execution_error'; import type { ActionsAuthorization } from '../authorization/actions_authorization'; import type { ConnectorRateLimiter } from './connector_rate_limiter'; -import { AxiosInstance } from 'axios'; // 1,000,000 nanoseconds in 1 millisecond const Millis2Nanos = 1000 * 1000; @@ -102,11 +102,11 @@ type ExecuteHelperOptions = Omit, 'requ spaceId?: string; }; -type GetAxiosInstanceParams = { +interface GetAxiosInstanceParams { actionId: string; request: KibanaRequest; getAxiosInstanceWithAuth: (validatedSecrets: Record) => Promise; -}; +} type UnsecuredExecuteOptions = Pick< ExecuteOptions, From 7d4df630fb725bac93cfee6c13cc1e4ad685910b Mon Sep 17 00:00:00 2001 From: adcoelho Date: Mon, 1 Dec 2025 14:04:53 +0100 Subject: [PATCH 08/15] Unit tests --- .../get_axios_instance.test.ts | 307 ++++++++++++++++++ .../get_axios_instance/get_axios_instance.ts | 5 +- 2 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts new file mode 100644 index 0000000000000..5e60cc529c42e --- /dev/null +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts @@ -0,0 +1,307 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import z from 'zod/v4'; + +import { loggerMock } from '@kbn/logging-mocks'; +import { ActionTypeRegistry } from '../../../../action_type_registry'; +import { ActionsClient } from '../../../../actions_client/actions_client'; +import { ActionExecutor, TaskRunnerFactory } from '../../../../lib'; +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { actionsConfigMock } from '../../../../actions_config.mock'; +import { licenseStateMock } from '../../../../lib/license_state.mock'; +import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; +import { + httpServerMock, + elasticsearchServiceMock, + savedObjectsClientMock, +} from '@kbn/core/server/mocks'; +import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; +import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; +import { actionExecutorMock } from '../../../../lib/action_executor.mock'; +import type { ActionsAuthorization } from '../../../../authorization/actions_authorization'; +import { actionsAuthorizationMock } from '../../../../authorization/actions_authorization.mock'; +import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; +import type { SavedObject } from '@kbn/core/server'; +import { connectorTokenClientMock } from '../../../../lib/connector_token_client.mock'; +import { inMemoryMetricsMock } from '../../../../monitoring/in_memory_metrics.mock'; +import { eventLogClientMock } from '@kbn/event-log-plugin/server/event_log_client.mock'; +import { ConnectorRateLimiter } from '../../../../lib/connector_rate_limiter'; +import { getConnectorType } from '../../../../fixtures'; +import { createMockInMemoryConnector } from '../../mocks'; + +const defaultConnectorTypeId = '.connector-type-id'; +const defaultConnectorId = 'connector-id'; +const inMemoryConnectorTypeId = '.in-memory-type-id'; +const inMemoryConnectorId = 'in-memory-id'; + +const kibanaIndices = ['.kibana']; +const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); +const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); +const actionExecutor = actionExecutorMock.create(); +const authorization = actionsAuthorizationMock.create(); +const bulkExecutionEnqueuer = jest.fn(); +const request = httpServerMock.createKibanaRequest(); +const auditLogger = auditLoggerMock.create(); +const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); +const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); +const taskManager = taskManagerMock.createSetup(); +const eventLogClient = eventLogClientMock.create(); +const getEventLogClient = jest.fn(); +const encryptedSavedObjectsClient = encryptedSavedObjectsMock.createClient(); +const getAxiosInstanceWithAuth = jest.fn(); +const isESOCanEncrypt = true; +const licenseState = licenseStateMock.create(); +const licensing = licensingMock.createSetup(); +const logger = loggerMock.create(); +const connectorTokenClient = connectorTokenClientMock.create(); +const inMemoryMetrics = inMemoryMetricsMock.create(); + +let actionsClient: ActionsClient; +let actionTypeRegistry: ActionTypeRegistry; + +const actionTypeIdFromSavedObjectMock = (actionTypeId = defaultConnectorTypeId) => { + return { + attributes: { + actionTypeId, + }, + } as SavedObject; +}; + +const connectorSavedObject = { + id: defaultConnectorId, + type: 'action', + attributes: { + name: '1', + actionTypeId: 'test', + config: { + bar: true, + }, + secrets: { + foobar: true, + }, + isMissingSecrets: false, + }, + references: [], +}; + +const inMemoryConnectors = [ + createMockInMemoryConnector({ + id: inMemoryConnectorId, + actionTypeId: inMemoryConnectorTypeId, + isPreconfigured: true, + secrets: { + foobar: true, + }, + }), +]; + +describe('execute()', () => { + beforeEach(() => { + jest.resetAllMocks(); + actionTypeRegistry = new ActionTypeRegistry({ + licensing, + taskManager, + taskRunnerFactory: new TaskRunnerFactory( + new ActionExecutor({ + isESOCanEncrypt, + connectorRateLimiter: new ConnectorRateLimiter({ + config: { email: { limit: 100, lookbackWindow: '1m' } }, + }), + }), + inMemoryMetrics + ), + actionsConfigUtils: actionsConfigMock.create(), + licenseState, + inMemoryConnectors, + }); + actionTypeRegistry.register( + getConnectorType({ + id: defaultConnectorTypeId, + isSystemActionType: true, + validate: { + config: { schema: z.object({}) }, + secrets: { schema: z.object({ foobar: z.boolean() }) }, + params: { schema: z.object({}) }, + }, + }) + ); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce( + connectorSavedObject + ); + actionsClient = new ActionsClient({ + logger, + actionTypeRegistry, + unsecuredSavedObjectsClient, + scopedClusterClient, + kibanaIndices, + inMemoryConnectors, + actionExecutor, + bulkExecutionEnqueuer, + request, + authorization: authorization as unknown as ActionsAuthorization, + auditLogger, + usageCounter: mockUsageCounter, + connectorTokenClient, + getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, + }); + getEventLogClient.mockResolvedValue(eventLogClient); + }); + + it('calls the getAxiosInstanceWithAuth with the connector secrets', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(actionTypeIdFromSavedObjectMock()); + await actionsClient.getAxiosInstance(defaultConnectorId); + expect(getAxiosInstanceWithAuth).toHaveBeenCalledWith({ + foobar: true, + }); + }); + + describe('inMemoryConnectors', () => { + it('calls the getAxiosInstanceWithAuth with the connector secrets for preconfigured inMemoryConnectors', async () => { + actionTypeRegistry.register( + getConnectorType({ + id: inMemoryConnectorTypeId, + validate: { + config: { schema: z.object({}) }, + secrets: { schema: z.object({ foobar: z.boolean() }) }, + params: { schema: z.object({}) }, + }, + }) + ); + await actionsClient.getAxiosInstance(inMemoryConnectorId); + expect(getAxiosInstanceWithAuth).toHaveBeenCalledWith({ + foobar: true, + }); + }); + + it('calls the getAxiosInstanceWithAuth with the connector secrets for system action inMemoryConnectors', async () => { + actionsClient = new ActionsClient({ + logger, + actionTypeRegistry, + unsecuredSavedObjectsClient, + scopedClusterClient, + kibanaIndices, + inMemoryConnectors: [ + createMockInMemoryConnector({ + id: inMemoryConnectorId, + actionTypeId: inMemoryConnectorTypeId, + isSystemAction: true, // TESTING THIS + secrets: { + foobar: true, + }, + }), + ], + actionExecutor, + bulkExecutionEnqueuer, + request, + authorization: authorization as unknown as ActionsAuthorization, + auditLogger, + usageCounter: mockUsageCounter, + connectorTokenClient, + getEventLogClient, + encryptedSavedObjectsClient, + isESOCanEncrypt, + getAxiosInstanceWithAuth, + }); + + actionTypeRegistry.register( + getConnectorType({ + id: inMemoryConnectorTypeId, + validate: { + config: { schema: z.object({}) }, + secrets: { schema: z.object({ foobar: z.boolean() }) }, + params: { schema: z.object({}) }, + }, + }) + ); + await actionsClient.getAxiosInstance(inMemoryConnectorId); + expect(getAxiosInstanceWithAuth).toHaveBeenCalledWith({ + foobar: true, + }); + }); + }); + + describe('authorization', () => { + it('ensures user is authorised to get an axios instance for execution', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(actionTypeIdFromSavedObjectMock()); + await actionsClient.getAxiosInstance(defaultConnectorId); + expect(authorization.ensureAuthorized).toHaveBeenCalledWith({ + actionTypeId: defaultConnectorTypeId, + operation: 'execute', + additionalPrivileges: [], + }); + }); + + it('throws when user is not authorised to get an axios instance for execution', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(actionTypeIdFromSavedObjectMock()); + authorization.ensureAuthorized.mockRejectedValue( + new Error(`Unauthorized to execute all actions`) + ); + + await expect( + actionsClient.getAxiosInstance(defaultConnectorId) + ).rejects.toMatchInlineSnapshot(`[Error: Unauthorized to execute all actions]`); + + expect(authorization.ensureAuthorized).toHaveBeenCalledWith({ + actionTypeId: defaultConnectorTypeId, + operation: 'execute', + additionalPrivileges: [], + }); + }); + + it('ensures that system actions privileges are being authorized correctly', async () => { + const newActionTypeId = '.foobar'; + actionTypeRegistry.register( + getConnectorType({ + id: newActionTypeId, + supportedFeatureIds: ['workflows'], + getKibanaPrivileges: () => ['test/other'], + isSystemActionType: true, + }) + ); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce( + actionTypeIdFromSavedObjectMock(newActionTypeId) + ); + + await actionsClient.getAxiosInstance(defaultConnectorId); + + expect(authorization.ensureAuthorized).toHaveBeenCalledWith({ + actionTypeId: newActionTypeId, + operation: 'execute', + additionalPrivileges: ['test/other'], + }); + }); + }); + + describe('validation', () => { + it('fails validation if secrets schema does not match saved values', async () => { + const newActionTypeId = '.validate-secrets'; + actionTypeRegistry.register( + getConnectorType({ + id: newActionTypeId, + validate: { + config: { schema: z.object({}) }, + secrets: { schema: z.object({ foobar: z.string() }) }, + params: { schema: z.object({}) }, + }, + }) + ); + + unsecuredSavedObjectsClient.get.mockResolvedValueOnce( + actionTypeIdFromSavedObjectMock(newActionTypeId) + ); + await expect(actionsClient.getAxiosInstance(defaultConnectorId)).rejects + .toMatchInlineSnapshot(` + [Error: error validating connector type secrets: ✖ Invalid input: expected string, received boolean + → at foobar] + `); + }); + }); +}); diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts index 93ba8dc66480d..147b2caaf73a9 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts @@ -36,7 +36,6 @@ export async function getAxiosInstance( } = context; let actionTypeId: string | undefined; - let secrets; try { if (isPreconfigured(context, actionId) || isSystemAction(context, actionId)) { @@ -64,11 +63,13 @@ export async function getAxiosInstance( actionTypeId, }); - // check to see if it's in memory connector first + // check to see if it's in memory connector before fetching secrets const inMemoryAction = inMemoryConnectors.find( (inMemoryConnector) => inMemoryConnector.id === actionId ); + let secrets; + if (inMemoryAction) { secrets = inMemoryAction.secrets; } else { From 7cafe3f97ff5760bf706edb45360a1fbb42c32c2 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Mon, 1 Dec 2025 14:05:22 +0100 Subject: [PATCH 09/15] Deleted unnecessary files --- .../methods/get_axios_instance/types/index.ts | 8 -------- .../methods/get_axios_instance/types/types.ts | 10 ---------- 2 files changed, 18 deletions(-) delete mode 100644 x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/index.ts delete mode 100644 x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/types.ts diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/index.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/index.ts deleted file mode 100644 index ff2bc6be97a80..0000000000000 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export type { ConnectorExecuteParams } from './types'; diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/types.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/types.ts deleted file mode 100644 index cd53f4574bebc..0000000000000 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/types/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { ExecuteOptions } from '../../../../../lib/action_executor'; - -export type ConnectorExecuteParams = Omit; From 2d47cc1108b4da917b0ded062dc77e0c15fb440e Mon Sep 17 00:00:00 2001 From: adcoelho Date: Mon, 1 Dec 2025 14:13:05 +0100 Subject: [PATCH 10/15] Revert changes to action_executor --- .../actions/server/lib/action_executor.ts | 46 ------------------- 1 file changed, 46 deletions(-) diff --git a/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts b/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts index 76bed245384ca..d04df86a2f8f3 100644 --- a/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts +++ b/x-pack/platform/plugins/shared/actions/server/lib/action_executor.ts @@ -21,7 +21,6 @@ import type { IEventLogger } from '@kbn/event-log-plugin/server'; import { SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/server'; import { createTaskRunError, TaskErrorSource } from '@kbn/task-manager-plugin/server'; import { getErrorSource } from '@kbn/task-manager-plugin/server/task_running'; -import type { AxiosInstance } from 'axios'; import { GEN_AI_TOKEN_COUNT_EVENT } from './event_based_telemetry'; import { ConnectorUsageCollector } from '../usage/connector_usage_collector'; import { @@ -102,12 +101,6 @@ type ExecuteHelperOptions = Omit, 'requ spaceId?: string; }; -interface GetAxiosInstanceParams { - actionId: string; - request: KibanaRequest; - getAxiosInstanceWithAuth: (validatedSecrets: Record) => Promise; -} - type UnsecuredExecuteOptions = Pick< ExecuteOptions, 'actionExecutionId' | 'actionId' | 'params' | 'relatedSavedObjects' | 'source' @@ -201,45 +194,6 @@ export class ActionExecutor { }); } - public async getAxiosInstance({ - actionId, - request, - getAxiosInstanceWithAuth, - }: GetAxiosInstanceParams): Promise { - if (!this.isInitialized) { - throw new Error('ActionExecutor not initialized'); - } - - const { spaces, actionTypeRegistry } = this.actionExecutorContext!; - const spaceId = spaces && spaces.getSpaceId(request); - const namespace = spaceId && spaceId !== 'default' ? { namespace: spaceId } : {}; - - const actionInfo = await this.getActionInfoInternal(actionId, namespace.namespace); - - const { actionTypeId, secrets } = actionInfo; - - if (!this.actionInfo || this.actionInfo.actionId !== actionId) { - this.actionInfo = actionInfo; - } - - const actionType = actionTypeRegistry.get(actionTypeId); - const configurationUtilities = actionTypeRegistry.getUtils(); - - let validatedSecrets; - try { - validatedSecrets = validateSecrets(actionType, secrets, { configurationUtilities }); - } catch (err) { - throw new ActionExecutionError(err.message, ActionExecutionErrorReason.Validation, { - actionId, - status: 'error', - message: err.message, - errorSource: TaskErrorSource.FRAMEWORK, - }); - } - - return await getAxiosInstanceWithAuth(validatedSecrets); - } - public async executeUnsecured({ actionExecutionId, actionId, From 9d3f368f07e7fd16fe6d48f382a43f1389875261 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:39:37 +0000 Subject: [PATCH 11/15] Changes from node scripts/eslint_all_files --no-cache --fix --- .../methods/get_axios_instance/get_axios_instance.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts index 5e60cc529c42e..a0098b417d0c3 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import z from 'zod/v4'; +import z from '@kbn/zod/v4'; import { loggerMock } from '@kbn/logging-mocks'; import { ActionTypeRegistry } from '../../../../action_type_registry'; From ea52abe85b4636281061565e04202a9d3224c991 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Tue, 2 Dec 2025 13:26:51 +0100 Subject: [PATCH 12/15] PR comments --- .../shared/actions/server/actions_client/actions_client.mock.ts | 1 + .../methods/get_axios_instance/get_axios_instance.test.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.mock.ts b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.mock.ts index 9834765487a80..a2b72fbfba417 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.mock.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.mock.ts @@ -29,6 +29,7 @@ const createActionsClientMock = () => { isSystemAction: jest.fn(), getGlobalExecutionKpiWithAuth: jest.fn(), getGlobalExecutionLogWithAuth: jest.fn(), + getAxiosInstance: jest.fn(), }; return mocked; }; diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts index a0098b417d0c3..58b50fbe274c2 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts @@ -100,7 +100,7 @@ const inMemoryConnectors = [ }), ]; -describe('execute()', () => { +describe('getAxiosInstance()', () => { beforeEach(() => { jest.resetAllMocks(); actionTypeRegistry = new ActionTypeRegistry({ From 6a0d29157388f585efa404171e29817c37410f90 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Wed, 3 Dec 2025 10:47:26 +0100 Subject: [PATCH 13/15] fix import that the bot broke --- .../methods/get_axios_instance/get_axios_instance.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts index 58b50fbe274c2..1fe1a8c7ae60b 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import z from '@kbn/zod/v4'; +import { z } from '@kbn/zod/v4'; import { loggerMock } from '@kbn/logging-mocks'; import { ActionTypeRegistry } from '../../../../action_type_registry'; From 205f2cb075e34f5b6535aeb06ad3d6b2b1283800 Mon Sep 17 00:00:00 2001 From: adcoelho Date: Wed, 3 Dec 2025 11:06:12 +0100 Subject: [PATCH 14/15] fix for changes from main --- .../server/actions_client/actions_client.ts | 9 ++++++-- .../get_axios_instance.test.ts | 12 ++++++++--- .../get_axios_instance/get_axios_instance.ts | 21 ++++++++++++------- .../plugins/shared/actions/server/plugin.ts | 4 ++-- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts index d7473a53945bc..1760c6c8ff610 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts @@ -85,6 +85,7 @@ import { isSystemAction } from '../lib/is_system_action'; import type { ConnectorExecuteParams } from '../application/connector/methods/execute/types'; import { connectorFromInMemoryConnector } from '../application/connector/lib/connector_from_in_memory_connector'; import { getAxiosInstance } from '../application/connector/methods/get_axios_instance'; +import { GetAxiosInstanceWithAuthFnOpts } from '../lib/get_axios_instance'; export interface ConstructorOptions { logger: Logger; @@ -102,7 +103,9 @@ export interface ConstructorOptions { usageCounter?: UsageCounter; connectorTokenClient: ConnectorTokenClientContract; getEventLogClient: () => Promise; - getAxiosInstanceWithAuth: (validatedSecrets: Record) => Promise; + getAxiosInstanceWithAuth: ( + getAxiosParams: GetAxiosInstanceWithAuthFnOpts + ) => Promise; spaces?: SpacesServiceSetup; isESOCanEncrypt: boolean; } @@ -123,7 +126,9 @@ export interface ActionsClientContext { usageCounter?: UsageCounter; connectorTokenClient: ConnectorTokenClientContract; getEventLogClient: () => Promise; - getAxiosInstanceWithAuth: (validatedSecrets: Record) => Promise; + getAxiosInstanceWithAuth: ( + getAxiosParams: GetAxiosInstanceWithAuthFnOpts + ) => Promise; spaces?: SpacesServiceSetup; isESOCanEncrypt: boolean; } diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts index 1fe1a8c7ae60b..bb3c6ef472882 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.test.ts @@ -159,7 +159,9 @@ describe('getAxiosInstance()', () => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce(actionTypeIdFromSavedObjectMock()); await actionsClient.getAxiosInstance(defaultConnectorId); expect(getAxiosInstanceWithAuth).toHaveBeenCalledWith({ - foobar: true, + connectorId: defaultConnectorId, + connectorTokenClient, + secrets: { foobar: true }, }); }); @@ -177,7 +179,9 @@ describe('getAxiosInstance()', () => { ); await actionsClient.getAxiosInstance(inMemoryConnectorId); expect(getAxiosInstanceWithAuth).toHaveBeenCalledWith({ - foobar: true, + connectorId: inMemoryConnectorId, + connectorTokenClient, + secrets: { foobar: true }, }); }); @@ -223,7 +227,9 @@ describe('getAxiosInstance()', () => { ); await actionsClient.getAxiosInstance(inMemoryConnectorId); expect(getAxiosInstanceWithAuth).toHaveBeenCalledWith({ - foobar: true, + connectorId: inMemoryConnectorId, + connectorTokenClient, + secrets: { foobar: true }, }); }); }); diff --git a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts index 147b2caaf73a9..a871255d77f25 100644 --- a/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts +++ b/x-pack/platform/plugins/shared/actions/server/application/connector/methods/get_axios_instance/get_axios_instance.ts @@ -20,7 +20,7 @@ export type GetAxiosInstanceWithAuthFn = (secrets: ValidatedSecrets) => Promise< export async function getAxiosInstance( context: ActionsClientContext, - actionId: string + connectorId: string ): Promise { const { actionTypeRegistry, @@ -33,27 +33,28 @@ export async function getAxiosInstance( request, spaces, unsecuredSavedObjectsClient, + connectorTokenClient, } = context; let actionTypeId: string | undefined; try { - if (isPreconfigured(context, actionId) || isSystemAction(context, actionId)) { + if (isPreconfigured(context, connectorId) || isSystemAction(context, connectorId)) { const connector = inMemoryConnectors.find( - (inMemoryConnector) => inMemoryConnector.id === actionId + (inMemoryConnector) => inMemoryConnector.id === connectorId ); actionTypeId = connector?.actionTypeId; } else { const { attributes } = await unsecuredSavedObjectsClient.get( ACTION_SAVED_OBJECT_TYPE, - actionId + connectorId ); actionTypeId = attributes.actionTypeId; } } catch (err) { - log.debug(`Failed to retrieve actionTypeId for action [${actionId}]`, err); + log.debug(`Failed to retrieve actionTypeId for action [${connectorId}]`, err); throw err; } @@ -65,7 +66,7 @@ export async function getAxiosInstance( // check to see if it's in memory connector before fetching secrets const inMemoryAction = inMemoryConnectors.find( - (inMemoryConnector) => inMemoryConnector.id === actionId + (inMemoryConnector) => inMemoryConnector.id === connectorId ); let secrets; @@ -82,7 +83,7 @@ export async function getAxiosInstance( const spaceId = spaces && spaces.getSpaceId(request); const rawAction = await encryptedSavedObjectsClient.getDecryptedAsInternalUser( 'action', - actionId, + connectorId, spaceId && spaceId !== 'default' ? { namespace: spaceId } : {} ); @@ -93,5 +94,9 @@ export async function getAxiosInstance( const configurationUtilities = actionTypeRegistry.getUtils(); const validatedSecrets = validateSecrets(actionType, secrets, { configurationUtilities }); - return await getAxiosInstanceWithAuth(validatedSecrets); + return await getAxiosInstanceWithAuth({ + connectorId, + connectorTokenClient, + secrets: validatedSecrets, + }); } diff --git a/x-pack/platform/plugins/shared/actions/server/plugin.ts b/x-pack/platform/plugins/shared/actions/server/plugin.ts index c6f3d472ff256..fdb6c48bff20c 100644 --- a/x-pack/platform/plugins/shared/actions/server/plugin.ts +++ b/x-pack/platform/plugins/shared/actions/server/plugin.ts @@ -842,8 +842,8 @@ export class ActionsPlugin logger: this.logger, }); - return async (validatedSecrets: Record) => { - return await getAxiosInstanceFn(validatedSecrets); + return async (getAxiosParams: GetAxiosInstanceWithAuthFnOpts) => { + return await getAxiosInstanceFn(getAxiosParams); }; }; From 0b1041098b57024e5440cb191036f7386114b9d6 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 3 Dec 2025 10:30:28 +0000 Subject: [PATCH 15/15] Changes from node scripts/eslint_all_files --no-cache --fix --- .../shared/actions/server/actions_client/actions_client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts index 1760c6c8ff610..39c9f3dd19bb6 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_client/actions_client.ts @@ -85,7 +85,7 @@ import { isSystemAction } from '../lib/is_system_action'; import type { ConnectorExecuteParams } from '../application/connector/methods/execute/types'; import { connectorFromInMemoryConnector } from '../application/connector/lib/connector_from_in_memory_connector'; import { getAxiosInstance } from '../application/connector/methods/get_axios_instance'; -import { GetAxiosInstanceWithAuthFnOpts } from '../lib/get_axios_instance'; +import type { GetAxiosInstanceWithAuthFnOpts } from '../lib/get_axios_instance'; export interface ConstructorOptions { logger: Logger;