diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts new file mode 100644 index 0000000000000..7722521d2b707 --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts @@ -0,0 +1,15 @@ +/* + * 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 { findRulesRequestQuerySchema } from './schemas/latest'; +export type { FindRulesRequestQuery, FindRulesResponse } from './types/latest'; + +export { findRulesRequestQuerySchema as findRulesRequestQuerySchemaV1 } from './schemas/v1'; +export type { + FindRulesRequestQuery as FindRulesRequestQueryV1, + FindRulesResponse as FindRulesResponseV1, +} from './types/latest'; diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/latest.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/latest.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 * from './v1'; diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts new file mode 100644 index 0000000000000..faa483e1aef1b --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts @@ -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 { schema } from '@kbn/config-schema'; + +export const findRulesRequestQuerySchema = schema.object({ + per_page: schema.number({ defaultValue: 10, min: 0 }), + page: schema.number({ defaultValue: 1, min: 1 }), + search: schema.maybe(schema.string()), + default_search_operator: schema.oneOf([schema.literal('OR'), schema.literal('AND')], { + defaultValue: 'OR', + }), + search_fields: schema.maybe(schema.oneOf([schema.arrayOf(schema.string()), schema.string()])), + sort_field: schema.maybe(schema.string()), + sort_order: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])), + has_reference: schema.maybe( + // use nullable as maybe is currently broken + // in config-schema + schema.nullable( + schema.object({ + type: schema.string(), + id: schema.string(), + }) + ) + ), + fields: schema.maybe(schema.arrayOf(schema.string())), + filter: schema.maybe(schema.string()), + filter_consumers: schema.maybe(schema.arrayOf(schema.string())), +}); diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/types/latest.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/types/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/types/latest.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 * from './v1'; diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts new file mode 100644 index 0000000000000..271e791282f43 --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts @@ -0,0 +1,21 @@ +/* + * 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 { RuleParamsV1, RuleResponseV1 } from '../../../response'; +import { findRulesRequestQuerySchemaV1 } from '..'; + +export type FindRulesRequestQuery = TypeOf; + +export interface FindRulesResponse { + body: { + page: number; + per_page: number; + total: number; + data: Array>>; + }; +} diff --git a/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts similarity index 90% rename from x-pack/plugins/alerting/server/rules_client/tests/find.test.ts rename to x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts index 660bf24332414..ee8038f2c8b6c 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RulesClient, ConstructorOptions } from '../rules_client'; +import { RulesClient, ConstructorOptions } from '../../../../rules_client/rules_client'; import { savedObjectsClientMock, loggingSystemMock, @@ -13,25 +13,30 @@ import { uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; -import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; -import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock'; +import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock'; +import { alertingAuthorizationMock } from '../../../../authorization/alerting_authorization.mock'; import { nodeTypes, fromKueryExpression } from '@kbn/es-query'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; -import { AlertingAuthorization } from '../../authorization/alerting_authorization'; +import { AlertingAuthorization } from '../../../../authorization/alerting_authorization'; import { ActionsAuthorization } from '@kbn/actions-plugin/server'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { getBeforeSetup, setGlobalDate } from './lib'; -import { RecoveredActionGroup } from '../../../common'; -import { RegistryRuleType } from '../../rule_type_registry'; +import { getBeforeSetup, setGlobalDate } from '../../../../rules_client/tests/lib'; +import { RecoveredActionGroup } from '../../../../../common'; +import { RegistryRuleType } from '../../../../rule_type_registry'; import { schema } from '@kbn/config-schema'; -import { enabledRule1, enabledRule2, siemRule1, siemRule2 } from './test_helpers'; -import { formatLegacyActions } from '../lib'; -import { ConnectorAdapterRegistry } from '../../connector_adapters/connector_adapter_registry'; -import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; -import { backfillClientMock } from '../../backfill_client/backfill_client.mock'; +import { + enabledRule1, + enabledRule2, + siemRule1, + siemRule2, +} from '../../../../rules_client/tests/test_helpers'; +import { formatLegacyActions } from '../../../../rules_client/lib'; +import { ConnectorAdapterRegistry } from '../../../../connector_adapters/connector_adapter_registry'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; +import { backfillClientMock } from '../../../../backfill_client/backfill_client.mock'; -jest.mock('../lib/siem_legacy_actions/format_legacy_actions', () => { +jest.mock('../../../../rules_client/lib/siem_legacy_actions/format_legacy_actions', () => { return { formatLegacyActions: jest.fn(), }; @@ -82,7 +87,7 @@ beforeEach(() => { setGlobalDate(); -jest.mock('../common/map_sort_field', () => ({ +jest.mock('../../../../rules_client/common/map_sort_field', () => ({ mapSortField: jest.fn(), })); @@ -127,6 +132,10 @@ describe('find()', () => { }, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), + executionStatus: { + status: 'pending', + lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'), + }, notifyWhen: 'onActiveAlert', actions: [ { @@ -197,6 +206,10 @@ describe('find()', () => { ], "alertTypeId": "myType", "createdAt": 2019-02-12T21:01:22.479Z, + "executionStatus": Object { + "lastExecutionDate": 2019-02-12T21:01:22.000Z, + "status": "pending", + }, "id": "1", "notifyWhen": "onActiveAlert", "params": Object { @@ -244,6 +257,10 @@ describe('find()', () => { params: { bar: true, }, + executionStatus: { + status: 'pending', + lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'), + }, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), notifyWhen: 'onActiveAlert', @@ -303,6 +320,10 @@ describe('find()', () => { ], "alertTypeId": "myType", "createdAt": 2019-02-12T21:01:22.479Z, + "executionStatus": Object { + "lastExecutionDate": 2019-02-12T21:01:22.000Z, + "status": "pending", + }, "id": "1", "notifyWhen": "onActiveAlert", "params": Object { @@ -350,6 +371,10 @@ describe('find()', () => { params: { bar: true, }, + executionStatus: { + status: 'pending', + lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'), + }, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), notifyWhen: 'onActiveAlert', @@ -400,6 +425,10 @@ describe('find()', () => { ], "alertTypeId": "myType", "createdAt": 2019-02-12T21:01:22.479Z, + "executionStatus": Object { + "lastExecutionDate": 2019-02-12T21:01:22.000Z, + "status": "pending", + }, "id": "1", "notifyWhen": "onActiveAlert", "params": Object { @@ -441,7 +470,9 @@ describe('find()', () => { test('calls mapSortField', async () => { const rulesClient = new RulesClient(rulesClientParams); await rulesClient.find({ options: { sortField: 'name' } }); - expect(jest.requireMock('../common/map_sort_field').mapSortField).toHaveBeenCalledWith('name'); + expect( + jest.requireMock('../../../../rules_client/common/map_sort_field').mapSortField + ).toHaveBeenCalledWith('name'); }); test('should translate filter/sort/search on params to mapped_params', async () => { @@ -559,6 +590,10 @@ describe('find()', () => { params: { bar: true, }, + executionStatus: { + status: 'pending', + lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'), + }, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), notifyWhen: 'onActiveAlert', @@ -591,6 +626,10 @@ describe('find()', () => { bar: true, parameterThatIsSavedObjectRef: 'soRef_0', }, + executionStatus: { + status: 'pending', + lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'), + }, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), notifyWhen: 'onActiveAlert', @@ -649,6 +688,10 @@ describe('find()', () => { ], "alertTypeId": "myType", "createdAt": 2019-02-12T21:01:22.479Z, + "executionStatus": Object { + "lastExecutionDate": 2019-02-12T21:01:22.000Z, + "status": "pending", + }, "id": "1", "notifyWhen": "onActiveAlert", "params": Object { @@ -675,6 +718,10 @@ describe('find()', () => { ], "alertTypeId": "123", "createdAt": 2019-02-12T21:01:22.479Z, + "executionStatus": Object { + "lastExecutionDate": 2019-02-12T21:01:22.000Z, + "status": "pending", + }, "id": "2", "notifyWhen": "onActiveAlert", "params": Object { @@ -779,6 +826,10 @@ describe('find()', () => { params: { bar: true, }, + executionStatus: { + status: 'pending', + lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'), + }, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), notifyWhen: 'onActiveAlert', @@ -811,6 +862,10 @@ describe('find()', () => { bar: true, parameterThatIsSavedObjectRef: 'soRef_0', }, + executionStatus: { + status: 'pending', + lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'), + }, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), notifyWhen: 'onActiveAlert', @@ -891,6 +946,10 @@ describe('find()', () => { type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], + executionStatus: { + status: 'pending', + lastExecutionDate: new Date('2019-02-12T21:01:22.479Z'), + }, alertTypeId: 'myType', consumer: 'myApp', tags: ['myTag'], diff --git a/x-pack/plugins/alerting/server/rules_client/methods/find.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts similarity index 59% rename from x-pack/plugins/alerting/server/rules_client/methods/find.ts rename to x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts index 7ca51bcb16f19..10aef42955e74 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/find.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts @@ -6,70 +6,56 @@ */ import Boom from '@hapi/boom'; -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isEmpty, pick } from 'lodash'; import { KueryNode, nodeBuilder } from '@kbn/es-query'; import { AlertConsumers } from '@kbn/rule-data-utils'; -import { RawRule, RuleTypeParams, SanitizedRule, Rule } from '../../types'; -import { AlertingAuthorizationEntity } from '../../authorization'; -import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; +import { SanitizedRule, Rule as DeprecatedRule, RawRule } from '../../../../types'; +import { AlertingAuthorizationEntity } from '../../../../authorization'; +import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; import { mapSortField, validateOperationOnAttributes, buildKueryNodeFilter, includeFieldsRequiredForAuthentication, -} from '../common'; +} from '../../../../rules_client/common'; import { getModifiedField, getModifiedSearchFields, getModifiedSearch, modifyFilterKueryNode, -} from '../common/mapped_params_utils'; -import { alertingAuthorizationFilterOpts } from '../common/constants'; -import { getAlertFromRaw } from '../lib/get_alert_from_raw'; -import type { IndexType, RulesClientContext } from '../types'; -import { formatLegacyActions } from '../lib'; -import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; - -export interface FindParams { - options?: FindOptions; - excludeFromPublicApi?: boolean; - includeSnoozeData?: boolean; - featuresIds?: string[]; -} - -export interface FindOptions extends IndexType { - perPage?: number; - page?: number; - search?: string; - defaultSearchOperator?: 'AND' | 'OR'; - searchFields?: string[]; - sortField?: string; - sortOrder?: estypes.SortOrder; - hasReference?: { - type: string; - id: string; - }; - fields?: string[]; - filter?: string | KueryNode; - filterConsumers?: string[]; -} - -export interface FindResult { +} from '../../../../rules_client/common/mapped_params_utils'; +import { alertingAuthorizationFilterOpts } from '../../../../rules_client/common/constants'; +import type { RulesClientContext } from '../../../../rules_client/types'; +import { formatLegacyActions, getAlertFromRaw } from '../../../../rules_client/lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; +import type { FindRulesParams } from './types'; +import { findRulesParamsSchema } from './schemas'; +import { Rule, RuleParams } from '../../types'; +import { findRulesSo } from '../../../../data/rule'; + +export interface FindResult { page: number; perPage: number; total: number; data: Array>; } -export async function find( +export async function findRules( context: RulesClientContext, - { - options: { fields, filterConsumers, ...options } = {}, - excludeFromPublicApi = false, - includeSnoozeData = false, - }: FindParams = {} + params?: FindRulesParams ): Promise> { + const { options, excludeFromPublicApi = false, includeSnoozeData = false } = params || {}; + + const { fields, filterConsumers, ...restOptions } = options || {}; + + try { + if (params) { + findRulesParamsSchema.validate(params); + } + } catch (error) { + throw Boom.badRequest(`Error validating find data - ${error.message}`); + } + let authorizationTuple; try { authorizationTuple = await context.authorization.getFindAuthorizationFilter( @@ -88,14 +74,14 @@ export async function find( } const { filter: authorizationFilter, ensureRuleTypeIsAuthorized } = authorizationTuple; - const filterKueryNode = buildKueryNodeFilter(options.filter); - let sortField = mapSortField(options.sortField); + const filterKueryNode = buildKueryNodeFilter(restOptions.filter as string | KueryNode); + let sortField = mapSortField(restOptions.sortField); if (excludeFromPublicApi) { try { validateOperationOnAttributes( filterKueryNode, sortField, - options.searchFields, + restOptions.searchFields, context.fieldsToExcludeFromPublicApi ); } catch (error) { @@ -103,16 +89,20 @@ export async function find( } } - sortField = mapSortField(getModifiedField(options.sortField)); + sortField = mapSortField(getModifiedField(restOptions.sortField)); // Generate new modified search and search fields, translating certain params properties // to mapped_params. Thus, allowing for sort/search/filtering on params. // We do the modifcation after the validate check to make sure the public API does not // use the mapped_params in their queries. - options = { - ...options, - ...(options.searchFields && { searchFields: getModifiedSearchFields(options.searchFields) }), - ...(options.search && { search: getModifiedSearch(options.searchFields, options.search) }), + const modifiedOptions = { + ...restOptions, + ...(restOptions.searchFields && { + searchFields: getModifiedSearchFields(restOptions.searchFields), + }), + ...(restOptions.search && { + search: getModifiedSearch(restOptions.searchFields, restOptions.search), + }), }; // Modifies kuery node AST to translate params filter and the filter value to mapped_params. @@ -126,15 +116,17 @@ export async function find( per_page: perPage, total, saved_objects: data, - } = await context.unsecuredSavedObjectsClient.find({ - ...options, - sortField, - filter: - (authorizationFilter && filterKueryNode - ? nodeBuilder.and([filterKueryNode, authorizationFilter as KueryNode]) - : authorizationFilter) ?? filterKueryNode, - fields: fields ? includeFieldsRequiredForAuthentication(fields) : fields, - type: RULE_SAVED_OBJECT_TYPE, + } = await findRulesSo({ + savedObjectsClient: context.unsecuredSavedObjectsClient, + savedObjectsFindOptions: { + ...modifiedOptions, + sortField, + filter: + (authorizationFilter && filterKueryNode + ? nodeBuilder.and([filterKueryNode, authorizationFilter as KueryNode]) + : authorizationFilter) ?? filterKueryNode, + fields: fields ? includeFieldsRequiredForAuthentication(fields) : fields, + }, }); const siemRules: Rule[] = []; @@ -161,7 +153,7 @@ export async function find( context, id, attributes.alertTypeId, - fields ? (pick(attributes, fields) as RawRule) : attributes, + (fields ? pick(attributes, fields) : attributes) as RawRule, references, false, excludeFromPublicApi, @@ -170,7 +162,7 @@ export async function find( // collect SIEM rule for further formatting legacy actions if (attributes.consumer === AlertConsumers.SIEM) { - siemRules.push(rule); + siemRules.push(rule as Rule); } return rule; @@ -187,12 +179,12 @@ export async function find( // format legacy actions for SIEM rules, if there any if (siemRules.length) { - const formattedRules = await formatLegacyActions(siemRules, { + const formattedRules = await formatLegacyActions(siemRules as DeprecatedRule[], { savedObjectsClient: context.unsecuredSavedObjectsClient, logger: context.logger, }); - const formattedRulesMap = formattedRules.reduce>((acc, rule) => { + const formattedRulesMap = formattedRules.reduce>((acc, rule) => { acc[rule.id] = rule; return acc; }, {}); @@ -210,6 +202,6 @@ export async function find( page, perPage, total, - data: authorizedData, + data: authorizedData as Array>, }; } diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/index.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/index.ts new file mode 100644 index 0000000000000..17287e7136c61 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/index.ts @@ -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. + */ + +export type { FindResult } from './find_rules'; +export type { FindRulesOptions, FindRulesParams } from './types'; + +export { findRules } from './find_rules'; diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts new file mode 100644 index 0000000000000..b766ffc283bb2 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts @@ -0,0 +1,41 @@ +/* + * 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 findRulesOptionsSchema = schema.object( + { + perPage: schema.maybe(schema.number()), + page: schema.maybe(schema.number()), + search: schema.maybe(schema.string()), + defaultSearchOperator: schema.maybe( + schema.oneOf([schema.literal('AND'), schema.literal('OR')]) + ), + searchFields: schema.maybe(schema.arrayOf(schema.string())), + sortField: schema.maybe(schema.string()), + sortOrder: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])), + hasReference: schema.maybe( + schema.object({ + type: schema.string(), + id: schema.string(), + }) + ), + fields: schema.maybe(schema.arrayOf(schema.string())), + filter: schema.maybe( + schema.oneOf([schema.string(), schema.recordOf(schema.string(), schema.any())]) + ), + filterConsumers: schema.maybe(schema.arrayOf(schema.string())), + }, + { unknowns: 'allow' } +); + +export const findRulesParamsSchema = schema.object({ + options: schema.maybe(findRulesOptionsSchema), + excludeFromPublicApi: schema.maybe(schema.boolean()), + includeSnoozeData: schema.maybe(schema.boolean()), + featureIds: schema.maybe(schema.arrayOf(schema.string())), +}); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/index.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/index.ts new file mode 100644 index 0000000000000..228a64a2dfa6b --- /dev/null +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/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 * from './find_rules_schemas'; diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts new file mode 100644 index 0000000000000..615a5b5db8672 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts @@ -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 { TypeOf } from '@kbn/config-schema'; +import { findRulesOptionsSchema, findRulesParamsSchema } from '../schemas'; + +export type FindRulesOptions = TypeOf; + +export type FindRulesParams = TypeOf; diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/types/index.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/types/index.ts new file mode 100644 index 0000000000000..cf7f87036c904 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/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 * from './find_rules_types'; diff --git a/x-pack/plugins/alerting/server/routes/index.ts b/x-pack/plugins/alerting/server/routes/index.ts index fc07b8dbeb6e8..edebbd6c7d1f7 100644 --- a/x-pack/plugins/alerting/server/routes/index.ts +++ b/x-pack/plugins/alerting/server/routes/index.ts @@ -20,7 +20,7 @@ import { deleteRuleRoute } from './delete_rule'; import { aggregateRulesRoute } from './rule/apis/aggregate/aggregate_rules_route'; import { disableRuleRoute } from './disable_rule'; import { enableRuleRoute } from './enable_rule'; -import { findRulesRoute, findInternalRulesRoute } from './find_rules'; +import { findRulesRoute, findInternalRulesRoute } from './rule/apis/find/find_rules_route'; import { getRuleAlertSummaryRoute } from './get_rule_alert_summary'; import { getRuleExecutionLogRoute } from './get_rule_execution_log'; import { getGlobalExecutionLogRoute } from './get_global_execution_logs'; diff --git a/x-pack/plugins/alerting/server/routes/legacy/find.ts b/x-pack/plugins/alerting/server/routes/legacy/find.ts index e0e4ffa34cf33..dcda2e01271d4 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/find.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/find.ts @@ -7,16 +7,35 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { estypes } from '@elastic/elasticsearch'; +import { KueryNode } from '@kbn/es-query'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; import { renameKeys } from '../lib/rename_keys'; -import { FindOptions } from '../../rules_client'; +import { IndexType } from '../../rules_client'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; import { trackLegacyTerminology } from '../lib/track_legacy_terminology'; +export interface FindOptions extends IndexType { + perPage?: number; + page?: number; + search?: string; + defaultSearchOperator?: 'AND' | 'OR'; + searchFields?: string[]; + sortField?: string; + sortOrder?: estypes.SortOrder; + hasReference?: { + type: string; + id: string; + }; + fields?: string[]; + filter?: string | KueryNode; + filterConsumers?: string[]; +} + // config definition const querySchema = schema.object({ per_page: schema.number({ defaultValue: 10, min: 0 }), diff --git a/x-pack/plugins/alerting/server/routes/find_rules.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts similarity index 92% rename from x-pack/plugins/alerting/server/routes/find_rules.test.ts rename to x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts index 69df6e978cd83..53c339a66b864 100644 --- a/x-pack/plugins/alerting/server/routes/find_rules.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts @@ -5,23 +5,23 @@ * 2.0. */ import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; -import { findRulesRoute } from './find_rules'; +import { findRulesRoute } from './find_rules_route'; import { httpServiceMock } from '@kbn/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { verifyApiAccess } from '../lib/license_api_access'; -import { mockHandlerArguments } from './_mock_handler_arguments'; -import { rulesClientMock } from '../rules_client.mock'; -import { trackLegacyTerminology } from './lib/track_legacy_terminology'; +import { licenseStateMock } from '../../../../lib/license_state.mock'; +import { verifyApiAccess } from '../../../../lib/license_api_access'; +import { mockHandlerArguments } from '../../../_mock_handler_arguments'; +import { rulesClientMock } from '../../../../rules_client.mock'; +import { trackLegacyTerminology } from '../../../lib/track_legacy_terminology'; const rulesClient = rulesClientMock.create(); const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); -jest.mock('../lib/license_api_access', () => ({ +jest.mock('../../../../lib/license_api_access', () => ({ verifyApiAccess: jest.fn(), })); -jest.mock('./lib/track_legacy_terminology', () => ({ +jest.mock('../../../lib/track_legacy_terminology', () => ({ trackLegacyTerminology: jest.fn(), })); @@ -79,7 +79,6 @@ describe('findRulesRoute', () => { "includeSnoozeData": true, "options": Object { "defaultSearchOperator": "OR", - "filterConsumers": undefined, "page": 1, "perPage": 1, }, @@ -130,6 +129,7 @@ describe('findRulesRoute', () => { schedule: { interval: '1s', }, + snoozeSchedule: [], actions: [ { actionTypeId: '.server-log', @@ -145,12 +145,12 @@ describe('findRulesRoute', () => { { actionTypeId: '.test', id: 'system_action-id', params: {}, uuid: '789' }, ], params: { x: 42 }, - updatedAt: '2024-03-21T13:15:00.498Z', - createdAt: '2024-03-21T13:15:00.498Z', + updatedAt: new Date('2024-03-21T13:15:00.498Z'), + createdAt: new Date('2024-03-21T13:15:00.498Z'), scheduledTaskId: '52125fb0-5895-11ec-ae69-bb65d1a71b72', executionStatus: { status: 'ok' as const, - lastExecutionDate: '2024-03-21T13:15:00.498Z', + lastExecutionDate: new Date('2024-03-21T13:15:00.498Z'), lastDuration: 1194, }, revision: 0, @@ -158,7 +158,6 @@ describe('findRulesRoute', () => { ], }; - // @ts-expect-error: TS complains about group being undefined in the system action rulesClient.find.mockResolvedValueOnce(findResult); const [context, req, res] = mockHandlerArguments( @@ -195,7 +194,6 @@ describe('findRulesRoute', () => { "uuid": "789", }, ], - "apiKey": null, "api_key_owner": "2889684073", "consumer": "alerts", "created_at": "2024-03-21T13:15:00.498Z", @@ -220,7 +218,7 @@ describe('findRulesRoute', () => { "interval": "1s", }, "scheduled_task_id": "52125fb0-5895-11ec-ae69-bb65d1a71b72", - "snooze_schedule": undefined, + "snooze_schedule": Array [], "tags": Array [], "throttle": null, "updated_at": "2024-03-21T13:15:00.498Z", @@ -242,7 +240,6 @@ describe('findRulesRoute', () => { "includeSnoozeData": true, "options": Object { "defaultSearchOperator": "OR", - "filterConsumers": undefined, "page": 1, "perPage": 1, }, @@ -274,7 +271,6 @@ describe('findRulesRoute', () => { uuid: '789', }, ], - apiKey: null, api_key_owner: '2889684073', consumer: 'alerts', created_at: '2024-03-21T13:15:00.498Z', @@ -299,7 +295,7 @@ describe('findRulesRoute', () => { interval: '1s', }, scheduled_task_id: '52125fb0-5895-11ec-ae69-bb65d1a71b72', - snooze_schedule: undefined, + snooze_schedule: [], tags: [], throttle: null, updated_at: '2024-03-21T13:15:00.498Z', diff --git a/x-pack/plugins/alerting/server/routes/find_rules.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts similarity index 56% rename from x-pack/plugins/alerting/server/routes/find_rules.ts rename to x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts index 711baa3108f35..6baf208e016a1 100644 --- a/x-pack/plugins/alerting/server/routes/find_rules.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts @@ -7,70 +7,21 @@ import { IRouter } from '@kbn/core/server'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; -import { schema } from '@kbn/config-schema'; -import { ILicenseState } from '../lib'; -import { FindOptions, FindResult } from '../rules_client'; -import { RewriteRequestCase, verifyAccessAndContext, rewriteRule } from './lib'; +import { ILicenseState } from '../../../../lib'; +import { verifyAccessAndContext } from '../../../lib'; +import { findRulesRequestQuerySchemaV1 } from '../../../../../common/routes/rule/apis/find'; +import type { + FindRulesRequestQueryV1, + FindRulesResponseV1, +} from '../../../../../common/routes/rule/apis/find'; +import type { RuleParamsV1 } from '../../../../../common/routes/rule/response'; import { - RuleTypeParams, AlertingRequestHandlerContext, BASE_ALERTING_API_PATH, INTERNAL_ALERTING_API_FIND_RULES_PATH, -} from '../types'; -import { trackLegacyTerminology } from './lib/track_legacy_terminology'; - -// query definition -const querySchema = schema.object({ - per_page: schema.number({ defaultValue: 10, min: 0 }), - page: schema.number({ defaultValue: 1, min: 1 }), - search: schema.maybe(schema.string()), - default_search_operator: schema.oneOf([schema.literal('OR'), schema.literal('AND')], { - defaultValue: 'OR', - }), - search_fields: schema.maybe(schema.oneOf([schema.arrayOf(schema.string()), schema.string()])), - sort_field: schema.maybe(schema.string()), - sort_order: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])), - has_reference: schema.maybe( - // use nullable as maybe is currently broken - // in config-schema - schema.nullable( - schema.object({ - type: schema.string(), - id: schema.string(), - }) - ) - ), - fields: schema.maybe(schema.arrayOf(schema.string())), - filter: schema.maybe(schema.string()), - filter_consumers: schema.maybe(schema.arrayOf(schema.string())), -}); - -const rewriteQueryReq: RewriteRequestCase = ({ - default_search_operator: defaultSearchOperator, - has_reference: hasReference, - search_fields: searchFields, - per_page: perPage, - sort_field: sortField, - sort_order: sortOrder, - filter_consumers: filterConsumers, - ...rest -}) => ({ - ...rest, - defaultSearchOperator, - perPage, - filterConsumers, - ...(sortField ? { sortField } : {}), - ...(sortOrder ? { sortOrder } : {}), - ...(hasReference ? { hasReference } : {}), - ...(searchFields ? { searchFields } : {}), -}); -const rewriteBodyRes = ({ perPage, data, ...restOfResult }: FindResult) => { - return { - ...restOfResult, - per_page: perPage, - data: data.map(rewriteRule), - }; -}; +} from '../../../../types'; +import { trackLegacyTerminology } from '../../../lib/track_legacy_terminology'; +import { transformFindRulesBodyV1, transformFindRulesResponseV1 } from './transforms'; interface BuildFindRulesRouteParams { licenseState: ILicenseState; @@ -91,24 +42,24 @@ const buildFindRulesRoute = ({ { path, validate: { - query: querySchema, + query: findRulesRequestQuerySchemaV1, }, }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { const rulesClient = (await context.alerting).getRulesClient(); + const query: FindRulesRequestQueryV1 = req.query; + trackLegacyTerminology( - [req.query.search, req.query.search_fields, req.query.sort_field].filter( - Boolean - ) as string[], + [query.search, query.search_fields, query.sort_field].filter(Boolean) as string[], usageCounter ); - const options = rewriteQueryReq({ - ...req.query, - has_reference: req.query.has_reference || undefined, - search_fields: searchFieldsAsArray(req.query.search_fields), + const options = transformFindRulesBodyV1({ + ...query, + has_reference: query.has_reference || undefined, + search_fields: searchFieldsAsArray(query.search_fields), }); if (req.query.fields) { @@ -124,8 +75,12 @@ const buildFindRulesRoute = ({ excludeFromPublicApi, includeSnoozeData: true, }); + + const responseBody: FindRulesResponseV1['body'] = + transformFindRulesResponseV1(findResult, options.fields); + return res.ok({ - body: rewriteBodyRes(findResult), + body: responseBody, }); }) ) @@ -135,13 +90,15 @@ const buildFindRulesRoute = ({ { path, validate: { - body: querySchema, + body: findRulesRequestQuerySchemaV1, }, }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { const rulesClient = (await context.alerting).getRulesClient(); + const body: FindRulesRequestQueryV1 = req.body; + trackLegacyTerminology( [req.body.search, req.body.search_fields, req.body.sort_field].filter( Boolean @@ -149,10 +106,10 @@ const buildFindRulesRoute = ({ usageCounter ); - const options = rewriteQueryReq({ - ...req.body, - has_reference: req.body.has_reference || undefined, - search_fields: searchFieldsAsArray(req.body.search_fields), + const options = transformFindRulesBodyV1({ + ...body, + has_reference: body.has_reference || undefined, + search_fields: searchFieldsAsArray(body.search_fields), }); if (req.body.fields) { @@ -168,8 +125,12 @@ const buildFindRulesRoute = ({ excludeFromPublicApi, includeSnoozeData: true, }); + + const responseBody: FindRulesResponseV1['body'] = + transformFindRulesResponseV1(findResult, options.fields); + return res.ok({ - body: rewriteBodyRes(findResult), + body: responseBody, }); }) ) diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts new file mode 100644 index 0000000000000..044a845f3f8f3 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts @@ -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 { transformFindRulesBody } from './transform_find_rules_body/latest'; +export { transformFindRulesResponse } from './transform_find_rules_response/latest'; + +export { transformFindRulesBody as transformFindRulesBodyV1 } from './transform_find_rules_body/v1'; +export { transformFindRulesResponse as transformFindRulesResponseV1 } from './transform_find_rules_response/v1'; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/latest.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/latest.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 * from './v1'; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts new file mode 100644 index 0000000000000..a2f9d3c99b00d --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts @@ -0,0 +1,40 @@ +/* + * 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 { FindRulesRequestQueryV1 } from '../../../../../../../common/routes/rule/apis/find'; +import { FindRulesOptions } from '../../../../../../application/rule/methods/find'; + +export const transformFindRulesBody = (params: FindRulesRequestQueryV1): FindRulesOptions => { + const { + per_page: perPage, + page, + search, + default_search_operator: defaultSearchOperator, + search_fields: searchFields, + sort_field: sortField, + sort_order: sortOrder, + has_reference: hasReference, + fields, + filter, + filter_consumers: filterConsumers, + } = params; + return { + ...(page ? { page } : {}), + ...(search ? { search } : {}), + ...(fields ? { fields } : {}), + ...(filter ? { filter } : {}), + ...(defaultSearchOperator ? { defaultSearchOperator } : {}), + ...(perPage ? { perPage } : {}), + ...(filterConsumers ? { filterConsumers } : {}), + ...(sortField ? { sortField } : {}), + ...(sortOrder ? { sortOrder } : {}), + ...(hasReference ? { hasReference } : {}), + ...(searchFields + ? { searchFields: Array.isArray(searchFields) ? searchFields : [searchFields] } + : {}), + }; +}; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_response/latest.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_response/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_response/latest.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 * from './v1'; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_response/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_response/v1.ts new file mode 100644 index 0000000000000..6754fa71e10d4 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_response/v1.ts @@ -0,0 +1,111 @@ +/* + * 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 { FindRulesResponseV1 } from '../../../../../../../common/routes/rule/apis/find'; +import type { + RuleResponseV1, + RuleParamsV1, +} from '../../../../../../../common/routes/rule/response'; +import type { FindResult } from '../../../../../../application/rule/methods/find'; +import { Rule, RuleParams } from '../../../../../../application/rule/types'; +import { + transformRuleActionsV1, + transformMonitoringV1, + transformRuleLastRunV1, +} from '../../../../transforms'; + +export const transformPartialRule = ( + rule: Partial>, + fields?: string[] +): Partial> => { + const ruleResponse = { + ...(rule.id !== undefined ? { id: rule.id } : {}), + ...(rule.enabled !== undefined ? { enabled: rule.enabled } : {}), + ...(rule.name !== undefined ? { name: rule.name } : {}), + ...(rule.tags ? { tags: rule.tags } : {}), + ...(rule.alertTypeId !== undefined ? { rule_type_id: rule.alertTypeId } : {}), + ...(rule.consumer !== undefined ? { consumer: rule.consumer } : {}), + ...(rule.schedule ? { schedule: rule.schedule } : {}), + ...(rule.actions || rule.systemActions + ? { actions: transformRuleActionsV1(rule.actions || [], rule.systemActions || []) } + : {}), + ...(rule.params ? { params: rule.params } : {}), + ...(rule.mapped_params ? { mapped_params: rule.mapped_params } : {}), + ...(rule.scheduledTaskId !== undefined ? { scheduled_task_id: rule.scheduledTaskId } : {}), + ...(rule.createdBy !== undefined ? { created_by: rule.createdBy } : {}), + ...(rule.updatedBy !== undefined ? { updated_by: rule.updatedBy } : {}), + ...(rule.createdAt ? { created_at: rule.createdAt.toISOString() } : {}), + ...(rule.updatedAt ? { updated_at: rule.updatedAt.toISOString() } : {}), + ...(rule.apiKeyOwner !== undefined ? { api_key_owner: rule.apiKeyOwner } : {}), + ...(rule.apiKeyCreatedByUser !== undefined + ? { api_key_created_by_user: rule.apiKeyCreatedByUser } + : {}), + ...(rule.throttle !== undefined ? { throttle: rule.throttle } : {}), + ...(rule.muteAll !== undefined ? { mute_all: rule.muteAll } : {}), + ...(rule.notifyWhen !== undefined ? { notify_when: rule.notifyWhen } : {}), + ...(rule.mutedInstanceIds ? { muted_alert_ids: rule.mutedInstanceIds } : {}), + ...(rule.scheduledTaskId !== undefined ? { scheduled_task_id: rule.scheduledTaskId } : {}), + ...(rule.executionStatus + ? { + execution_status: { + status: rule.executionStatus.status, + ...(rule.executionStatus.error ? { error: rule.executionStatus.error } : {}), + ...(rule.executionStatus.warning ? { warning: rule.executionStatus.warning } : {}), + last_execution_date: rule.executionStatus.lastExecutionDate?.toISOString(), + ...(rule.executionStatus.lastDuration !== undefined + ? { last_duration: rule.executionStatus.lastDuration } + : {}), + }, + } + : {}), + ...(rule.monitoring ? { monitoring: transformMonitoringV1(rule.monitoring) } : {}), + ...(rule.snoozeSchedule ? { snooze_schedule: rule.snoozeSchedule } : {}), + ...(rule.activeSnoozes ? { active_snoozes: rule.activeSnoozes } : {}), + ...(rule.isSnoozedUntil !== undefined + ? { is_snoozed_until: rule.isSnoozedUntil?.toISOString() || null } + : {}), + ...(rule.lastRun !== undefined + ? { last_run: rule.lastRun ? transformRuleLastRunV1(rule.lastRun) : null } + : {}), + ...(rule.nextRun !== undefined ? { next_run: rule.nextRun?.toISOString() || null } : {}), + ...(rule.revision !== undefined ? { revision: rule.revision } : {}), + ...(rule.running !== undefined ? { running: rule.running } : {}), + ...(rule.viewInAppRelativeUrl !== undefined + ? { view_in_app_relative_url: rule.viewInAppRelativeUrl } + : {}), + ...(rule.alertDelay !== undefined ? { alert_delay: rule.alertDelay } : {}), + }; + + type RuleKeys = keyof RuleResponseV1; + for (const key in ruleResponse) { + if (ruleResponse[key as RuleKeys] !== undefined) { + continue; + } + if (!fields) { + continue; + } + if (fields.includes(key)) { + continue; + } + delete ruleResponse[key as RuleKeys]; + } + return ruleResponse; +}; + +export const transformFindRulesResponse = ( + result: FindResult, + fields?: string[] +): FindRulesResponseV1['body'] => { + return { + page: result.page, + per_page: result.perPage, + total: result.total, + data: result.data.map((rule) => + transformPartialRule(rule as Partial>, fields) + ), + }; +}; diff --git a/x-pack/plugins/alerting/server/routes/rule/transforms/index.ts b/x-pack/plugins/alerting/server/routes/rule/transforms/index.ts index 6e7ba66e752be..49661dd04f9d1 100644 --- a/x-pack/plugins/alerting/server/routes/rule/transforms/index.ts +++ b/x-pack/plugins/alerting/server/routes/rule/transforms/index.ts @@ -5,7 +5,15 @@ * 2.0. */ -export { transformRuleToRuleResponse } from './transform_rule_to_rule_response/latest'; -export { transformRuleToRuleResponse as transformRuleToRuleResponseV1 } from './transform_rule_to_rule_response/v1'; -export { transformRuleActions } from './transform_rule_to_rule_response/latest'; -export { transformRuleActions as transformRuleActionsV1 } from './transform_rule_to_rule_response/v1'; +export { + transformRuleToRuleResponse, + transformRuleActions, + transformRuleLastRun, + transformMonitoring, +} from './transform_rule_to_rule_response/latest'; +export { + transformRuleToRuleResponse as transformRuleToRuleResponseV1, + transformRuleActions as transformRuleActionsV1, + transformRuleLastRun as transformRuleLastRunV1, + transformMonitoring as transformMonitoringV1, +} from './transform_rule_to_rule_response/v1'; diff --git a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/latest.ts b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/latest.ts index f0561497b5d17..25300c97a6d2e 100644 --- a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/latest.ts +++ b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/latest.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { transformRuleToRuleResponse, transformRuleActions } from './v1'; +export * from './v1'; diff --git a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts index ee4a3a6d14c0f..2181876f230bc 100644 --- a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts @@ -13,7 +13,7 @@ import { } from '../../../../../common/routes/rule/response'; import { Rule, RuleLastRun, RuleParams, Monitoring } from '../../../../application/rule/types'; -const transformRuleLastRun = (lastRun: RuleLastRun): RuleLastRunV1 => { +export const transformRuleLastRun = (lastRun: RuleLastRun): RuleLastRunV1 => { return { outcome: lastRun.outcome, ...(lastRun.outcomeOrder !== undefined ? { outcome_order: lastRun.outcomeOrder } : {}), @@ -23,7 +23,7 @@ const transformRuleLastRun = (lastRun: RuleLastRun): RuleLastRunV1 => { }; }; -const transformMonitoring = (monitoring: Monitoring): MonitoringV1 => { +export const transformMonitoring = (monitoring: Monitoring): MonitoringV1 => { return { run: { history: monitoring.run.history.map((history) => ({ @@ -39,7 +39,7 @@ const transformMonitoring = (monitoring: Monitoring): MonitoringV1 => { }; export const transformRuleActions = ( - actions: Rule['actions'], + actions: Rule['actions'] = [], systemActions: Rule['systemActions'] = [] ): RuleResponseV1['actions'] => { return [ diff --git a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.test.ts index 043754dff226e..7b0d4352cbb53 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.test.ts @@ -17,12 +17,12 @@ import { import { retrieveMigratedLegacyActions } from './retrieve_migrated_legacy_actions'; -import { find } from '../../methods/find'; +import { findRules } from '../../../application/rule/methods/find/find_rules'; import { deleteRule } from '../../methods/delete'; -jest.mock('../../methods/find', () => { +jest.mock('../../../application/rule/methods/find/find_rules', () => { return { - find: jest.fn(), + findRules: jest.fn(), }; }); @@ -32,7 +32,7 @@ jest.mock('../../methods/delete', () => { }; }); -const findMock = find as jest.Mock; +const findMock = findRules as jest.Mock; const deleteRuleMock = deleteRule as jest.Mock; const getEmptyFindResult = () => ({ diff --git a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.ts b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.ts index fe4bb56713861..a9ab748cfa3d9 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.ts @@ -9,7 +9,7 @@ import type { SavedObjectReference } from '@kbn/core/server'; import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import type { RulesClientContext } from '../..'; import { RawRuleAction } from '../../../types'; -import { find } from '../../methods/find'; +import { findRules } from '../../../application/rule/methods/find/find_rules'; import { deleteRule } from '../../methods/delete'; import { LegacyIRuleActionsAttributes, legacyRuleActionsSavedObjectType } from './types'; import { transformFromLegacyActions } from './transform_legacy_actions'; @@ -49,7 +49,7 @@ export const retrieveMigratedLegacyActions: RetrieveMigratedLegacyActions = asyn */ // find it using the references array, not params.ruleAlertId const [siemNotification, legacyRuleActionsSO] = await Promise.all([ - find(context, { + findRules(context, { options: { filter: 'alert.attributes.alertTypeId:(siem.notifications)', hasReference: { diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index e7ebb9fe2e64e..88ddcb92ce806 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -36,7 +36,7 @@ import { getRuleExecutionKPI, GetRuleExecutionKPIParams, } from './methods/get_execution_kpi'; -import { find, FindParams } from './methods/find'; +import { findRules, FindRulesParams } from '../application/rule/methods/find'; import { AggregateParams } from '../application/rule/methods/aggregate/types'; import { aggregateRules } from '../application/rule/methods/aggregate'; import { deleteRule } from './methods/delete'; @@ -132,8 +132,8 @@ export class RulesClient { public create = (params: CreateRuleParams) => createRule(this.context, params); public delete = (params: { id: string }) => deleteRule(this.context, params); - public find = (params?: FindParams) => - find(this.context, params); + public find = (params?: FindRulesParams) => + findRules(this.context, params); public get = (params: GetRuleParams) => getRule(this.context, params); public resolve = (params: ResolveParams) => diff --git a/x-pack/plugins/alerting/server/rules_client/types.ts b/x-pack/plugins/alerting/server/rules_client/types.ts index f83d55ca2bb8b..9a701e1c95c81 100644 --- a/x-pack/plugins/alerting/server/rules_client/types.ts +++ b/x-pack/plugins/alerting/server/rules_client/types.ts @@ -44,7 +44,7 @@ export type { BulkEditOperation, BulkEditFields, } from '../application/rule/methods/bulk_edit/types'; -export type { FindOptions, FindResult } from './methods/find'; +export type { FindResult } from '../application/rule/methods/find/find_rules'; export type { GetAlertSummaryParams } from './methods/get_alert_summary'; export type { GetExecutionLogByIdParams, diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.ts index 6fbd4cf07d5c8..df5db4cb2e1ab 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.ts @@ -59,7 +59,7 @@ export const getDetectionRules = async ( filter: convertRuleTagsToMatchAllKQL(ruleTags), searchFields: ['tags'], page: 1, - per_page: 1, + perPage: 1, }, }); }) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts index 22c2f9ce6489e..cb933c7cdf6ba 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts @@ -135,6 +135,7 @@ const findTestUtils = ( monitoring: match.monitoring, snooze_schedule: match.snooze_schedule, ...(hasActiveSnoozes && { active_snoozes: activeSnoozes }), + is_snoozed_until: null, } : {}), }); @@ -348,6 +349,7 @@ const findTestUtils = ( monitoring: match.monitoring, snooze_schedule: match.snooze_schedule, ...(hasActiveSnoozes && { active_snoozes: activeSnoozes }), + is_snoozed_until: null, } : {}), }); @@ -426,6 +428,7 @@ const findTestUtils = ( tags: [myTag], ...(describeType === 'internal' && { snooze_schedule: [], + is_snoozed_until: null, }), }); expect(omit(matchSecond, 'updatedAt')).to.eql({ @@ -434,6 +437,7 @@ const findTestUtils = ( tags: [myTag], ...(describeType === 'internal' && { snooze_schedule: [], + is_snoozed_until: null, }), }); break; @@ -510,6 +514,7 @@ const findTestUtils = ( execution_status: matchFirst.execution_status, ...(describeType === 'internal' && { snooze_schedule: [], + is_snoozed_until: null, }), }); expect(omit(matchSecond, 'updatedAt')).to.eql({ @@ -519,6 +524,7 @@ const findTestUtils = ( execution_status: matchSecond.execution_status, ...(describeType === 'internal' && { snooze_schedule: [], + is_snoozed_until: null, }), }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts index 9e750fd23d78a..64044222beb2d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts @@ -99,6 +99,7 @@ const findTestUtils = ( monitoring: match.monitoring, snooze_schedule: match.snooze_schedule, ...(hasActiveSnoozes && { active_snoozes: activeSnoozes }), + is_snoozed_until: null, } : {}), }); @@ -321,6 +322,7 @@ const findTestUtils = ( monitoring: match.monitoring, snooze_schedule: match.snooze_schedule, ...(hasActiveSnoozes && { active_snoozes: activeSnoozes }), + is_snoozed_until: null, } : {}), }); @@ -405,6 +407,7 @@ const findTestUtils = ( tags: [myTag], ...(describeType === 'internal' && { snooze_schedule: [], + is_snoozed_until: null, }), }); expect(omit(matchSecond, 'updatedAt')).to.eql({ @@ -413,6 +416,7 @@ const findTestUtils = ( tags: [myTag], ...(describeType === 'internal' && { snooze_schedule: [], + is_snoozed_until: null, }), }); break; @@ -495,6 +499,7 @@ const findTestUtils = ( execution_status: matchFirst.execution_status, ...(describeType === 'internal' && { snooze_schedule: [], + is_snoozed_until: null, }), }); expect(omit(matchSecond, 'updatedAt')).to.eql({ @@ -504,6 +509,7 @@ const findTestUtils = ( execution_status: matchSecond.execution_status, ...(describeType === 'internal' && { snooze_schedule: [], + is_snoozed_until: null, }), }); break; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts index 295c8acebbf1a..a83ec1e70a0a1 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts @@ -126,6 +126,7 @@ const findTestUtils = ( monitoring: match.monitoring, snooze_schedule: match.snooze_schedule, ...(hasActiveSnoozes && { active_snoozes: activeSnoozes }), + is_snoozed_until: null, } : {}), });