[Response Ops][Actions] Prepare connector listTypes HTTP API for versioning (#162830)

Towards https://github.com/elastic/response-ops-team/issues/125

## Summary

Preparing the `GET ${BASE_ACTION_API_PATH}/connector_types` HTTP API for
versioning

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Ying Mao 2023-08-30 08:50:00 -04:00 committed by GitHub
parent 4509cbeaa3
commit f35ecc6f96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 609 additions and 283 deletions

View file

@ -0,0 +1,12 @@
/*
* 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 { connectorTypesQuerySchema } from './schemas/latest';
export type { ConnectorTypesRequestQuery } from './types/latest';
export { connectorTypesQuerySchema as connectorTypesQuerySchemaV1 } from './schemas/v1';
export type { ConnectorTypesRequestQuery as ConnectorTypesRequestQueryV1 } from './types/v1';

View file

@ -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 * from './v1';

View file

@ -0,0 +1,12 @@
/*
* 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 { schema } from '@kbn/config-schema';
export const connectorTypesQuerySchema = schema.object({
feature_id: schema.maybe(schema.string()),
});

View file

@ -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 * from './v1';

View file

@ -0,0 +1,11 @@
/*
* 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 { TypeOf } from '@kbn/config-schema';
import { connectorTypesQuerySchemaV1 } from '..';
export type ConnectorTypesRequestQuery = TypeOf<typeof connectorTypesQuerySchemaV1>;

View file

@ -8,6 +8,7 @@
// Latest
export type { ConnectorResponse, ActionTypeConfig } from './types/latest';
export { connectorResponseSchema } from './schemas/latest';
export { connectorTypesResponseSchema } from './schemas/latest';
// v1
export type {
@ -15,3 +16,5 @@ export type {
ActionTypeConfig as ActionTypeConfigV1,
} from './types/v1';
export { connectorResponseSchema as connectorResponseSchemaV1 } from './schemas/v1';
export type { ConnectorTypesResponse as ConnectorTypesResponseV1 } from './types/v1';
export { connectorTypesResponseSchema as connectorTypesResponseSchemaV1 } from './schemas/v1';

View file

@ -6,3 +6,4 @@
*/
export { connectorResponseSchema } from './v1';
export { connectorTypesResponseSchema } from './v1';

View file

@ -18,3 +18,21 @@ export const connectorResponseSchema = schema.object({
is_system_action: schema.boolean(),
referenced_by_count: schema.number(),
});
export const connectorTypesResponseSchema = schema.object({
id: schema.string(),
name: schema.string(),
enabled: schema.boolean(),
enabled_in_config: schema.boolean(),
enabled_in_license: schema.boolean(),
minimum_license_required: schema.oneOf([
schema.literal('basic'),
schema.literal('standard'),
schema.literal('gold'),
schema.literal('platinum'),
schema.literal('enterprise'),
schema.literal('trial'),
]),
supported_feature_ids: schema.arrayOf(schema.string()),
is_system_action_type: schema.boolean(),
});

View file

@ -6,7 +6,7 @@
*/
import { TypeOf } from '@kbn/config-schema';
import { connectorResponseSchemaV1 } from '..';
import { connectorResponseSchemaV1, connectorTypesResponseSchemaV1 } from '..';
export type ActionTypeConfig = Record<string, unknown>;
type ConnectorResponseSchemaType = TypeOf<typeof connectorResponseSchemaV1>;
@ -22,3 +22,15 @@ export interface ConnectorResponse<Config extends ActionTypeConfig = ActionTypeC
is_system_action: ConnectorResponseSchemaType['is_system_action'];
referenced_by_count: ConnectorResponseSchemaType['referenced_by_count'];
}
type ConnectorTypesResponseSchemaType = TypeOf<typeof connectorTypesResponseSchemaV1>;
export interface ConnectorTypesResponse {
id: ConnectorTypesResponseSchemaType['id'];
name: ConnectorTypesResponseSchemaType['name'];
enabled: ConnectorTypesResponseSchemaType['enabled'];
enabled_in_config: ConnectorTypesResponseSchemaType['enabled_in_config'];
enabled_in_license: ConnectorTypesResponseSchemaType['enabled_in_license'];
minimum_license_required: ConnectorTypesResponseSchemaType['minimum_license_required'];
supported_feature_ids: ConnectorTypesResponseSchemaType['supported_feature_ids'];
is_system_action_type: ConnectorTypesResponseSchemaType['is_system_action_type'];
}

View file

@ -3233,172 +3233,6 @@ describe('bulkEnqueueExecution()', () => {
});
});
describe('listType()', () => {
it('filters action types by feature ID', async () => {
mockedLicenseState.isLicenseValidForActionType.mockReturnValue({ isValid: true });
actionTypeRegistry.register({
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
actionTypeRegistry.register({
id: 'my-action-type-2',
name: 'My action type 2',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['cases'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
expect(await actionsClient.listTypes({ featureId: 'alerting' })).toEqual([
{
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
enabled: true,
enabledInConfig: true,
enabledInLicense: true,
supportedFeatureIds: ['alerting'],
isSystemActionType: false,
},
]);
});
it('filters out system action types when not defining options', async () => {
mockedLicenseState.isLicenseValidForActionType.mockReturnValue({ isValid: true });
actionTypeRegistry.register({
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
actionTypeRegistry.register({
id: 'my-action-type-2',
name: 'My action type 2',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['cases'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
actionTypeRegistry.register({
id: '.cases',
name: 'Cases',
minimumLicenseRequired: 'platinum',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
isSystemActionType: true,
executor,
});
expect(await actionsClient.listTypes()).toEqual([
{
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
enabled: true,
enabledInConfig: true,
enabledInLicense: true,
supportedFeatureIds: ['alerting'],
isSystemActionType: false,
},
{
id: 'my-action-type-2',
name: 'My action type 2',
isSystemActionType: false,
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['cases'],
enabled: true,
enabledInConfig: true,
enabledInLicense: true,
},
]);
});
it('return system action types when defining options', async () => {
mockedLicenseState.isLicenseValidForActionType.mockReturnValue({ isValid: true });
actionTypeRegistry.register({
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
actionTypeRegistry.register({
id: '.cases',
name: 'Cases',
minimumLicenseRequired: 'platinum',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
isSystemActionType: true,
executor,
});
expect(await actionsClient.listTypes({ includeSystemActionTypes: true })).toEqual([
{
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
enabled: true,
enabledInConfig: true,
enabledInLicense: true,
supportedFeatureIds: ['alerting'],
isSystemActionType: false,
},
{
id: '.cases',
name: 'Cases',
isSystemActionType: true,
minimumLicenseRequired: 'platinum',
supportedFeatureIds: ['alerting'],
enabled: true,
enabledInConfig: true,
enabledInLicense: true,
},
]);
});
});
describe('isActionTypeEnabled()', () => {
const fooActionType: ActionType = {
id: 'foo',

View file

@ -25,9 +25,10 @@ import { RunNowResult } from '@kbn/task-manager-plugin/server';
import { IEventLogClient } from '@kbn/event-log-plugin/server';
import { KueryNode } from '@kbn/es-query';
import { FindConnectorResult } from '../application/connector/types';
import { ConnectorType } from '../application/connector/types';
import { getAll } from '../application/connector/methods/get_all';
import { listTypes } from '../application/connector/methods/list_types';
import {
ActionType,
GetGlobalExecutionKPIParams,
GetGlobalExecutionLogParams,
IExecutionLogResult,
@ -48,7 +49,6 @@ import {
ActionTypeExecutorResult,
ConnectorTokenClientContract,
} from '../types';
import { PreconfiguredActionDisabledModificationError } from '../lib/errors/preconfigured_action_disabled_modification';
import { ExecuteOptions } from '../lib/action_executor';
import {
@ -88,6 +88,7 @@ import {
getExecutionLogAggregation,
} from '../lib/get_execution_log_aggregation';
import { connectorFromSavedObject, isConnectorDeprecated } from '../application/connector/lib';
import { ListTypesParams } from '../application/connector/methods/list_types/types';
interface ActionUpdate {
name: string;
@ -104,7 +105,7 @@ export interface CreateOptions {
options?: { id?: string };
}
interface ConstructorOptions {
export interface ConstructorOptions {
logger: Logger;
kibanaIndices: string[];
scopedClusterClient: IScopedClusterClient;
@ -128,11 +129,6 @@ export interface UpdateOptions {
action: ActionUpdate;
}
interface ListTypesOptions {
featureId?: string;
includeSystemActionTypes?: boolean;
}
export interface ActionsClientContext {
logger: Logger;
kibanaIndices: string[];
@ -839,21 +835,11 @@ export class ActionsClient {
);
}
/**
* Return all available action types
* expect system action types
*/
public async listTypes({
featureId,
includeSystemActionTypes = false,
}: ListTypesOptions = {}): Promise<ActionType[]> {
const actionTypes = this.context.actionTypeRegistry.list(featureId);
const filteredActionTypes = includeSystemActionTypes
? actionTypes
: actionTypes.filter((actionType) => !Boolean(actionType.isSystemActionType));
return filteredActionTypes;
}: ListTypesParams = {}): Promise<ConnectorType[]> {
return listTypes(this.context, { featureId, includeSystemActionTypes });
}
public isActionTypeEnabled(

View file

@ -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 { listTypes } from './list_types';

View file

@ -0,0 +1,236 @@
/*
* 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 { actionsConfigMock } from '../../../../actions_config.mock';
import { ActionTypeRegistry, ActionTypeRegistryOpts } from '../../../../action_type_registry';
import { ActionsAuthorization } from '../../../../authorization/actions_authorization';
import { ActionExecutor, ILicenseState, TaskRunnerFactory } from '../../../../lib';
import { actionExecutorMock } from '../../../../lib/action_executor.mock';
import { connectorTokenClientMock } from '../../../../lib/connector_token_client.mock';
import { licenseStateMock } from '../../../../lib/license_state.mock';
import { actionsAuthorizationMock } from '../../../../mocks';
import { inMemoryMetricsMock } from '../../../../monitoring/in_memory_metrics.mock';
import { schema } from '@kbn/config-schema';
import {
httpServerMock,
loggingSystemMock,
elasticsearchServiceMock,
savedObjectsClientMock,
} from '@kbn/core/server/mocks';
import { licensingMock } from '@kbn/licensing-plugin/server/mocks';
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
import { ActionsClient } from '../../../../actions_client/actions_client';
import { ExecutorType } from '../../../../types';
let mockedLicenseState: jest.Mocked<ILicenseState>;
let actionTypeRegistryParams: ActionTypeRegistryOpts;
let actionTypeRegistry: ActionTypeRegistry;
const executor: ExecutorType<{}, {}, {}, void> = async (options) => {
return { status: 'ok', actionId: options.actionId };
};
describe('listTypes()', () => {
let actionsClient: ActionsClient;
beforeEach(async () => {
jest.resetAllMocks();
mockedLicenseState = licenseStateMock.create();
actionTypeRegistryParams = {
licensing: licensingMock.createSetup(),
taskManager: taskManagerMock.createSetup(),
taskRunnerFactory: new TaskRunnerFactory(
new ActionExecutor({ isESOCanEncrypt: true }),
inMemoryMetricsMock.create()
),
actionsConfigUtils: actionsConfigMock.create(),
licenseState: mockedLicenseState,
inMemoryConnectors: [],
};
actionTypeRegistry = new ActionTypeRegistry(actionTypeRegistryParams);
actionsClient = new ActionsClient({
logger: loggingSystemMock.create().get(),
kibanaIndices: ['.kibana'],
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
actionTypeRegistry,
unsecuredSavedObjectsClient: savedObjectsClientMock.create(),
inMemoryConnectors: [],
actionExecutor: actionExecutorMock.create(),
executionEnqueuer: jest.fn(),
ephemeralExecutionEnqueuer: jest.fn(),
bulkExecutionEnqueuer: jest.fn(),
request: httpServerMock.createKibanaRequest(),
authorization: actionsAuthorizationMock.create() as unknown as ActionsAuthorization,
connectorTokenClient: connectorTokenClientMock.create(),
getEventLogClient: jest.fn(),
});
});
it('filters action types by feature ID', async () => {
mockedLicenseState.isLicenseValidForActionType.mockReturnValue({ isValid: true });
actionTypeRegistry.register({
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
actionTypeRegistry.register({
id: 'my-action-type-2',
name: 'My action type 2',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['cases'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
expect(await actionsClient.listTypes({ featureId: 'alerting' })).toEqual([
{
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
enabled: true,
enabledInConfig: true,
enabledInLicense: true,
supportedFeatureIds: ['alerting'],
isSystemActionType: false,
},
]);
});
it('filters out system action types when not defining options', async () => {
mockedLicenseState.isLicenseValidForActionType.mockReturnValue({ isValid: true });
actionTypeRegistry.register({
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
actionTypeRegistry.register({
id: 'my-action-type-2',
name: 'My action type 2',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['cases'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
actionTypeRegistry.register({
id: '.cases',
name: 'Cases',
minimumLicenseRequired: 'platinum',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
isSystemActionType: true,
executor,
});
expect(await actionsClient.listTypes({})).toEqual([
{
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
enabled: true,
enabledInConfig: true,
enabledInLicense: true,
supportedFeatureIds: ['alerting'],
isSystemActionType: false,
},
{
id: 'my-action-type-2',
name: 'My action type 2',
isSystemActionType: false,
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['cases'],
enabled: true,
enabledInConfig: true,
enabledInLicense: true,
},
]);
});
it('return system action types when defining options', async () => {
mockedLicenseState.isLicenseValidForActionType.mockReturnValue({ isValid: true });
actionTypeRegistry.register({
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
actionTypeRegistry.register({
id: '.cases',
name: 'Cases',
minimumLicenseRequired: 'platinum',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
isSystemActionType: true,
executor,
});
expect(await actionsClient.listTypes({ includeSystemActionTypes: true })).toEqual([
{
id: 'my-action-type',
name: 'My action type',
minimumLicenseRequired: 'basic',
enabled: true,
enabledInConfig: true,
enabledInLicense: true,
supportedFeatureIds: ['alerting'],
isSystemActionType: false,
},
{
id: '.cases',
name: 'Cases',
isSystemActionType: true,
minimumLicenseRequired: 'platinum',
supportedFeatureIds: ['alerting'],
enabled: true,
enabledInConfig: true,
enabledInLicense: true,
},
]);
});
});

View file

@ -0,0 +1,33 @@
/*
* 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 Boom from '@hapi/boom';
import { ActionsClientContext } from '../../../../actions_client';
import { ConnectorType } from '../../types';
import { listTypesParamsSchema } from './schemas';
import { ListTypesParams } from './types';
export async function listTypes(
context: ActionsClientContext,
options: ListTypesParams
): Promise<ConnectorType[]> {
try {
listTypesParamsSchema.validate(options);
} catch (error) {
throw Boom.badRequest(`Error validating params - ${error.message}`);
}
const { featureId, includeSystemActionTypes } = options;
const connectorTypes = context.actionTypeRegistry.list(featureId);
const filteredConnectorTypes = includeSystemActionTypes
? connectorTypes
: connectorTypes.filter((type) => !Boolean(type.isSystemActionType));
return filteredConnectorTypes;
}

View file

@ -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 { listTypesParamsSchema } from './list_types_params_schema';

View file

@ -0,0 +1,13 @@
/*
* 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 { schema } from '@kbn/config-schema';
export const listTypesParamsSchema = schema.object({
featureId: schema.maybe(schema.string()),
includeSystemActionTypes: schema.maybe(schema.boolean()),
});

View file

@ -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 { ListTypesParams } from './list_types_params';

View file

@ -0,0 +1,16 @@
/*
* 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 { TypeOf } from '@kbn/config-schema';
import { listTypesParamsSchema } from '../schemas';
type ListTypesParamsType = TypeOf<typeof listTypesParamsSchema>;
export interface ListTypesParams {
featureId?: ListTypesParamsType['featureId'];
includeSystemActionTypes?: ListTypesParamsType['includeSystemActionTypes'];
}

View file

@ -0,0 +1,26 @@
/*
* 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 { schema } from '@kbn/config-schema';
export const connectorTypeSchema = schema.object({
id: schema.string(),
name: schema.string(),
enabled: schema.boolean(),
enabledInConfig: schema.boolean(),
enabledInLicense: schema.boolean(),
minimumLicenseRequired: schema.oneOf([
schema.literal('basic'),
schema.literal('standard'),
schema.literal('gold'),
schema.literal('platinum'),
schema.literal('enterprise'),
schema.literal('trial'),
]),
supportedFeatureIds: schema.arrayOf(schema.string()),
isSystemActionType: schema.boolean(),
});

View file

@ -6,3 +6,4 @@
*/
export * from './connector_schema';
export * from './connector_type_schema';

View file

@ -0,0 +1,22 @@
/*
* 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 { TypeOf } from '@kbn/config-schema';
import { connectorTypeSchema } from '../schemas';
type ConnectorTypeSchemaType = TypeOf<typeof connectorTypeSchema>;
export interface ConnectorType {
id: ConnectorTypeSchemaType['id'];
name: ConnectorTypeSchemaType['name'];
enabled: ConnectorTypeSchemaType['enabled'];
enabledInConfig: ConnectorTypeSchemaType['enabledInConfig'];
enabledInLicense: ConnectorTypeSchemaType['enabledInLicense'];
minimumLicenseRequired: ConnectorTypeSchemaType['minimumLicenseRequired'];
supportedFeatureIds: ConnectorTypeSchemaType['supportedFeatureIds'];
isSystemActionType: ConnectorTypeSchemaType['isSystemActionType'];
}

View file

@ -6,3 +6,4 @@
*/
export type { Connector, FindConnectorResult } from './connector';
export type { ConnectorType } from './connector_type';

View file

@ -12,7 +12,7 @@ import {
} from '@kbn/core/server/mocks';
import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks';
import { Logger } from '@kbn/core/server';
import { actionsClientMock } from './actions_client.mock';
import { actionsClientMock } from './actions_client/actions_client.mock';
import { PluginSetupContract, PluginStartContract, renderActionParameterTemplates } from './plugin';
import { Services } from './types';
import { actionsAuthorizationMock } from './authorization/actions_authorization.mock';

View file

@ -42,7 +42,7 @@ import { MonitoringCollectionSetup } from '@kbn/monitoring-collection-plugin/ser
import { ActionsConfig, getValidatedConfig } from './config';
import { resolveCustomHosts } from './lib/custom_host_settings';
import { ActionsClient } from './actions_client';
import { ActionsClient } from './actions_client/actions_client';
import { ActionTypeRegistry } from './action_type_registry';
import {
createExecutionEnqueuerFunction,

View file

@ -10,7 +10,7 @@ import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../../../lib/license_state.mock';
import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments';
import { verifyAccessAndContext } from '../../verify_access_and_context';
import { actionsClientMock } from '../../../actions_client.mock';
import { actionsClientMock } from '../../../actions_client/actions_client.mock';
jest.mock('../../verify_access_and_context', () => ({
verifyAccessAndContext: jest.fn(),

View file

@ -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 { listTypesRoute } from './list_types';

View file

@ -5,15 +5,15 @@
* 2.0.
*/
import { connectorTypesRoute } from './connector_types';
import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './legacy/_mock_handler_arguments';
import { LicenseType } from '@kbn/licensing-plugin/server';
import { actionsClientMock } from '../mocks';
import { verifyAccessAndContext } from './verify_access_and_context';
import { licenseStateMock } from '../../../lib/license_state.mock';
import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments';
import { listTypesRoute } from './list_types';
import { verifyAccessAndContext } from '../../verify_access_and_context';
import { actionsClientMock } from '../../../mocks';
jest.mock('./verify_access_and_context', () => ({
jest.mock('../../verify_access_and_context', () => ({
verifyAccessAndContext: jest.fn(),
}));
@ -22,12 +22,12 @@ beforeEach(() => {
(verifyAccessAndContext as jest.Mock).mockImplementation((license, handler) => handler);
});
describe('connectorTypesRoute', () => {
describe('listTypesRoute', () => {
it('lists action types with proper parameters', async () => {
const licenseState = licenseStateMock.create();
const router = httpServiceMock.createRouter();
connectorTypesRoute(router, licenseState);
listTypesRoute(router, licenseState);
const [config, handler] = router.get.mock.calls[0];
@ -89,7 +89,7 @@ describe('connectorTypesRoute', () => {
const licenseState = licenseStateMock.create();
const router = httpServiceMock.createRouter();
connectorTypesRoute(router, licenseState);
listTypesRoute(router, licenseState);
const [config, handler] = router.get.mock.calls[0];
@ -168,7 +168,7 @@ describe('connectorTypesRoute', () => {
const licenseState = licenseStateMock.create();
const router = httpServiceMock.createRouter();
connectorTypesRoute(router, licenseState);
listTypesRoute(router, licenseState);
const [config, handler] = router.get.mock.calls[0];
@ -211,7 +211,7 @@ describe('connectorTypesRoute', () => {
throw new Error('OMG');
});
connectorTypesRoute(router, licenseState);
listTypesRoute(router, licenseState);
const [config, handler] = router.get.mock.calls[0];

View file

@ -0,0 +1,47 @@
/*
* 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 { IRouter } from '@kbn/core/server';
import { ConnectorTypesResponseV1 } from '../../../../common/routes/connector/response';
import {
connectorTypesQuerySchemaV1,
ConnectorTypesRequestQueryV1,
} from '../../../../common/routes/connector/apis/connector_types';
import { transformListTypesResponseV1 } from './transforms';
import { ActionsRequestHandlerContext } from '../../../types';
import { BASE_ACTION_API_PATH } from '../../../../common';
import { ILicenseState } from '../../../lib';
import { verifyAccessAndContext } from '../../verify_access_and_context';
export const listTypesRoute = (
router: IRouter<ActionsRequestHandlerContext>,
licenseState: ILicenseState
) => {
router.get(
{
path: `${BASE_ACTION_API_PATH}/connector_types`,
validate: {
query: connectorTypesQuerySchemaV1,
},
},
router.handleLegacyErrors(
verifyAccessAndContext(licenseState, async function (context, req, res) {
const actionsClient = (await context.actions).getActionsClient();
// Assert versioned inputs
const query: ConnectorTypesRequestQueryV1 = req.query;
const connectorTypes = await actionsClient.listTypes({ featureId: query?.feature_id });
const responseBody: ConnectorTypesResponseV1[] =
transformListTypesResponseV1(connectorTypes);
return res.ok({ body: responseBody });
})
)
);
};

View file

@ -0,0 +1,9 @@
/*
* 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 { transformListTypesResponse } from './transform_list_types_response/latest';
export { transformListTypesResponse as transformListTypesResponseV1 } from './transform_list_types_response/v1';

View file

@ -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 { transformListTypesResponse } from './v1';

View file

@ -0,0 +1,35 @@
/*
* 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 { ConnectorType } from '../../../../../application/connector/types';
import { ConnectorTypesResponseV1 } from '../../../../../../common/routes/connector/response';
export const transformListTypesResponse = (
results: ConnectorType[]
): ConnectorTypesResponseV1[] => {
return results.map(
({
id,
name,
enabled,
enabledInConfig,
enabledInLicense,
minimumLicenseRequired,
supportedFeatureIds,
isSystemActionType,
}) => ({
id,
name,
enabled,
enabled_in_config: enabledInConfig,
enabled_in_license: enabledInLicense,
minimum_license_required: minimumLicenseRequired,
supported_feature_ids: supportedFeatureIds,
is_system_action_type: isSystemActionType,
})
);
};

View file

@ -1,59 +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 { IRouter } from '@kbn/core/server';
import { schema } from '@kbn/config-schema';
import { ILicenseState } from '../lib';
import { ActionType, BASE_ACTION_API_PATH, RewriteResponseCase } from '../../common';
import { ActionsRequestHandlerContext } from '../types';
import { verifyAccessAndContext } from './verify_access_and_context';
const querySchema = schema.object({
feature_id: schema.maybe(schema.string()),
});
const rewriteBodyRes: RewriteResponseCase<ActionType[]> = (results) => {
return results.map(
({
enabledInConfig,
enabledInLicense,
minimumLicenseRequired,
supportedFeatureIds,
isSystemActionType,
...res
}) => ({
...res,
enabled_in_config: enabledInConfig,
enabled_in_license: enabledInLicense,
minimum_license_required: minimumLicenseRequired,
supported_feature_ids: supportedFeatureIds,
is_system_action_type: isSystemActionType,
})
);
};
export const connectorTypesRoute = (
router: IRouter<ActionsRequestHandlerContext>,
licenseState: ILicenseState
) => {
router.get(
{
path: `${BASE_ACTION_API_PATH}/connector_types`,
validate: {
query: querySchema,
},
},
router.handleLegacyErrors(
verifyAccessAndContext(licenseState, async function (context, req, res) {
const actionsClient = (await context.actions).getActionsClient();
return res.ok({
body: rewriteBodyRes(await actionsClient.listTypes({ featureId: req.query?.feature_id })),
});
})
)
);
};

View file

@ -9,9 +9,9 @@ import { createActionRoute, bodySchema } from './create';
import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './legacy/_mock_handler_arguments';
import { actionsClientMock } from '../actions_client.mock';
import { verifyAccessAndContext } from './verify_access_and_context';
import { omit } from 'lodash';
import { actionsClientMock } from '../actions_client/actions_client.mock';
jest.mock('./verify_access_and_context', () => ({
verifyAccessAndContext: jest.fn(),

View file

@ -10,7 +10,7 @@ import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './legacy/_mock_handler_arguments';
import { asHttpRequestExecutionSource } from '../lib';
import { actionsClientMock } from '../actions_client.mock';
import { actionsClientMock } from '../actions_client/actions_client.mock';
import { ActionTypeExecutorResult } from '../types';
import { verifyAccessAndContext } from './verify_access_and_context';

View file

@ -9,7 +9,7 @@ import { getActionRoute } from './get';
import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './legacy/_mock_handler_arguments';
import { actionsClientMock } from '../actions_client.mock';
import { actionsClientMock } from '../actions_client/actions_client.mock';
import { verifyAccessAndContext } from './verify_access_and_context';
jest.mock('./verify_access_and_context', () => ({

View file

@ -8,7 +8,7 @@
import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './legacy/_mock_handler_arguments';
import { actionsClientMock } from '../actions_client.mock';
import { actionsClientMock } from '../actions_client/actions_client.mock';
import { getGlobalExecutionKPIRoute } from './get_global_execution_kpi';
import { verifyAccessAndContext } from './verify_access_and_context';

View file

@ -9,7 +9,7 @@ import { getGlobalExecutionLogRoute } from './get_global_execution_logs';
import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './legacy/_mock_handler_arguments';
import { actionsClientMock } from '../actions_client.mock';
import { actionsClientMock } from '../actions_client/actions_client.mock';
import { IExecutionLogResult } from '../../common';
import { verifyAccessAndContext } from './verify_access_and_context';

View file

@ -11,7 +11,7 @@ import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './legacy/_mock_handler_arguments';
import { verifyAccessAndContext } from './verify_access_and_context';
import { actionsConfigMock } from '../actions_config.mock';
import { actionsClientMock } from '../actions_client.mock';
import { actionsClientMock } from '../actions_client/actions_client.mock';
jest.mock('./verify_access_and_context', () => ({
verifyAccessAndContext: jest.fn(),

View file

@ -8,13 +8,13 @@
import { IRouter } from '@kbn/core/server';
import { UsageCounter } from '@kbn/usage-collection-plugin/server';
import { getAllConnectorsRoute } from './connector/get_all';
import { listTypesRoute } from './connector/list_types';
import { ILicenseState } from '../lib';
import { ActionsRequestHandlerContext } from '../types';
import { createActionRoute } from './create';
import { deleteActionRoute } from './delete';
import { executeActionRoute } from './execute';
import { getActionRoute } from './get';
import { connectorTypesRoute } from './connector_types';
import { updateActionRoute } from './update';
import { getOAuthAccessToken } from './get_oauth_access_token';
import { defineLegacyRoutes } from './legacy';
@ -39,7 +39,7 @@ export function defineRoutes(opts: RouteOptions) {
getActionRoute(router, licenseState);
getAllConnectorsRoute(router, licenseState);
updateActionRoute(router, licenseState);
connectorTypesRoute(router, licenseState);
listTypesRoute(router, licenseState);
executeActionRoute(router, licenseState);
getGlobalExecutionLogRoute(router, licenseState);
getGlobalExecutionKPIRoute(router, licenseState);

View file

@ -9,15 +9,16 @@ import { KibanaRequest, KibanaResponseFactory } from '@kbn/core/server';
import { identity } from 'lodash';
import type { MethodKeysOf } from '@kbn/utility-types';
import { httpServerMock } from '@kbn/core/server/mocks';
import { ActionType } from '../../../common';
import { ActionsClientMock, actionsClientMock } from '../../actions_client.mock';
import { ActionsRequestHandlerContext } from '../../types';
import { actionsClientMock } from '../../mocks';
import { ActionsClientMock } from '../../actions_client/actions_client.mock';
import { ConnectorType } from '../../application/connector/types';
export function mockHandlerArguments(
{
actionsClient = actionsClientMock.create(),
listTypes: listTypesRes = [],
}: { actionsClient?: ActionsClientMock; listTypes?: ActionType[] },
}: { actionsClient?: ActionsClientMock; listTypes?: ConnectorType[] },
request: unknown,
response?: Array<MethodKeysOf<KibanaResponseFactory>>
): [ActionsRequestHandlerContext, KibanaRequest<unknown, unknown, unknown>, KibanaResponseFactory] {

View file

@ -9,7 +9,7 @@ import { createActionRoute } from './create';
import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../../lib/license_state.mock';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { actionsClientMock } from '../../actions_client.mock';
import { actionsClientMock } from '../../actions_client/actions_client.mock';
import { verifyAccessAndContext } from '../verify_access_and_context';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock';

View file

@ -10,7 +10,7 @@ import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../../lib/license_state.mock';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { verifyApiAccess, ActionTypeDisabledError, asHttpRequestExecutionSource } from '../../lib';
import { actionsClientMock } from '../../actions_client.mock';
import { actionsClientMock } from '../../actions_client/actions_client.mock';
import { ActionTypeExecutorResult } from '../../types';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock';

View file

@ -10,7 +10,7 @@ import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../../lib/license_state.mock';
import { verifyApiAccess } from '../../lib';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { actionsClientMock } from '../../actions_client.mock';
import { actionsClientMock } from '../../actions_client/actions_client.mock';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock';

View file

@ -10,7 +10,7 @@ import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../../lib/license_state.mock';
import { verifyApiAccess } from '../../lib';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { actionsClientMock } from '../../actions_client.mock';
import { actionsClientMock } from '../../actions_client/actions_client.mock';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock';

View file

@ -10,7 +10,7 @@ import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../../lib/license_state.mock';
import { verifyApiAccess, ActionTypeDisabledError } from '../../lib';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { actionsClientMock } from '../../actions_client.mock';
import { actionsClientMock } from '../../actions_client/actions_client.mock';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock';

View file

@ -9,7 +9,7 @@ import { bodySchema, updateActionRoute } from './update';
import { httpServiceMock } from '@kbn/core/server/mocks';
import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './legacy/_mock_handler_arguments';
import { actionsClientMock } from '../actions_client.mock';
import { actionsClientMock } from '../actions_client/actions_client.mock';
import { verifyAccessAndContext } from './verify_access_and_context';
jest.mock('./verify_access_and_context', () => ({

View file

@ -8,7 +8,7 @@
import { licenseStateMock } from '../lib/license_state.mock';
import { verifyApiAccess, ActionTypeDisabledError } from '../lib';
import { mockHandlerArguments } from './legacy/_mock_handler_arguments';
import { actionsClientMock } from '../actions_client.mock';
import { actionsClientMock } from '../actions_client/actions_client.mock';
import { verifyAccessAndContext } from './verify_access_and_context';
jest.mock('../lib/verify_api_access', () => ({

View file

@ -11,7 +11,7 @@ import type { ISavedObjectsSerializer } from '@kbn/core-saved-objects-server';
import { createFileServiceMock } from '@kbn/files-plugin/server/mocks';
import { securityMock } from '@kbn/security-plugin/server/mocks';
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client.mock';
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock';
import { makeLensEmbeddableFactory } from '@kbn/lens-plugin/server/embeddable/make_lens_embeddable_factory';
import { serializerMock } from '@kbn/core-saved-objects-base-server-mocks';

View file

@ -16,7 +16,7 @@ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks';
// See: https://github.com/elastic/kibana/issues/117255, the moduleNameMapper creates mocks to avoid memory leaks from kibana core.
// We cannot import from "../../../../../../actions/server" directly here or we have a really bad memory issue. We cannot add this to the existing mocks we created, this fix must be here.
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client.mock';
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock';
import { licensingMock } from '@kbn/licensing-plugin/server/mocks';
import { listMock } from '@kbn/lists-plugin/server/mocks';
import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks';

View file

@ -27,7 +27,7 @@ import { requestContextMock } from '../../../routes/__mocks__/request_context';
import { savedObjectsExporterMock } from '@kbn/core-saved-objects-import-export-server-mocks';
import { mockRouter } from '@kbn/core-http-router-server-mocks';
import { Readable } from 'stream';
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client.mock';
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock';
const exceptionsClient = getExceptionListClientMock();

View file

@ -28,7 +28,7 @@ import { mockRouter } from '@kbn/core-http-router-server-mocks';
const exceptionsClient = getExceptionListClientMock();
import type { loggingSystemMock } from '@kbn/core/server/mocks';
import { requestContextMock } from '../../../routes/__mocks__/request_context';
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client.mock';
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock';
const connectors = [
{

View file

@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client.mock';
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock';
import {
getImportRulesSchemaMock,
webHookConnector,