From f5bfe345bb87275b6e24968bd9f37dc40a0f9727 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Thu, 1 Dec 2022 21:49:03 +0100 Subject: [PATCH 01/35] add a rule management filters internal endpoint --- .../api/get_filters/response_schema.test.ts | 88 ++++++++++++++++++ .../api/get_filters/response_schema.ts | 17 ++++ .../rule_management/api/urls.ts | 10 ++ .../routes/__mocks__/request_responses.ts | 8 ++ .../rule_management/api/filters/route.test.ts | 69 ++++++++++++++ .../rule_management/api/filters/route.ts | 91 +++++++++++++++++++ .../rule_management/api/register_routes.ts | 4 + 7 files changed, 287 insertions(+) create mode 100644 x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts create mode 100644 x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts create mode 100644 x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts new file mode 100644 index 0000000000000..03bafeaab8fda --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts @@ -0,0 +1,88 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { RuleManagementFiltersResponse } from './response_schema'; + +describe('Rule management filters response schema', () => { + test('it should validate an empty response with defaults', () => { + const payload: RuleManagementFiltersResponse = { + rules_custom_installed_count: 0, + rules_prebuilt_installed_count: 0, + }; + const decoded = RuleManagementFiltersResponse.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate an extra invalid field added', () => { + const payload: RuleManagementFiltersResponse & { invalid_field: string } = { + rules_custom_installed_count: 0, + rules_prebuilt_installed_count: 0, + invalid_field: 'invalid', + }; + const decoded = RuleManagementFiltersResponse.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_field"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT validate an empty response with a negative "rules_prebuilt_installed_count" number', () => { + const payload: RuleManagementFiltersResponse = { + rules_custom_installed_count: 0, + rules_prebuilt_installed_count: -1, + }; + const decoded = RuleManagementFiltersResponse.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "-1" supplied to "rules_prebuilt_installed_count"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT validate an empty response with a negative "rules_custom_installed_count"', () => { + const payload: RuleManagementFiltersResponse = { + rules_custom_installed_count: -1, + rules_prebuilt_installed_count: 0, + }; + const decoded = RuleManagementFiltersResponse.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "-1" supplied to "rules_custom_installed_count"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT validate an empty prepackaged response if "rules_prebuilt_installed_count" is not there', () => { + const payload: RuleManagementFiltersResponse = { + rules_custom_installed_count: 0, + rules_prebuilt_installed_count: 0, + }; + // @ts-expect-error + delete payload.rules_prebuilt_installed_count; + const decoded = RuleManagementFiltersResponse.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "rules_prebuilt_installed_count"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts new file mode 100644 index 0000000000000..0e4d710782892 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts @@ -0,0 +1,17 @@ +/* + * 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 * as t from 'io-ts'; +import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; + +export type RuleManagementFiltersResponse = t.TypeOf; +export const RuleManagementFiltersResponse = t.exact( + t.type({ + rules_custom_installed_count: PositiveInteger, + rules_prebuilt_installed_count: PositiveInteger, + }) +); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts new file mode 100644 index 0000000000000..a3e73ee8fb512 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { INTERNAL_DETECTION_ENGINE_URL } from '../../../constants'; + +export const RULE_MANAGEMENT_FILTERS_URL = `${INTERNAL_DETECTION_ENGINE_URL}/rules/_filter`; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 7b6c85d486638..8239108728304 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -24,6 +24,7 @@ import { DETECTION_ENGINE_RULES_BULK_CREATE, DETECTION_ENGINE_RULES_URL_FIND, } from '../../../../../common/constants'; +import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; import { PREBUILT_RULES_STATUS_URL, @@ -33,6 +34,7 @@ import { getPerformBulkActionSchemaMock, getPerformBulkActionEditSchemaMock, } from '../../../../../common/detection_engine/rule_management/mocks'; + import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/rule_schema/mocks'; import type { QuerySignalsSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/query_signals_index_schema'; import type { SetSignalsStatusSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/set_signal_status_schema'; @@ -189,6 +191,12 @@ export const getPrepackagedRulesStatusRequest = () => path: PREBUILT_RULES_STATUS_URL, }); +export const getRuleManagementFiltersRequest = () => + requestMock.create({ + method: 'get', + path: RULE_MANAGEMENT_FILTERS_URL, + }); + export interface FindHit { page: number; perPage: number; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts new file mode 100644 index 0000000000000..24261c3e17cca --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts @@ -0,0 +1,69 @@ +/* + * 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 { getRuleManagementFilters } from './route'; + +import { + getEmptyFindResult, + getFindResultWithSingleHit, + getRuleManagementFiltersRequest, +} from '../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock } from '../../../routes/__mocks__'; + +describe('Rule management filters route', () => { + let server: ReturnType; + let { clients, context } = requestContextMock.createTools(); + + beforeEach(() => { + jest.clearAllMocks(); + server = serverMock.create(); + ({ clients, context } = requestContextMock.createTools()); + + clients.rulesClient.find.mockResolvedValue(getEmptyFindResult()); + + getRuleManagementFilters(server.router); + }); + + describe('status codes', () => { + test('returns 200', async () => { + const response = await server.inject( + getRuleManagementFiltersRequest(), + requestContextMock.convertContext(context) + ); + expect(response.status).toEqual(200); + }); + + test('catch error when finding rules throws error', async () => { + clients.rulesClient.find.mockImplementation(async () => { + throw new Error('Test error'); + }); + const response = await server.inject( + getRuleManagementFiltersRequest(), + requestContextMock.convertContext(context) + ); + expect(response.status).toEqual(500); + expect(response.body).toEqual({ + message: 'Test error', + status_code: 500, + }); + }); + }); + + describe('responses', () => { + test('1 rule installed and 1 custom rule', async () => { + clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); + const request = getRuleManagementFiltersRequest(); + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + rules_custom_installed_count: 1, + rules_prebuilt_installed_count: 1, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts new file mode 100644 index 0000000000000..0389e144b1360 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts @@ -0,0 +1,91 @@ +/* + * 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 { transformError } from '@kbn/securitysolution-es-utils'; +import { validate } from '@kbn/securitysolution-io-ts-utils'; +import type { RulesClient } from '@kbn/alerting-plugin/server'; +import { RuleManagementFiltersResponse } from '../../../../../../common/detection_engine/rule_management/api/get_filters/response_schema'; +import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../../common/detection_engine/rule_management/api/urls'; +import { buildSiemResponse } from '../../../routes/utils'; +import type { SecuritySolutionPluginRouter } from '../../../../../types'; +import { findRules } from '../../logic/search/find_rules'; + +interface RulesCount { + prebuilt: number; + custom: number; +} + +const DEFAULT_FIND_RULES_COUNT_PARAMS = { + perPage: 0, + page: 1, + sortField: undefined, + sortOrder: undefined, + fields: undefined, +}; + +async function fetchRulesCount(rulesClient: RulesClient): Promise { + const [prebuiltRules, customRules] = await Promise.all([ + findRules({ + ...DEFAULT_FIND_RULES_COUNT_PARAMS, + rulesClient, + filter: 'alert.attributes.params.immutable: true', + }), + findRules({ + ...DEFAULT_FIND_RULES_COUNT_PARAMS, + rulesClient, + filter: 'alert.attributes.params.immutable: false', + }), + ]); + + return { + prebuilt: prebuiltRules.total, + custom: customRules.total, + }; +} + +export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) => { + router.get( + { + path: RULE_MANAGEMENT_FILTERS_URL, + validate: false, + options: { + tags: ['access:securitySolution'], + }, + }, + async (context, _, response) => { + const siemResponse = buildSiemResponse(response); + const ctx = await context.resolve(['core', 'alerting']); + const rulesClient = ctx.alerting.getRulesClient(); + + try { + const { prebuilt: prebuiltRulesCount, custom: customRulesCount } = await fetchRulesCount( + rulesClient + ); + const responseBody: RuleManagementFiltersResponse = { + rules_custom_installed_count: customRulesCount, + rules_prebuilt_installed_count: prebuiltRulesCount, + }; + const [validatedBody, validationError] = validate( + responseBody, + RuleManagementFiltersResponse + ); + + if (validationError != null) { + return siemResponse.error({ statusCode: 500, body: validationError }); + } else { + return response.ok({ body: validatedBody ?? {} }); + } + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts index 90a37a7dbe7da..d801cc3cad3ba 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts @@ -9,6 +9,7 @@ import type { Logger } from '@kbn/core/server'; import type { ConfigType } from '../../../../config'; import type { SetupPlugins } from '../../../../plugin_contract'; import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { getRuleManagementFilters } from './filters/route'; import { performBulkActionRoute } from './rules/bulk_actions/route'; import { bulkCreateRulesRoute } from './rules/bulk_create_rules/route'; @@ -56,4 +57,7 @@ export const registerRuleManagementRoutes = ( // Rule tags readTagsRoute(router); + + // Rules filters + getRuleManagementFilters(router); }; From 8b794e1b106a826eb3d2a7219fed0a923469b16d Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Fri, 2 Dec 2022 11:47:42 +0100 Subject: [PATCH 02/35] rename the custom rules count field --- .../api/get_filters/response_schema.test.ts | 14 +++++++------- .../api/get_filters/response_schema.ts | 2 +- .../rule_management/api/filters/route.test.ts | 2 +- .../rule_management/api/filters/route.ts | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts index 03bafeaab8fda..874dcb7ee1fc7 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts @@ -14,7 +14,7 @@ import { RuleManagementFiltersResponse } from './response_schema'; describe('Rule management filters response schema', () => { test('it should validate an empty response with defaults', () => { const payload: RuleManagementFiltersResponse = { - rules_custom_installed_count: 0, + rules_custom_count: 0, rules_prebuilt_installed_count: 0, }; const decoded = RuleManagementFiltersResponse.decode(payload); @@ -27,7 +27,7 @@ describe('Rule management filters response schema', () => { test('it should not validate an extra invalid field added', () => { const payload: RuleManagementFiltersResponse & { invalid_field: string } = { - rules_custom_installed_count: 0, + rules_custom_count: 0, rules_prebuilt_installed_count: 0, invalid_field: 'invalid', }; @@ -41,7 +41,7 @@ describe('Rule management filters response schema', () => { test('it should NOT validate an empty response with a negative "rules_prebuilt_installed_count" number', () => { const payload: RuleManagementFiltersResponse = { - rules_custom_installed_count: 0, + rules_custom_count: 0, rules_prebuilt_installed_count: -1, }; const decoded = RuleManagementFiltersResponse.decode(payload); @@ -54,9 +54,9 @@ describe('Rule management filters response schema', () => { expect(message.schema).toEqual({}); }); - test('it should NOT validate an empty response with a negative "rules_custom_installed_count"', () => { + test('it should NOT validate an empty response with a negative "rules_custom_count"', () => { const payload: RuleManagementFiltersResponse = { - rules_custom_installed_count: -1, + rules_custom_count: -1, rules_prebuilt_installed_count: 0, }; const decoded = RuleManagementFiltersResponse.decode(payload); @@ -64,14 +64,14 @@ describe('Rule management filters response schema', () => { const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "rules_custom_installed_count"', + 'Invalid value "-1" supplied to "rules_custom_count"', ]); expect(message.schema).toEqual({}); }); test('it should NOT validate an empty prepackaged response if "rules_prebuilt_installed_count" is not there', () => { const payload: RuleManagementFiltersResponse = { - rules_custom_installed_count: 0, + rules_custom_count: 0, rules_prebuilt_installed_count: 0, }; // @ts-expect-error diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts index 0e4d710782892..5a3faa6f09f1e 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts @@ -11,7 +11,7 @@ import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; export type RuleManagementFiltersResponse = t.TypeOf; export const RuleManagementFiltersResponse = t.exact( t.type({ - rules_custom_installed_count: PositiveInteger, + rules_custom_count: PositiveInteger, rules_prebuilt_installed_count: PositiveInteger, }) ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts index 24261c3e17cca..225989a741758 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts @@ -61,7 +61,7 @@ describe('Rule management filters route', () => { expect(response.status).toEqual(200); expect(response.body).toEqual({ - rules_custom_installed_count: 1, + rules_custom_count: 1, rules_prebuilt_installed_count: 1, }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts index 0389e144b1360..d2f6dafe6672b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts @@ -66,7 +66,7 @@ export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) = rulesClient ); const responseBody: RuleManagementFiltersResponse = { - rules_custom_installed_count: customRulesCount, + rules_custom_count: customRulesCount, rules_prebuilt_installed_count: prebuiltRulesCount, }; const [validatedBody, validationError] = validate( From a7142fd58aabbe7e2d328f07d1c33349ff508506 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Fri, 2 Dec 2022 11:47:53 +0100 Subject: [PATCH 03/35] add functional tests --- .../group1/get_rule_management_filters.ts | 88 +++++++++++++++++++ .../security_and_spaces/group1/index.ts | 1 + 2 files changed, 89 insertions(+) create mode 100644 x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts new file mode 100644 index 0000000000000..899c5ac5a1bb8 --- /dev/null +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts @@ -0,0 +1,88 @@ +/* + * 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 expect from '@kbn/expect'; + +import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; +import { PREBUILT_RULES_URL } from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; +import { RULE_MANAGEMENT_FILTERS_URL } from '@kbn/security-solution-plugin/common/detection_engine/rule_management/api/urls'; + +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { + createSignalsIndex, + deleteAllAlerts, + deleteSignalsIndex, + getSimpleRule, + deleteAllTimelines, +} from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('es'); + const log = getService('log'); + + describe('get_rule_management_filters', () => { + beforeEach(async () => { + await createSignalsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteSignalsIndex(supertest, log); + await deleteAllAlerts(supertest, log); + await deleteAllTimelines(es); + }); + + it('should return expected JSON keys', async () => { + const { body } = await supertest + .get(RULE_MANAGEMENT_FILTERS_URL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + expect(Object.keys(body)).to.eql(['rules_custom_count', 'rules_prebuilt_installed_count']); + }); + + it('should return that rules_custom_count and rules_prebuilt_installed_count are zero', async () => { + const { body } = await supertest + .get(RULE_MANAGEMENT_FILTERS_URL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + expect(body.rules_custom_count).to.eql(0); + expect(body.rules_prebuilt_installed_count).to.eql(0); + }); + + it('should show the correct number of custom rules after a custom rule has been created', async () => { + await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(getSimpleRule()) + .expect(200); + + const { body } = await supertest + .get(RULE_MANAGEMENT_FILTERS_URL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + expect(body.rules_custom_count).to.eql(1); + expect(body.rules_prebuilt_installed_count).to.eql(0); + }); + + it('should show the correct number of installed prepacked rules after pre-packaged rules have been installed', async () => { + await supertest.put(PREBUILT_RULES_URL).set('kbn-xsrf', 'true').send().expect(200); + + const { body } = await supertest + .get(RULE_MANAGEMENT_FILTERS_URL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + expect(body.rules_prebuilt_installed_count).to.be.greaterThan(0); + expect(body.rules_custom_count).to.eql(0); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts index 690498a287530..24e0d5389a018 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts @@ -31,5 +31,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./find_rules')); loadTestFile(require.resolve('./find_rule_exception_references')); loadTestFile(require.resolve('./get_prepackaged_rules_status')); + loadTestFile(require.resolve('./get_rule_management_filters')); }); }; From 91f3854d9adbb4845313e5ef102fd8bd2f83a797 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Fri, 2 Dec 2022 14:15:36 +0100 Subject: [PATCH 04/35] use the new added endpoint at the UI --- .../rule_management/api/api.ts | 20 +++++++- .../api/hooks/use_bulk_action_mutation.ts | 6 ++- .../use_create_prebuilt_rules_mutation.ts | 5 +- .../api/hooks/use_create_rule_mutation.ts | 3 ++ ...use_fetch_rule_management_filters_query.ts | 48 +++++++++++++++++++ .../rule_management/logic/translations.ts | 7 +++ .../logic/use_rule_management_filters.ts | 19 ++++++++ .../rules_table_filters.tsx | 12 ++--- .../pages/rule_management/index.tsx | 8 ++-- 9 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_management_filters.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index e7fe4dd64fb7d..04aac0e93af64 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -11,6 +11,7 @@ import type { ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../common/detection_engine/rule_management/api/urls'; import type { BulkActionsDryRunErrCode } from '../../../../common/constants'; import { DETECTION_ENGINE_RULES_BULK_ACTION, @@ -33,7 +34,7 @@ import type { BulkActionDuplicatePayload, } from '../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { BulkActionType } from '../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; - +import type { RuleManagementFiltersResponse } from '../../../../common/detection_engine/rule_management/api/get_filters/response_schema'; import type { RuleResponse, PreviewResponse, @@ -403,6 +404,23 @@ export const fetchTags = async ({ signal }: { signal?: AbortSignal }): Promise => + KibanaServices.get().http.fetch(RULE_MANAGEMENT_FILTERS_URL, { + method: 'GET', + signal, + }); + /** * Get pre packaged rules Status * diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts index 3f652063707c2..95172779475e3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts @@ -10,11 +10,12 @@ import type { IHttpFetchError } from '@kbn/core/public'; import { BulkActionType } from '../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import type { BulkActionErrorResponse, BulkActionResponse, PerformBulkActionProps } from '../api'; import { performBulkAction } from '../api'; +import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../common/constants'; import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFindRulesQuery, useUpdateRulesCache } from './use_find_rules_query'; import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; -import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../common/constants'; +import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; export const BULK_ACTION_MUTATION_KEY = ['POST', DETECTION_ENGINE_RULES_BULK_ACTION]; @@ -27,6 +28,7 @@ export const useBulkActionMutation = ( ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); + const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); const invalidateFetchPrebuiltRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); const updateRulesCache = useUpdateRulesCache(); @@ -66,11 +68,13 @@ export const useBulkActionMutation = ( case BulkActionType.delete: invalidateFindRulesQuery(); invalidateFetchRuleByIdQuery(); + invalidateFetchRuleManagementFilters(); invalidateFetchTagsQuery(); invalidateFetchPrebuiltRulesStatusQuery(); break; case BulkActionType.duplicate: invalidateFindRulesQuery(); + invalidateFetchRuleManagementFilters(); invalidateFetchPrebuiltRulesStatusQuery(); break; case BulkActionType.edit: diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts index a88f011ae8ea4..63a6d67bc6f18 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts @@ -6,12 +6,13 @@ */ import type { UseMutationOptions } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query'; +import { PREBUILT_RULES_URL } from '../../../../../common/detection_engine/prebuilt_rules/api/urls'; import type { CreatePrepackagedRulesResponse } from '../api'; import { createPrepackagedRules } from '../api'; import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; -import { PREBUILT_RULES_URL } from '../../../../../common/detection_engine/prebuilt_rules/api/urls'; +import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; export const CREATE_PREBUILT_RULES_MUTATION_KEY = ['PUT', PREBUILT_RULES_URL]; @@ -20,6 +21,7 @@ export const useCreatePrebuiltRulesMutation = ( ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidatePrePackagedRulesStatus = useInvalidateFetchPrebuiltRulesStatusQuery(); + const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); return useMutation(() => createPrepackagedRules(), { @@ -30,6 +32,7 @@ export const useCreatePrebuiltRulesMutation = ( // the number of rules might change after the installation invalidatePrePackagedRulesStatus(); invalidateFindRulesQuery(); + invalidateFetchRuleManagementFilters(); invalidateFetchTagsQuery(); if (options?.onSettled) { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts index a2901e1ed88bc..17d8eb3719c14 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts @@ -14,6 +14,7 @@ import type { import { transformOutput } from '../../../../detections/containers/detection_engine/rules/transforms'; import { createRule } from '../api'; import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; +import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; @@ -23,6 +24,7 @@ export const useCreateRuleMutation = ( options?: UseMutationOptions ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); + const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); const invalidateFetchPrePackagedRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); @@ -34,6 +36,7 @@ export const useCreateRuleMutation = ( onSettled: (...args) => { invalidateFetchPrePackagedRulesStatusQuery(); invalidateFindRulesQuery(); + invalidateFetchRuleManagementFilters(); invalidateFetchTagsQuery(); if (options?.onSettled) { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts new file mode 100644 index 0000000000000..ea394d829fc03 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts @@ -0,0 +1,48 @@ +/* + * 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 { useCallback } from 'react'; +import type { UseQueryOptions } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import type { RuleManagementFiltersResponse } from '../../../../../common/detection_engine/rule_management/api/get_filters/response_schema'; +import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; +import { fetchRuleManagementFilters } from '../api'; +import { DEFAULT_QUERY_OPTIONS } from './constants'; + +export const RULE_MANAGEMENT_FILTERS_QUERY_KEY = ['GET', RULE_MANAGEMENT_FILTERS_URL]; + +export const useFetchRuleManagementFiltersQuery = ( + options?: UseQueryOptions +) => { + return useQuery( + RULE_MANAGEMENT_FILTERS_QUERY_KEY, + async ({ signal }) => { + const response = await fetchRuleManagementFilters({ signal }); + return response; + }, + { + ...DEFAULT_QUERY_OPTIONS, + ...options, + } + ); +}; + +/** + * We should use this hook to invalidate the prepackaged rules cache. For + * example, rule mutations that affect rule set size, like creation or deletion, + * should lead to cache invalidation. + * + * @returns A rules cache invalidation callback + */ +export const useInvalidateFetchRuleManagementFiltersQuery = () => { + const queryClient = useQueryClient(); + + return useCallback(() => { + queryClient.invalidateQueries(RULE_MANAGEMENT_FILTERS_QUERY_KEY, { + refetchType: 'active', + }); + }, [queryClient]); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts index 36735f1ff11e1..2a85ad68019ba 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts @@ -14,6 +14,13 @@ export const RULE_AND_TIMELINE_FETCH_FAILURE = i18n.translate( } ); +export const RULE_MANAGEMENT_FILTERS_FETCH_FAILURE = i18n.translate( + 'xpack.securitySolution.containers.detectionEngine.ruleManagementFiltersFetchFailure', + { + defaultMessage: 'Failed to fetch Rule management filters', + } +); + export const RULE_ADD_FAILURE = i18n.translate( 'xpack.securitySolution.containers.detectionEngine.addRuleFailDescription', { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_management_filters.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_management_filters.ts new file mode 100644 index 0000000000000..a16f433b993a1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_management_filters.ts @@ -0,0 +1,19 @@ +/* + * 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 { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useFetchRuleManagementFiltersQuery } from '../api/hooks/use_fetch_rule_management_filters_query'; +import * as i18n from './translations'; + +export const useRuleManagementFilters = () => { + const { addError } = useAppToasts(); + + return useFetchRuleManagementFiltersQuery({ + onError: (err) => { + addError(err, { title: i18n.RULE_MANAGEMENT_FILTERS_FETCH_FAILURE }); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx index 0636048384714..68dfcf0c18497 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx @@ -9,9 +9,9 @@ import { EuiFilterButton, EuiFilterGroup, EuiFlexGroup, EuiFlexItem } from '@ela import { isEqual } from 'lodash/fp'; import React, { useCallback } from 'react'; import styled from 'styled-components'; +import { useRuleManagementFilters } from '../../../../rule_management/logic/use_rule_management_filters'; import { RULES_TABLE_ACTIONS } from '../../../../../common/lib/apm/user_actions'; import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; -import { usePrePackagedRulesStatus } from '../../../../rule_management/logic/use_pre_packaged_rules_status'; import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; import { useRulesTableContext } from '../rules_table/rules_table_context'; import { TagsFilterPopover } from './tags_filter_popover'; @@ -33,9 +33,9 @@ const RulesTableFiltersComponent = () => { actions: { setFilterOptions }, } = useRulesTableContext(); const { data: allTags = [] } = useTags(); - const { data: prePackagedRulesStatus } = usePrePackagedRulesStatus(); - const rulesCustomInstalled = prePackagedRulesStatus?.rules_custom_installed; - const rulesInstalled = prePackagedRulesStatus?.rules_installed; + const { data: filtersData } = useRuleManagementFilters(); + const rulesCustomCount = filtersData?.rules_custom_count; + const rulesPrebuiltInstalledCount = filtersData?.rules_prebuilt_installed_count; const { showCustomRules, showElasticRules, tags: selectedTags } = filterOptions; @@ -90,7 +90,7 @@ const RulesTableFiltersComponent = () => { withNext > {i18n.ELASTIC_RULES} - {rulesInstalled != null ? ` (${rulesInstalled})` : ''} + {rulesPrebuiltInstalledCount != null ? ` (${rulesPrebuiltInstalledCount ?? ''})` : ''} { data-test-subj="showCustomRulesFilterButton" > {i18n.CUSTOM_RULES} - {rulesCustomInstalled != null ? ` (${rulesCustomInstalled})` : ''} + {rulesCustomCount != null ? ` (${rulesCustomCount})` : ''} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx index a76c064103cbe..f02075809a46d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx @@ -32,7 +32,6 @@ import { useListsConfig } from '../../../../detections/containers/detection_engi import { redirectToDetections } from '../../../../detections/pages/detection_engine/rules/helpers'; import { useInvalidateFindRulesQuery } from '../../../rule_management/api/hooks/use_find_rules_query'; -import { useInvalidateFetchPrebuiltRulesStatusQuery } from '../../../rule_management/api/hooks/use_fetch_prebuilt_rules_status_query'; import { importRules } from '../../../rule_management/logic'; import { usePrePackagedRulesInstallationStatus } from '../../../rule_management/logic/use_pre_packaged_rules_installation_status'; import { usePrePackagedTimelinesInstallationStatus } from '../../../rule_management/logic/use_pre_packaged_timelines_installation_status'; @@ -42,17 +41,18 @@ import { RulesTableContextProvider } from '../../components/rules_table/rules_ta import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; import { RulesPageTourComponent } from '../../components/rules_table/alternative_tour/tour'; +import { useInvalidateFetchRuleManagementFiltersQuery } from '../../../rule_management/api/hooks/use_fetch_rule_management_filters_query'; const RulesPageComponent: React.FC = () => { const [isImportModalVisible, showImportModal, hideImportModal] = useBoolState(); const [isValueListFlyoutVisible, showValueListFlyout, hideValueListFlyout] = useBoolState(); const { navigateToApp } = useKibana().services.application; const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchPrebuiltRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); + const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateRules = useCallback(() => { invalidateFindRulesQuery(); - invalidateFetchPrebuiltRulesStatusQuery(); - }, [invalidateFindRulesQuery, invalidateFetchPrebuiltRulesStatusQuery]); + invalidateFetchRuleManagementFilters(); + }, [invalidateFindRulesQuery, invalidateFetchRuleManagementFilters]); const [ { From f9606fa8ec0d270b3918c255f76efa76362397d9 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Fri, 2 Dec 2022 18:30:50 +0100 Subject: [PATCH 05/35] add tags field for the rule management filters endpoint --- .../alerting/server/rules_client.mock.ts | 2 +- .../api/get_filters/response_schema.test.ts | 33 +++++++++++++++++++ .../api/get_filters/response_schema.ts | 1 + .../rule_management/api/filters/route.test.ts | 8 ++++- .../rule_management/api/filters/route.ts | 17 ++++++++-- 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/alerting/server/rules_client.mock.ts b/x-pack/plugins/alerting/server/rules_client.mock.ts index cef3381600fa1..585d3b1c6aa05 100644 --- a/x-pack/plugins/alerting/server/rules_client.mock.ts +++ b/x-pack/plugins/alerting/server/rules_client.mock.ts @@ -12,7 +12,7 @@ export type RulesClientMock = jest.Mocked; const createRulesClientMock = () => { const mocked: RulesClientMock = { - aggregate: jest.fn(), + aggregate: jest.fn().mockReturnValue({ alertExecutionStatus: {}, ruleLastRunOutcome: {} }), create: jest.fn(), get: jest.fn(), resolve: jest.fn(), diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts index 874dcb7ee1fc7..4f0a5424d7484 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts @@ -16,6 +16,21 @@ describe('Rule management filters response schema', () => { const payload: RuleManagementFiltersResponse = { rules_custom_count: 0, rules_prebuilt_installed_count: 0, + tags: [], + }; + const decoded = RuleManagementFiltersResponse.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an non empty response with defaults', () => { + const payload: RuleManagementFiltersResponse = { + rules_custom_count: 10, + rules_prebuilt_installed_count: 20, + tags: ['a', 'b', 'c'], }; const decoded = RuleManagementFiltersResponse.decode(payload); const checked = exactCheck(payload, decoded); @@ -29,6 +44,7 @@ describe('Rule management filters response schema', () => { const payload: RuleManagementFiltersResponse & { invalid_field: string } = { rules_custom_count: 0, rules_prebuilt_installed_count: 0, + tags: [], invalid_field: 'invalid', }; const decoded = RuleManagementFiltersResponse.decode(payload); @@ -43,6 +59,7 @@ describe('Rule management filters response schema', () => { const payload: RuleManagementFiltersResponse = { rules_custom_count: 0, rules_prebuilt_installed_count: -1, + tags: [], }; const decoded = RuleManagementFiltersResponse.decode(payload); const checked = exactCheck(payload, decoded); @@ -58,6 +75,7 @@ describe('Rule management filters response schema', () => { const payload: RuleManagementFiltersResponse = { rules_custom_count: -1, rules_prebuilt_installed_count: 0, + tags: [], }; const decoded = RuleManagementFiltersResponse.decode(payload); const checked = exactCheck(payload, decoded); @@ -73,6 +91,7 @@ describe('Rule management filters response schema', () => { const payload: RuleManagementFiltersResponse = { rules_custom_count: 0, rules_prebuilt_installed_count: 0, + tags: [], }; // @ts-expect-error delete payload.rules_prebuilt_installed_count; @@ -85,4 +104,18 @@ describe('Rule management filters response schema', () => { ]); expect(message.schema).toEqual({}); }); + + test('it should NOT validate an empty response with wrong "tags"', () => { + const payload: RuleManagementFiltersResponse = { + rules_custom_count: 0, + rules_prebuilt_installed_count: 0, + tags: [1] as unknown as string[], + }; + const decoded = RuleManagementFiltersResponse.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "tags"']); + expect(message.schema).toEqual({}); + }); }); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts index 5a3faa6f09f1e..0a0f43d7ca58f 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts @@ -13,5 +13,6 @@ export const RuleManagementFiltersResponse = t.exact( t.type({ rules_custom_count: PositiveInteger, rules_prebuilt_installed_count: PositiveInteger, + tags: t.array(t.string), }) ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts index 225989a741758..8880047826762 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts @@ -54,8 +54,13 @@ describe('Rule management filters route', () => { }); describe('responses', () => { - test('1 rule installed and 1 custom rule', async () => { + test('1 rule installed, 1 custom rule and 3 tags', async () => { clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.rulesClient.aggregate.mockResolvedValue({ + alertExecutionStatus: {}, + ruleLastRunOutcome: {}, + ruleTags: ['a', 'b', 'c'], + }); const request = getRuleManagementFiltersRequest(); const response = await server.inject(request, requestContextMock.convertContext(context)); @@ -63,6 +68,7 @@ describe('Rule management filters route', () => { expect(response.body).toEqual({ rules_custom_count: 1, rules_prebuilt_installed_count: 1, + tags: ['a', 'b', 'c'], }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts index d2f6dafe6672b..d333928fee2cb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts @@ -47,6 +47,17 @@ async function fetchRulesCount(rulesClient: RulesClient): Promise { }; } +async function fetchRuleTags(rulesClient: RulesClient): Promise { + const res = await rulesClient.aggregate({ + options: { + fields: ['tags'], + filter: undefined, + }, + }); + + return res.ruleTags ?? []; +} + export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) => { router.get( { @@ -62,12 +73,12 @@ export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) = const rulesClient = ctx.alerting.getRulesClient(); try { - const { prebuilt: prebuiltRulesCount, custom: customRulesCount } = await fetchRulesCount( - rulesClient - ); + const [{ prebuilt: prebuiltRulesCount, custom: customRulesCount }, tags] = + await Promise.all([fetchRulesCount(rulesClient), fetchRuleTags(rulesClient)]); const responseBody: RuleManagementFiltersResponse = { rules_custom_count: customRulesCount, rules_prebuilt_installed_count: prebuiltRulesCount, + tags, }; const [validatedBody, validationError] = validate( responseBody, From ed7eda6edc72273c30530e2fa281f29328266a5a Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sat, 3 Dec 2022 16:29:38 +0100 Subject: [PATCH 06/35] fetch tags from the new endpoint --- .../rule_management/api/api.test.ts | 21 --------- .../rule_management/api/api.ts | 15 ------- .../api/hooks/use_bulk_action_mutation.ts | 4 -- .../use_create_prebuilt_rules_mutation.ts | 3 -- .../api/hooks/use_create_rule_mutation.ts | 3 -- .../api/hooks/use_fetch_tags_query.ts | 43 ------------------- .../api/hooks/use_update_rule_mutation.ts | 8 ++-- .../rule_management/logic/translations.ts | 7 --- .../rule_management/logic/use_tags.ts | 24 ----------- .../bulk_actions/forms/tags_form.tsx | 4 +- .../rules_table_filters.tsx | 3 +- 11 files changed, 7 insertions(+), 128 deletions(-) delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_tags_query.ts delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_tags.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts index 265cf9d42e9d2..bf1ac32d2bc78 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts @@ -31,7 +31,6 @@ import { createPrepackagedRules, importRules, exportRules, - fetchTags, getPrePackagedRulesStatus, previewRule, findRuleExceptionReferences, @@ -630,26 +629,6 @@ describe('Detections Rules API', () => { }); }); - describe('fetchTags', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(['some', 'tags']); - }); - - test('check parameter url when fetching tags', async () => { - await fetchTags({ signal: abortCtrl.signal }); - expect(fetchMock).toHaveBeenCalledWith('/api/detection_engine/tags', { - signal: abortCtrl.signal, - method: 'GET', - }); - }); - - test('happy path', async () => { - const resp = await fetchTags({ signal: abortCtrl.signal }); - expect(resp).toEqual(['some', 'tags']); - }); - }); - describe('getPrePackagedRulesStatus', () => { const prePackagedRulesStatus = { rules_custom_installed: 33, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index 04aac0e93af64..ea79c74efbb02 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -389,21 +389,6 @@ export const exportRules = async ({ }); }; -export type FetchTagsResponse = string[]; - -/** - * Fetch all unique Tags used by Rules - * - * @param signal to cancel request - * - * @throws An error if response is not OK - */ -export const fetchTags = async ({ signal }: { signal?: AbortSignal }): Promise => - KibanaServices.get().http.fetch(DETECTION_ENGINE_TAGS_URL, { - method: 'GET', - signal, - }); - /** * Fetch rule management related filters * diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts index 95172779475e3..24d3948097dcc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts @@ -13,7 +13,6 @@ import { performBulkAction } from '../api'; import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../common/constants'; import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFindRulesQuery, useUpdateRulesCache } from './use_find_rules_query'; -import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; @@ -29,7 +28,6 @@ export const useBulkActionMutation = ( const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); - const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); const invalidateFetchPrebuiltRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); const updateRulesCache = useUpdateRulesCache(); @@ -69,7 +67,6 @@ export const useBulkActionMutation = ( invalidateFindRulesQuery(); invalidateFetchRuleByIdQuery(); invalidateFetchRuleManagementFilters(); - invalidateFetchTagsQuery(); invalidateFetchPrebuiltRulesStatusQuery(); break; case BulkActionType.duplicate: @@ -86,7 +83,6 @@ export const useBulkActionMutation = ( invalidateFindRulesQuery(); } invalidateFetchRuleByIdQuery(); - invalidateFetchTagsQuery(); break; } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts index 63a6d67bc6f18..41bce8f0cc154 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts @@ -11,7 +11,6 @@ import type { CreatePrepackagedRulesResponse } from '../api'; import { createPrepackagedRules } from '../api'; import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; -import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; export const CREATE_PREBUILT_RULES_MUTATION_KEY = ['PUT', PREBUILT_RULES_URL]; @@ -22,7 +21,6 @@ export const useCreatePrebuiltRulesMutation = ( const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidatePrePackagedRulesStatus = useInvalidateFetchPrebuiltRulesStatusQuery(); const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); - const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); return useMutation(() => createPrepackagedRules(), { ...options, @@ -33,7 +31,6 @@ export const useCreatePrebuiltRulesMutation = ( invalidatePrePackagedRulesStatus(); invalidateFindRulesQuery(); invalidateFetchRuleManagementFilters(); - invalidateFetchTagsQuery(); if (options?.onSettled) { options.onSettled(...args); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts index 17d8eb3719c14..f4ca1b6ce6e3e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts @@ -15,7 +15,6 @@ import { transformOutput } from '../../../../detections/containers/detection_eng import { createRule } from '../api'; import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; -import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; export const CREATE_RULE_MUTATION_KEY = ['POST', DETECTION_ENGINE_RULES_URL]; @@ -25,7 +24,6 @@ export const useCreateRuleMutation = ( ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); - const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); const invalidateFetchPrePackagedRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); return useMutation( @@ -37,7 +35,6 @@ export const useCreateRuleMutation = ( invalidateFetchPrePackagedRulesStatusQuery(); invalidateFindRulesQuery(); invalidateFetchRuleManagementFilters(); - invalidateFetchTagsQuery(); if (options?.onSettled) { options.onSettled(...args); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_tags_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_tags_query.ts deleted file mode 100644 index c09ae5d6cb56d..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_tags_query.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { UseQueryOptions } from '@tanstack/react-query'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { useCallback } from 'react'; -import { DETECTION_ENGINE_TAGS_URL } from '../../../../../common/constants'; -import type { FetchTagsResponse } from '../api'; -import { fetchTags } from '../api'; -import { DEFAULT_QUERY_OPTIONS } from './constants'; - -const TAGS_QUERY_KEY = ['GET', DETECTION_ENGINE_TAGS_URL]; - -/** - * Hook for using the list of Tags from the Detection Engine API - * - */ -export const useFetchTagsQuery = (options?: UseQueryOptions) => { - return useQuery( - TAGS_QUERY_KEY, - async ({ signal }) => { - return fetchTags({ signal }); - }, - { - ...DEFAULT_QUERY_OPTIONS, - ...options, - } - ); -}; - -export const useInvalidateFetchTagsQuery = () => { - const queryClient = useQueryClient(); - - return useCallback(() => { - queryClient.invalidateQueries(TAGS_QUERY_KEY, { - refetchType: 'active', - }); - }, [queryClient]); -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts index 13247852521db..21d0c78f49b41 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts @@ -11,11 +11,11 @@ import type { RuleUpdateProps, } from '../../../../../common/detection_engine/rule_schema'; import { transformOutput } from '../../../../detections/containers/detection_engine/rules/transforms'; +import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { updateRule } from '../api'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; -import { useInvalidateFetchTagsQuery } from './use_fetch_tags_query'; import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; -import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; +import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; export const UPDATE_RULE_MUTATION_KEY = ['PUT', DETECTION_ENGINE_RULES_URL]; @@ -23,7 +23,7 @@ export const useUpdateRuleMutation = ( options?: UseMutationOptions ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchTagsQuery = useInvalidateFetchTagsQuery(); + const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); return useMutation( @@ -34,7 +34,7 @@ export const useUpdateRuleMutation = ( onSettled: (...args) => { invalidateFindRulesQuery(); invalidateFetchRuleByIdQuery(); - invalidateFetchTagsQuery(); + invalidateFetchRuleManagementFilters(); if (options?.onSettled) { options.onSettled(...args); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts index 2a85ad68019ba..a89ec04e4002c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts @@ -55,10 +55,3 @@ export const TIMELINE_PREPACKAGED_SUCCESS = i18n.translate( defaultMessage: 'Installed pre-packaged timeline templates from elastic', } ); - -export const TAG_FETCH_FAILURE = i18n.translate( - 'xpack.securitySolution.containers.detectionEngine.tagFetchFailDescription', - { - defaultMessage: 'Failed to fetch Tags', - } -); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_tags.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_tags.ts deleted file mode 100644 index ab3671f262f8a..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_tags.ts +++ /dev/null @@ -1,24 +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 { useAppToasts } from '../../../common/hooks/use_app_toasts'; -import { useFetchTagsQuery } from '../api/hooks/use_fetch_tags_query'; -import * as i18n from './translations'; - -/** - * Hook for using the list of Tags from the Detection Engine API - * - */ -export const useTags = () => { - const { addError } = useAppToasts(); - - return useFetchTagsQuery({ - onError: (err) => { - addError(err, { title: i18n.TAG_FETCH_FAILURE }); - }, - }); -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx index 4288342c03d10..841fe6b25557c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx @@ -9,6 +9,7 @@ import { EuiCallOut, EuiFormRow } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import React, { useMemo } from 'react'; +import { useRuleManagementFilters } from '../../../../../rule_management/logic/use_rule_management_filters'; import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { BulkActionEditType } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import * as i18n from '../../../../../../detections/pages/detection_engine/rules/translations'; @@ -25,7 +26,6 @@ import { } from '../../../../../../shared_imports'; import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; -import { useTags } from '../../../../../rule_management/logic/use_tags'; type TagsEditActions = | BulkActionEditType.add_tags @@ -78,7 +78,7 @@ interface TagsFormProps { } const TagsFormComponent = ({ editAction, rulesCount, onClose, onConfirm }: TagsFormProps) => { - const { data: tags = [] } = useTags(); + const { data: { tags } = { tags: [] } } = useRuleManagementFilters(); const { form } = useForm({ defaultValue: initialFormData, schema, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx index 68dfcf0c18497..3370c89f49d84 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx @@ -15,7 +15,6 @@ import { useStartTransaction } from '../../../../../common/lib/apm/use_start_tra import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; import { useRulesTableContext } from '../rules_table/rules_table_context'; import { TagsFilterPopover } from './tags_filter_popover'; -import { useTags } from '../../../../rule_management/logic/use_tags'; import { RuleSearchField } from './rule_search_field'; const FilterWrapper = styled(EuiFlexGroup)` @@ -32,8 +31,8 @@ const RulesTableFiltersComponent = () => { state: { filterOptions }, actions: { setFilterOptions }, } = useRulesTableContext(); - const { data: allTags = [] } = useTags(); const { data: filtersData } = useRuleManagementFilters(); + const allTags = filtersData?.tags ?? []; const rulesCustomCount = filtersData?.rules_custom_count; const rulesPrebuiltInstalledCount = filtersData?.rules_prebuilt_installed_count; From 6aca19bca653e57eed8c091af7f22e2eb937a459 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sat, 3 Dec 2022 21:33:39 +0100 Subject: [PATCH 07/35] rename the new endpoint --- .../info}/response_schema.test.ts | 30 ++--- .../info}/response_schema.ts | 4 +- .../rule_management/api/urls.ts | 2 +- .../rule_management/api/api.ts | 13 +- .../api/hooks/use_bulk_action_mutation.ts | 8 +- .../use_create_prebuilt_rules_mutation.ts | 6 +- .../api/hooks/use_create_rule_mutation.ts | 6 +- ...query.ts => use_fetch_rules_info_query.ts} | 18 ++- .../api/hooks/use_update_rule_mutation.ts | 6 +- ...anagement_filters.ts => use_rules_info.ts} | 6 +- .../bulk_actions/forms/tags_form.tsx | 4 +- .../rules_table_filters.tsx | 10 +- .../pages/rule_management/index.tsx | 8 +- .../routes/__mocks__/request_responses.ts | 6 +- .../rule_management/api/register_routes.ts | 4 +- .../api/{filters => rules/info}/route.test.ts | 16 +-- .../api/{filters => rules/info}/route.ts | 25 ++-- .../group1/get_rule_management_filters.ts | 88 ------------- .../group1/get_rules_info.ts | 119 ++++++++++++++++++ .../security_and_spaces/group1/index.ts | 2 +- .../utils/get_simple_rule.ts | 1 + 21 files changed, 206 insertions(+), 176 deletions(-) rename x-pack/plugins/security_solution/common/detection_engine/rule_management/api/{get_filters => rules/info}/response_schema.test.ts (79%) rename x-pack/plugins/security_solution/common/detection_engine/rule_management/api/{get_filters => rules/info}/response_schema.ts (77%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/{use_fetch_rule_management_filters_query.ts => use_fetch_rules_info_query.ts} (61%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/{use_rule_management_filters.ts => use_rules_info.ts} (72%) rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/{filters => rules/info}/route.test.ts (83%) rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/{filters => rules/info}/route.ts (75%) delete mode 100644 x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts create mode 100644 x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts similarity index 79% rename from x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts index 4f0a5424d7484..3c412b8781929 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts @@ -9,16 +9,16 @@ import { left } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { RuleManagementFiltersResponse } from './response_schema'; +import { RulesInfoResponse } from './response_schema'; describe('Rule management filters response schema', () => { test('it should validate an empty response with defaults', () => { - const payload: RuleManagementFiltersResponse = { + const payload: RulesInfoResponse = { rules_custom_count: 0, rules_prebuilt_installed_count: 0, tags: [], }; - const decoded = RuleManagementFiltersResponse.decode(payload); + const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -27,12 +27,12 @@ describe('Rule management filters response schema', () => { }); test('it should validate an non empty response with defaults', () => { - const payload: RuleManagementFiltersResponse = { + const payload: RulesInfoResponse = { rules_custom_count: 10, rules_prebuilt_installed_count: 20, tags: ['a', 'b', 'c'], }; - const decoded = RuleManagementFiltersResponse.decode(payload); + const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -41,13 +41,13 @@ describe('Rule management filters response schema', () => { }); test('it should not validate an extra invalid field added', () => { - const payload: RuleManagementFiltersResponse & { invalid_field: string } = { + const payload: RulesInfoResponse & { invalid_field: string } = { rules_custom_count: 0, rules_prebuilt_installed_count: 0, tags: [], invalid_field: 'invalid', }; - const decoded = RuleManagementFiltersResponse.decode(payload); + const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -56,12 +56,12 @@ describe('Rule management filters response schema', () => { }); test('it should NOT validate an empty response with a negative "rules_prebuilt_installed_count" number', () => { - const payload: RuleManagementFiltersResponse = { + const payload: RulesInfoResponse = { rules_custom_count: 0, rules_prebuilt_installed_count: -1, tags: [], }; - const decoded = RuleManagementFiltersResponse.decode(payload); + const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -72,12 +72,12 @@ describe('Rule management filters response schema', () => { }); test('it should NOT validate an empty response with a negative "rules_custom_count"', () => { - const payload: RuleManagementFiltersResponse = { + const payload: RulesInfoResponse = { rules_custom_count: -1, rules_prebuilt_installed_count: 0, tags: [], }; - const decoded = RuleManagementFiltersResponse.decode(payload); + const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -88,14 +88,14 @@ describe('Rule management filters response schema', () => { }); test('it should NOT validate an empty prepackaged response if "rules_prebuilt_installed_count" is not there', () => { - const payload: RuleManagementFiltersResponse = { + const payload: RulesInfoResponse = { rules_custom_count: 0, rules_prebuilt_installed_count: 0, tags: [], }; // @ts-expect-error delete payload.rules_prebuilt_installed_count; - const decoded = RuleManagementFiltersResponse.decode(payload); + const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); @@ -106,12 +106,12 @@ describe('Rule management filters response schema', () => { }); test('it should NOT validate an empty response with wrong "tags"', () => { - const payload: RuleManagementFiltersResponse = { + const payload: RulesInfoResponse = { rules_custom_count: 0, rules_prebuilt_installed_count: 0, tags: [1] as unknown as string[], }; - const decoded = RuleManagementFiltersResponse.decode(payload); + const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = pipe(checked, foldLeftRight); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.ts similarity index 77% rename from x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.ts index 0a0f43d7ca58f..925223ccb8ba3 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/get_filters/response_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.ts @@ -8,8 +8,8 @@ import * as t from 'io-ts'; import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; -export type RuleManagementFiltersResponse = t.TypeOf; -export const RuleManagementFiltersResponse = t.exact( +export type RulesInfoResponse = t.TypeOf; +export const RulesInfoResponse = t.exact( t.type({ rules_custom_count: PositiveInteger, rules_prebuilt_installed_count: PositiveInteger, diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts index a3e73ee8fb512..c5b673a48749f 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts @@ -7,4 +7,4 @@ import { INTERNAL_DETECTION_ENGINE_URL } from '../../../constants'; -export const RULE_MANAGEMENT_FILTERS_URL = `${INTERNAL_DETECTION_ENGINE_URL}/rules/_filter`; +export const RULES_INFO_URL = `${INTERNAL_DETECTION_ENGINE_URL}/rules/_info`; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index ea79c74efbb02..fcb684526e1fc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -11,14 +11,14 @@ import type { ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../common/detection_engine/rule_management/api/urls'; +import type { RulesInfoResponse } from '../../../../common/detection_engine/rule_management/api/rules/info/response_schema'; +import { RULES_INFO_URL } from '../../../../common/detection_engine/rule_management/api/urls'; import type { BulkActionsDryRunErrCode } from '../../../../common/constants'; import { DETECTION_ENGINE_RULES_BULK_ACTION, DETECTION_ENGINE_RULES_PREVIEW, DETECTION_ENGINE_RULES_URL, DETECTION_ENGINE_RULES_URL_FIND, - DETECTION_ENGINE_TAGS_URL, } from '../../../../common/constants'; import { @@ -34,7 +34,6 @@ import type { BulkActionDuplicatePayload, } from '../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { BulkActionType } from '../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; -import type { RuleManagementFiltersResponse } from '../../../../common/detection_engine/rule_management/api/get_filters/response_schema'; import type { RuleResponse, PreviewResponse, @@ -390,18 +389,18 @@ export const exportRules = async ({ }; /** - * Fetch rule management related filters + * Fetch rules information like installed count, tags and etc * * @param signal to cancel request * * @throws An error if response is not OK */ -export const fetchRuleManagementFilters = async ({ +export const fetchRulesInfo = async ({ signal, }: { signal?: AbortSignal; -}): Promise => - KibanaServices.get().http.fetch(RULE_MANAGEMENT_FILTERS_URL, { +}): Promise => + KibanaServices.get().http.fetch(RULES_INFO_URL, { method: 'GET', signal, }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts index 24d3948097dcc..133630e5c5cf4 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts @@ -14,7 +14,7 @@ import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../common/consta import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFindRulesQuery, useUpdateRulesCache } from './use_find_rules_query'; import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; -import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; +import { useInvalidateFetchRulesInfoQuery } from './use_fetch_rules_info_query'; export const BULK_ACTION_MUTATION_KEY = ['POST', DETECTION_ENGINE_RULES_BULK_ACTION]; @@ -27,7 +27,7 @@ export const useBulkActionMutation = ( ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); - const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); const invalidateFetchPrebuiltRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); const updateRulesCache = useUpdateRulesCache(); @@ -66,12 +66,12 @@ export const useBulkActionMutation = ( case BulkActionType.delete: invalidateFindRulesQuery(); invalidateFetchRuleByIdQuery(); - invalidateFetchRuleManagementFilters(); + invalidateFetchRulesInfo(); invalidateFetchPrebuiltRulesStatusQuery(); break; case BulkActionType.duplicate: invalidateFindRulesQuery(); - invalidateFetchRuleManagementFilters(); + invalidateFetchRulesInfo(); invalidateFetchPrebuiltRulesStatusQuery(); break; case BulkActionType.edit: diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts index 41bce8f0cc154..8be2539653b4b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts @@ -11,7 +11,7 @@ import type { CreatePrepackagedRulesResponse } from '../api'; import { createPrepackagedRules } from '../api'; import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; -import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; +import { useInvalidateFetchRulesInfoQuery } from './use_fetch_rules_info_query'; export const CREATE_PREBUILT_RULES_MUTATION_KEY = ['PUT', PREBUILT_RULES_URL]; @@ -20,7 +20,7 @@ export const useCreatePrebuiltRulesMutation = ( ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidatePrePackagedRulesStatus = useInvalidateFetchPrebuiltRulesStatusQuery(); - const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); return useMutation(() => createPrepackagedRules(), { ...options, @@ -30,7 +30,7 @@ export const useCreatePrebuiltRulesMutation = ( // the number of rules might change after the installation invalidatePrePackagedRulesStatus(); invalidateFindRulesQuery(); - invalidateFetchRuleManagementFilters(); + invalidateFetchRulesInfo(); if (options?.onSettled) { options.onSettled(...args); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts index f4ca1b6ce6e3e..c06807855e846 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts @@ -14,7 +14,7 @@ import type { import { transformOutput } from '../../../../detections/containers/detection_engine/rules/transforms'; import { createRule } from '../api'; import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; -import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; +import { useInvalidateFetchRulesInfoQuery } from './use_fetch_rules_info_query'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; export const CREATE_RULE_MUTATION_KEY = ['POST', DETECTION_ENGINE_RULES_URL]; @@ -23,7 +23,7 @@ export const useCreateRuleMutation = ( options?: UseMutationOptions ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); const invalidateFetchPrePackagedRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); return useMutation( @@ -34,7 +34,7 @@ export const useCreateRuleMutation = ( onSettled: (...args) => { invalidateFetchPrePackagedRulesStatusQuery(); invalidateFindRulesQuery(); - invalidateFetchRuleManagementFilters(); + invalidateFetchRulesInfo(); if (options?.onSettled) { options.onSettled(...args); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts similarity index 61% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts index ea394d829fc03..72f0dc2cef34e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts @@ -7,20 +7,18 @@ import { useCallback } from 'react'; import type { UseQueryOptions } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query'; -import type { RuleManagementFiltersResponse } from '../../../../../common/detection_engine/rule_management/api/get_filters/response_schema'; -import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; -import { fetchRuleManagementFilters } from '../api'; +import type { RulesInfoResponse } from '../../../../../common/detection_engine/rule_management/api/rules/info/response_schema'; +import { RULES_INFO_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; +import { fetchRulesInfo } from '../api'; import { DEFAULT_QUERY_OPTIONS } from './constants'; -export const RULE_MANAGEMENT_FILTERS_QUERY_KEY = ['GET', RULE_MANAGEMENT_FILTERS_URL]; +export const RULE_MANAGEMENT_FILTERS_QUERY_KEY = ['GET', RULES_INFO_URL]; -export const useFetchRuleManagementFiltersQuery = ( - options?: UseQueryOptions -) => { - return useQuery( +export const useFetchRulesInfoQuery = (options?: UseQueryOptions) => { + return useQuery( RULE_MANAGEMENT_FILTERS_QUERY_KEY, async ({ signal }) => { - const response = await fetchRuleManagementFilters({ signal }); + const response = await fetchRulesInfo({ signal }); return response; }, { @@ -37,7 +35,7 @@ export const useFetchRuleManagementFiltersQuery = ( * * @returns A rules cache invalidation callback */ -export const useInvalidateFetchRuleManagementFiltersQuery = () => { +export const useInvalidateFetchRulesInfoQuery = () => { const queryClient = useQueryClient(); return useCallback(() => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts index 21d0c78f49b41..bdfc5fe8eced9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts @@ -15,7 +15,7 @@ import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { updateRule } from '../api'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; -import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; +import { useInvalidateFetchRulesInfoQuery } from './use_fetch_rules_info_query'; export const UPDATE_RULE_MUTATION_KEY = ['PUT', DETECTION_ENGINE_RULES_URL]; @@ -23,7 +23,7 @@ export const useUpdateRuleMutation = ( options?: UseMutationOptions ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); return useMutation( @@ -34,7 +34,7 @@ export const useUpdateRuleMutation = ( onSettled: (...args) => { invalidateFindRulesQuery(); invalidateFetchRuleByIdQuery(); - invalidateFetchRuleManagementFilters(); + invalidateFetchRulesInfo(); if (options?.onSettled) { options.onSettled(...args); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_management_filters.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rules_info.ts similarity index 72% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_management_filters.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rules_info.ts index a16f433b993a1..d806f30b93031 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_management_filters.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rules_info.ts @@ -5,13 +5,13 @@ * 2.0. */ import { useAppToasts } from '../../../common/hooks/use_app_toasts'; -import { useFetchRuleManagementFiltersQuery } from '../api/hooks/use_fetch_rule_management_filters_query'; +import { useFetchRulesInfoQuery } from '../api/hooks/use_fetch_rules_info_query'; import * as i18n from './translations'; -export const useRuleManagementFilters = () => { +export const useRulesInfo = () => { const { addError } = useAppToasts(); - return useFetchRuleManagementFiltersQuery({ + return useFetchRulesInfoQuery({ onError: (err) => { addError(err, { title: i18n.RULE_MANAGEMENT_FILTERS_FETCH_FAILURE }); }, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx index 841fe6b25557c..0574b3f13f492 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx @@ -9,7 +9,7 @@ import { EuiCallOut, EuiFormRow } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import React, { useMemo } from 'react'; -import { useRuleManagementFilters } from '../../../../../rule_management/logic/use_rule_management_filters'; +import { useRulesInfo } from '../../../../../rule_management/logic/use_rules_info'; import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { BulkActionEditType } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import * as i18n from '../../../../../../detections/pages/detection_engine/rules/translations'; @@ -78,7 +78,7 @@ interface TagsFormProps { } const TagsFormComponent = ({ editAction, rulesCount, onClose, onConfirm }: TagsFormProps) => { - const { data: { tags } = { tags: [] } } = useRuleManagementFilters(); + const { data: { tags } = { tags: [] } } = useRulesInfo(); const { form } = useForm({ defaultValue: initialFormData, schema, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx index 3370c89f49d84..9d9b64cd98db3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx @@ -9,7 +9,7 @@ import { EuiFilterButton, EuiFilterGroup, EuiFlexGroup, EuiFlexItem } from '@ela import { isEqual } from 'lodash/fp'; import React, { useCallback } from 'react'; import styled from 'styled-components'; -import { useRuleManagementFilters } from '../../../../rule_management/logic/use_rule_management_filters'; +import { useRulesInfo } from '../../../../rule_management/logic/use_rules_info'; import { RULES_TABLE_ACTIONS } from '../../../../../common/lib/apm/user_actions'; import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; @@ -31,10 +31,10 @@ const RulesTableFiltersComponent = () => { state: { filterOptions }, actions: { setFilterOptions }, } = useRulesTableContext(); - const { data: filtersData } = useRuleManagementFilters(); - const allTags = filtersData?.tags ?? []; - const rulesCustomCount = filtersData?.rules_custom_count; - const rulesPrebuiltInstalledCount = filtersData?.rules_prebuilt_installed_count; + const { data: rulesInfo } = useRulesInfo(); + const allTags = rulesInfo?.tags ?? []; + const rulesCustomCount = rulesInfo?.rules_custom_count; + const rulesPrebuiltInstalledCount = rulesInfo?.rules_prebuilt_installed_count; const { showCustomRules, showElasticRules, tags: selectedTags } = filterOptions; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx index f02075809a46d..03147fd526fc5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx @@ -41,18 +41,18 @@ import { RulesTableContextProvider } from '../../components/rules_table/rules_ta import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; import { RulesPageTourComponent } from '../../components/rules_table/alternative_tour/tour'; -import { useInvalidateFetchRuleManagementFiltersQuery } from '../../../rule_management/api/hooks/use_fetch_rule_management_filters_query'; +import { useInvalidateFetchRulesInfoQuery } from '../../../rule_management/api/hooks/use_fetch_rules_info_query'; const RulesPageComponent: React.FC = () => { const [isImportModalVisible, showImportModal, hideImportModal] = useBoolState(); const [isValueListFlyoutVisible, showValueListFlyout, hideValueListFlyout] = useBoolState(); const { navigateToApp } = useKibana().services.application; const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); const invalidateRules = useCallback(() => { invalidateFindRulesQuery(); - invalidateFetchRuleManagementFilters(); - }, [invalidateFindRulesQuery, invalidateFetchRuleManagementFilters]); + invalidateFetchRulesInfo(); + }, [invalidateFindRulesQuery, invalidateFetchRulesInfo]); const [ { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 8239108728304..68ec467c52993 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -24,7 +24,7 @@ import { DETECTION_ENGINE_RULES_BULK_CREATE, DETECTION_ENGINE_RULES_URL_FIND, } from '../../../../../common/constants'; -import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; +import { RULES_INFO_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; import { PREBUILT_RULES_STATUS_URL, @@ -191,10 +191,10 @@ export const getPrepackagedRulesStatusRequest = () => path: PREBUILT_RULES_STATUS_URL, }); -export const getRuleManagementFiltersRequest = () => +export const getRulesInfoRequest = () => requestMock.create({ method: 'get', - path: RULE_MANAGEMENT_FILTERS_URL, + path: RULES_INFO_URL, }); export interface FindHit { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts index d801cc3cad3ba..a0f9b187c8eb7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts @@ -9,7 +9,6 @@ import type { Logger } from '@kbn/core/server'; import type { ConfigType } from '../../../../config'; import type { SetupPlugins } from '../../../../plugin_contract'; import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { getRuleManagementFilters } from './filters/route'; import { performBulkActionRoute } from './rules/bulk_actions/route'; import { bulkCreateRulesRoute } from './rules/bulk_create_rules/route'; @@ -21,6 +20,7 @@ import { deleteRuleRoute } from './rules/delete_rule/route'; import { exportRulesRoute } from './rules/export_rules/route'; import { findRulesRoute } from './rules/find_rules/route'; import { importRulesRoute } from './rules/import_rules/route'; +import { getRulesInfo } from './rules/info/route'; import { patchRuleRoute } from './rules/patch_rule/route'; import { readRuleRoute } from './rules/read_rule/route'; import { updateRuleRoute } from './rules/update_rule/route'; @@ -59,5 +59,5 @@ export const registerRuleManagementRoutes = ( readTagsRoute(router); // Rules filters - getRuleManagementFilters(router); + getRulesInfo(router); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.test.ts similarity index 83% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.test.ts index 8880047826762..613ff24ca95b0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.test.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { getRuleManagementFilters } from './route'; +import { getRulesInfo } from './route'; import { getEmptyFindResult, getFindResultWithSingleHit, - getRuleManagementFiltersRequest, -} from '../../../routes/__mocks__/request_responses'; -import { requestContextMock, serverMock } from '../../../routes/__mocks__'; + getRulesInfoRequest, +} from '../../../../routes/__mocks__/request_responses'; +import { requestContextMock, serverMock } from '../../../../routes/__mocks__'; describe('Rule management filters route', () => { let server: ReturnType; @@ -25,13 +25,13 @@ describe('Rule management filters route', () => { clients.rulesClient.find.mockResolvedValue(getEmptyFindResult()); - getRuleManagementFilters(server.router); + getRulesInfo(server.router); }); describe('status codes', () => { test('returns 200', async () => { const response = await server.inject( - getRuleManagementFiltersRequest(), + getRulesInfoRequest(), requestContextMock.convertContext(context) ); expect(response.status).toEqual(200); @@ -42,7 +42,7 @@ describe('Rule management filters route', () => { throw new Error('Test error'); }); const response = await server.inject( - getRuleManagementFiltersRequest(), + getRulesInfoRequest(), requestContextMock.convertContext(context) ); expect(response.status).toEqual(500); @@ -61,7 +61,7 @@ describe('Rule management filters route', () => { ruleLastRunOutcome: {}, ruleTags: ['a', 'b', 'c'], }); - const request = getRuleManagementFiltersRequest(); + const request = getRulesInfoRequest(); const response = await server.inject(request, requestContextMock.convertContext(context)); expect(response.status).toEqual(200); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts similarity index 75% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts index d333928fee2cb..2d3942a138e53 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/filters/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts @@ -8,11 +8,11 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { validate } from '@kbn/securitysolution-io-ts-utils'; import type { RulesClient } from '@kbn/alerting-plugin/server'; -import { RuleManagementFiltersResponse } from '../../../../../../common/detection_engine/rule_management/api/get_filters/response_schema'; -import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../../common/detection_engine/rule_management/api/urls'; -import { buildSiemResponse } from '../../../routes/utils'; -import type { SecuritySolutionPluginRouter } from '../../../../../types'; -import { findRules } from '../../logic/search/find_rules'; +import { RulesInfoResponse } from '../../../../../../../common/detection_engine/rule_management/api/rules/info/response_schema'; +import { RULES_INFO_URL } from '../../../../../../../common/detection_engine/rule_management/api/urls'; +import { buildSiemResponse } from '../../../../routes/utils'; +import type { SecuritySolutionPluginRouter } from '../../../../../../types'; +import { findRules } from '../../../logic/search/find_rules'; interface RulesCount { prebuilt: number; @@ -47,21 +47,25 @@ async function fetchRulesCount(rulesClient: RulesClient): Promise { }; } +// This is a contrived max limit on the number of tags. In fact it can exceed this number and will be truncated to the hardcoded number. +const EXPECTED_MAX_TAGS = 500; + async function fetchRuleTags(rulesClient: RulesClient): Promise { const res = await rulesClient.aggregate({ options: { fields: ['tags'], filter: undefined, + maxTags: EXPECTED_MAX_TAGS, }, }); return res.ruleTags ?? []; } -export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) => { +export const getRulesInfo = (router: SecuritySolutionPluginRouter) => { router.get( { - path: RULE_MANAGEMENT_FILTERS_URL, + path: RULES_INFO_URL, validate: false, options: { tags: ['access:securitySolution'], @@ -75,15 +79,12 @@ export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) = try { const [{ prebuilt: prebuiltRulesCount, custom: customRulesCount }, tags] = await Promise.all([fetchRulesCount(rulesClient), fetchRuleTags(rulesClient)]); - const responseBody: RuleManagementFiltersResponse = { + const responseBody: RulesInfoResponse = { rules_custom_count: customRulesCount, rules_prebuilt_installed_count: prebuiltRulesCount, tags, }; - const [validatedBody, validationError] = validate( - responseBody, - RuleManagementFiltersResponse - ); + const [validatedBody, validationError] = validate(responseBody, RulesInfoResponse); if (validationError != null) { return siemResponse.error({ statusCode: 500, body: validationError }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts deleted file mode 100644 index 899c5ac5a1bb8..0000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts +++ /dev/null @@ -1,88 +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 expect from '@kbn/expect'; - -import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; -import { PREBUILT_RULES_URL } from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; -import { RULE_MANAGEMENT_FILTERS_URL } from '@kbn/security-solution-plugin/common/detection_engine/rule_management/api/urls'; - -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - createSignalsIndex, - deleteAllAlerts, - deleteSignalsIndex, - getSimpleRule, - deleteAllTimelines, -} from '../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext): void => { - const supertest = getService('supertest'); - const es = getService('es'); - const log = getService('log'); - - describe('get_rule_management_filters', () => { - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteSignalsIndex(supertest, log); - await deleteAllAlerts(supertest, log); - await deleteAllTimelines(es); - }); - - it('should return expected JSON keys', async () => { - const { body } = await supertest - .get(RULE_MANAGEMENT_FILTERS_URL) - .set('kbn-xsrf', 'true') - .send() - .expect(200); - - expect(Object.keys(body)).to.eql(['rules_custom_count', 'rules_prebuilt_installed_count']); - }); - - it('should return that rules_custom_count and rules_prebuilt_installed_count are zero', async () => { - const { body } = await supertest - .get(RULE_MANAGEMENT_FILTERS_URL) - .set('kbn-xsrf', 'true') - .send() - .expect(200); - expect(body.rules_custom_count).to.eql(0); - expect(body.rules_prebuilt_installed_count).to.eql(0); - }); - - it('should show the correct number of custom rules after a custom rule has been created', async () => { - await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .send(getSimpleRule()) - .expect(200); - - const { body } = await supertest - .get(RULE_MANAGEMENT_FILTERS_URL) - .set('kbn-xsrf', 'true') - .send() - .expect(200); - expect(body.rules_custom_count).to.eql(1); - expect(body.rules_prebuilt_installed_count).to.eql(0); - }); - - it('should show the correct number of installed prepacked rules after pre-packaged rules have been installed', async () => { - await supertest.put(PREBUILT_RULES_URL).set('kbn-xsrf', 'true').send().expect(200); - - const { body } = await supertest - .get(RULE_MANAGEMENT_FILTERS_URL) - .set('kbn-xsrf', 'true') - .send() - .expect(200); - expect(body.rules_prebuilt_installed_count).to.be.greaterThan(0); - expect(body.rules_custom_count).to.eql(0); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts new file mode 100644 index 0000000000000..448415398539b --- /dev/null +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts @@ -0,0 +1,119 @@ +/* + * 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 expect from '@kbn/expect'; + +import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; +import { PREBUILT_RULES_URL } from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; +import { RULES_INFO_URL } from '@kbn/security-solution-plugin/common/detection_engine/rule_management/api/urls'; + +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { + createSignalsIndex, + deleteAllAlerts, + deleteSignalsIndex, + getSimpleRule, + deleteAllTimelines, +} from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('es'); + const log = getService('log'); + + describe('get_rules_info', () => { + beforeEach(async () => { + await createSignalsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteSignalsIndex(supertest, log); + await deleteAllAlerts(supertest, log); + await deleteAllTimelines(es); + }); + + it('should return expected JSON keys', async () => { + const { body } = await supertest + .get(RULES_INFO_URL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + expect(Object.keys(body)).to.eql([ + 'rules_custom_count', + 'rules_prebuilt_installed_count', + 'tags', + ]); + }); + + it('should return the correct result when there are no rules', async () => { + const { body } = await supertest + .get(RULES_INFO_URL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + expect(body.rules_custom_count).to.eql(0); + expect(body.rules_prebuilt_installed_count).to.eql(0); + expect(body.tags).to.eql([]); + }); + + describe('when there is a custom rule', () => { + beforeEach(async () => { + await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(getSimpleRule()) + .expect(200); + }); + + it('should return the correct number of custom rules', async () => { + const { body } = await supertest + .get(RULES_INFO_URL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + expect(body.rules_custom_count).to.eql(1); + expect(body.rules_prebuilt_installed_count).to.eql(0); + }); + + it('should return correct tags', async () => { + const { body } = await supertest + .get(RULES_INFO_URL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + expect(body.tags).to.eql(['tag-a']); + }); + }); + + describe('when there are installed prebuilt rules', () => { + beforeEach(async () => { + await supertest.put(PREBUILT_RULES_URL).set('kbn-xsrf', 'true').send().expect(200); + }); + + it('should return the correct number of installed prepacked rules after pre-packaged rules have been installed', async () => { + const { body } = await supertest + .get(RULES_INFO_URL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + expect(body.rules_prebuilt_installed_count).to.be.greaterThan(0); + expect(body.rules_custom_count).to.eql(0); + }); + + it('should return correct tags', async () => { + const { body } = await supertest + .get(RULES_INFO_URL) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + expect(body.tags.length).to.be.greaterThan(0); + }); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts index 24e0d5389a018..f1e2672e31484 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts @@ -31,6 +31,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./find_rules')); loadTestFile(require.resolve('./find_rule_exception_references')); loadTestFile(require.resolve('./get_prepackaged_rules_status')); - loadTestFile(require.resolve('./get_rule_management_filters')); + loadTestFile(require.resolve('./get_rules_info')); }); }; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts index e630ba9859e2f..23258f81f6772 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts @@ -22,4 +22,5 @@ export const getSimpleRule = (ruleId = 'rule-1', enabled = false): QueryRuleCrea index: ['auditbeat-*'], type: 'query', query: 'user.name: root or user.name: admin', + tags: ['tag-a'], }); From 2c64e989944858bc8e76a18045cf19b45e2c28f9 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sat, 3 Dec 2022 23:04:09 +0100 Subject: [PATCH 08/35] remove unused translation --- x-pack/plugins/translations/translations/fr-FR.json | 1 - x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 3 files changed, 3 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 1b3868de820df..e4d3af06607ec 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -27784,7 +27784,6 @@ "xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleSuccesDescription": "Installation effectuée des règles prépackagées à partir d'Elastic", "xpack.securitySolution.containers.detectionEngine.createPrePackagedTimelineSuccesDescription": "Installation effectuée des modèles de chronologies prépackagées à partir d'Elastic", "xpack.securitySolution.containers.detectionEngine.rulesAndTimelines": "Impossible de récupérer les règles et les chronologies", - "xpack.securitySolution.containers.detectionEngine.tagFetchFailDescription": "Impossible de récupérer les balises", "xpack.securitySolution.contextMenuItemByRouter.viewDetails": "Afficher les détails", "xpack.securitySolution.createPackagePolicy.stepConfigure.cloudDropdownOption": "Charges de travail cloud (serveurs Linux ou environnements Kubernetes)", "xpack.securitySolution.createPackagePolicy.stepConfigure.cloudEventFiltersAllEvents": "Tous les événements", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 23ca149fbbe89..018bc103d2e65 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -27757,7 +27757,6 @@ "xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleSuccesDescription": "Elastic から事前にパッケージ化されているルールをインストールしました", "xpack.securitySolution.containers.detectionEngine.createPrePackagedTimelineSuccesDescription": "Elasticから事前にパッケージ化されているタイムラインテンプレートをインストールしました", "xpack.securitySolution.containers.detectionEngine.rulesAndTimelines": "ルールとタイムラインを取得できませんでした", - "xpack.securitySolution.containers.detectionEngine.tagFetchFailDescription": "タグを取得できませんでした", "xpack.securitySolution.contextMenuItemByRouter.viewDetails": "詳細を表示", "xpack.securitySolution.createPackagePolicy.stepConfigure.cloudDropdownOption": "クラウドワークロード(LinuxサーバーまたはKubernetes環境)", "xpack.securitySolution.createPackagePolicy.stepConfigure.cloudEventFiltersAllEvents": "すべてのイベント", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 6cd3f143aaec5..bd8805a391218 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -27790,7 +27790,6 @@ "xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleSuccesDescription": "已安装 Elastic 的预打包规则", "xpack.securitySolution.containers.detectionEngine.createPrePackagedTimelineSuccesDescription": "安装 Elastic 预先打包的时间线模板", "xpack.securitySolution.containers.detectionEngine.rulesAndTimelines": "无法提取规则和时间线", - "xpack.securitySolution.containers.detectionEngine.tagFetchFailDescription": "无法提取标签", "xpack.securitySolution.contextMenuItemByRouter.viewDetails": "查看详情", "xpack.securitySolution.createPackagePolicy.stepConfigure.cloudDropdownOption": "云工作负载(Linux 服务器或 Kubernetes 环境)", "xpack.securitySolution.createPackagePolicy.stepConfigure.cloudEventFiltersAllEvents": "所有事件", From d8d3b0957337cebe9c52fda15d9fd307ece49067 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sun, 4 Dec 2022 09:11:07 +0100 Subject: [PATCH 09/35] avoid extending default rule testing data --- .../security_and_spaces/group1/get_rules_info.ts | 5 ++++- .../utils/get_simple_rule.ts | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts index 448415398539b..605f9bf1b013a 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts @@ -64,10 +64,13 @@ export default ({ getService }: FtrProviderContext): void => { describe('when there is a custom rule', () => { beforeEach(async () => { + const rule = getSimpleRule(); + rule.tags = ['tag-a']; + await supertest .post(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') - .send(getSimpleRule()) + .send(rule) .expect(200); }); diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts index 23258f81f6772..e630ba9859e2f 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule.ts @@ -22,5 +22,4 @@ export const getSimpleRule = (ruleId = 'rule-1', enabled = false): QueryRuleCrea index: ['auditbeat-*'], type: 'query', query: 'user.name: root or user.name: admin', - tags: ['tag-a'], }); From 7c991dcea44b9fd97c4d2250013849ff9ddc3145 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sun, 4 Dec 2022 11:37:24 +0100 Subject: [PATCH 10/35] use the new endpoint in the rules table --- .../components/rules_table/rules_tables.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx index 7156126b39c29..246673f4caa64 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx @@ -18,7 +18,6 @@ import { useBoolState } from '../../../../common/hooks/use_bool_state'; import { useValueChanged } from '../../../../common/hooks/use_value_changed'; import { PrePackagedRulesPrompt } from '../../../../detections/components/rules/pre_packaged_rules/load_empty_prompt'; import type { Rule, RulesSortingFields } from '../../../rule_management/logic'; -import { usePrePackagedRulesStatus } from '../../../rule_management/logic/use_pre_packaged_rules_status'; import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; import type { EuiBasicTableOnChange } from '../../../../detections/pages/detection_engine/rules/types'; import { BulkActionDryRunConfirmation } from './bulk_actions/bulk_action_dry_run_confirmation'; @@ -39,6 +38,7 @@ import { useBulkDuplicateExceptionsConfirmation } from './bulk_actions/use_bulk_ import { BulkActionDuplicateExceptionsConfirmation } from './bulk_actions/bulk_duplicate_exceptions_confirmation'; import { useStartMlJobs } from '../../../rule_management/logic/use_start_ml_jobs'; import { RULES_TABLE_PAGE_SIZE_OPTIONS } from './constants'; +import { useRulesInfo } from '../../../rule_management/logic/use_rules_info'; const INITIAL_SORT_FIELD = 'enabled'; @@ -65,8 +65,7 @@ export const RulesTables = React.memo(({ selectedTab }) => { const tableRef = useRef(null); const rulesTableContext = useRulesTableContext(); - const { data: prePackagedRulesStatus, isLoading: isPrepackagedStatusLoading } = - usePrePackagedRulesStatus(); + const { data: rulesInfo, isLoading: isRulesInfoLoading } = useRulesInfo(); const { state: { @@ -214,11 +213,11 @@ export const RulesTables = React.memo(({ selectedTab }) => { }, [rules, isAllSelected, setIsAllSelected, setSelectedRuleIds]); const isTableEmpty = - !isPrepackagedStatusLoading && - prePackagedRulesStatus?.rules_custom_installed === 0 && - prePackagedRulesStatus.rules_installed === 0; + !isRulesInfoLoading && + rulesInfo?.rules_custom_count === 0 && + rulesInfo?.rules_prebuilt_installed_count === 0; - const shouldShowRulesTable = !isPrepackagedStatusLoading && !isLoading && !isTableEmpty; + const shouldShowRulesTable = !isRulesInfoLoading && !isLoading && !isTableEmpty; const tableProps = selectedTab === AllRulesTabs.rules From d384fa037f447b37bc7577396eb20ea2e25dcd09 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sun, 4 Dec 2022 18:52:49 +0100 Subject: [PATCH 11/35] rename i18n constant --- .../detection_engine/rule_management/logic/translations.ts | 2 +- .../detection_engine/rule_management/logic/use_rules_info.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts index a89ec04e4002c..1e02234b915aa 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts @@ -14,7 +14,7 @@ export const RULE_AND_TIMELINE_FETCH_FAILURE = i18n.translate( } ); -export const RULE_MANAGEMENT_FILTERS_FETCH_FAILURE = i18n.translate( +export const RULES_INFO_FETCH_FAILURE = i18n.translate( 'xpack.securitySolution.containers.detectionEngine.ruleManagementFiltersFetchFailure', { defaultMessage: 'Failed to fetch Rule management filters', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rules_info.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rules_info.ts index d806f30b93031..19a9b7dcc8490 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rules_info.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rules_info.ts @@ -13,7 +13,7 @@ export const useRulesInfo = () => { return useFetchRulesInfoQuery({ onError: (err) => { - addError(err, { title: i18n.RULE_MANAGEMENT_FILTERS_FETCH_FAILURE }); + addError(err, { title: i18n.RULES_INFO_FETCH_FAILURE }); }, }); }; From 27498d515217b581e402c8268b1a647d807fe1fc Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sun, 4 Dec 2022 18:53:09 +0100 Subject: [PATCH 12/35] fix tags data invalidation after bulk tags update --- .../rule_management/api/hooks/use_bulk_action_mutation.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts index 133630e5c5cf4..a6064622d2073 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts @@ -83,6 +83,7 @@ export const useBulkActionMutation = ( invalidateFindRulesQuery(); } invalidateFetchRuleByIdQuery(); + invalidateFetchRulesInfo(); break; } From 4d588809f6987c97688a387718f63910cf4b78bb Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sun, 4 Dec 2022 18:55:19 +0100 Subject: [PATCH 13/35] get rid of outdated naming --- .../rule_management/api/rules/info/response_schema.test.ts | 2 +- .../rule_management/api/hooks/use_fetch_rules_info_query.ts | 6 +++--- .../rule_management/api/rules/info/route.test.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts index 3c412b8781929..716270fcb986a 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts @@ -11,7 +11,7 @@ import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts import { RulesInfoResponse } from './response_schema'; -describe('Rule management filters response schema', () => { +describe('Rules info response schema', () => { test('it should validate an empty response with defaults', () => { const payload: RulesInfoResponse = { rules_custom_count: 0, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts index 72f0dc2cef34e..74ae35bcb9bd4 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts @@ -12,11 +12,11 @@ import { RULES_INFO_URL } from '../../../../../common/detection_engine/rule_mana import { fetchRulesInfo } from '../api'; import { DEFAULT_QUERY_OPTIONS } from './constants'; -export const RULE_MANAGEMENT_FILTERS_QUERY_KEY = ['GET', RULES_INFO_URL]; +export const RULES_INFO_QUERY_KEY = ['GET', RULES_INFO_URL]; export const useFetchRulesInfoQuery = (options?: UseQueryOptions) => { return useQuery( - RULE_MANAGEMENT_FILTERS_QUERY_KEY, + RULES_INFO_QUERY_KEY, async ({ signal }) => { const response = await fetchRulesInfo({ signal }); return response; @@ -39,7 +39,7 @@ export const useInvalidateFetchRulesInfoQuery = () => { const queryClient = useQueryClient(); return useCallback(() => { - queryClient.invalidateQueries(RULE_MANAGEMENT_FILTERS_QUERY_KEY, { + queryClient.invalidateQueries(RULES_INFO_QUERY_KEY, { refetchType: 'active', }); }, [queryClient]); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.test.ts index 613ff24ca95b0..58f43810369d0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.test.ts @@ -14,7 +14,7 @@ import { } from '../../../../routes/__mocks__/request_responses'; import { requestContextMock, serverMock } from '../../../../routes/__mocks__'; -describe('Rule management filters route', () => { +describe('Rules info route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); From 7bccfa8d4f5a9f236d93849255e96e5e27b9a1dc Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Mon, 5 Dec 2022 14:15:48 +0100 Subject: [PATCH 14/35] fix an error message --- .../detection_engine/rule_management/logic/translations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts index 1e02234b915aa..0780cd410347e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts @@ -17,7 +17,7 @@ export const RULE_AND_TIMELINE_FETCH_FAILURE = i18n.translate( export const RULES_INFO_FETCH_FAILURE = i18n.translate( 'xpack.securitySolution.containers.detectionEngine.ruleManagementFiltersFetchFailure', { - defaultMessage: 'Failed to fetch Rule management filters', + defaultMessage: 'Failed to fetch rules information', } ); From a6491dfae12dfc437de68ed6584b34bc639f41e8 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Mon, 5 Dec 2022 19:03:59 +0100 Subject: [PATCH 15/35] simplify unit response schema unit tests --- .../api/rules/info/response_schema.test.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts index 716270fcb986a..610d8795b1f1b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts @@ -6,7 +6,6 @@ */ import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; import { RulesInfoResponse } from './response_schema'; @@ -20,7 +19,7 @@ describe('Rules info response schema', () => { }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); + const message = foldLeftRight(checked); expect(getPaths(left(message.errors))).toEqual([]); expect(message.schema).toEqual(payload); @@ -34,7 +33,7 @@ describe('Rules info response schema', () => { }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); + const message = foldLeftRight(checked); expect(getPaths(left(message.errors))).toEqual([]); expect(message.schema).toEqual(payload); @@ -49,7 +48,7 @@ describe('Rules info response schema', () => { }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); + const message = foldLeftRight(checked); expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_field"']); expect(message.schema).toEqual({}); @@ -63,7 +62,7 @@ describe('Rules info response schema', () => { }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); + const message = foldLeftRight(checked); expect(getPaths(left(message.errors))).toEqual([ 'Invalid value "-1" supplied to "rules_prebuilt_installed_count"', @@ -79,7 +78,7 @@ describe('Rules info response schema', () => { }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); + const message = foldLeftRight(checked); expect(getPaths(left(message.errors))).toEqual([ 'Invalid value "-1" supplied to "rules_custom_count"', @@ -97,7 +96,7 @@ describe('Rules info response schema', () => { delete payload.rules_prebuilt_installed_count; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); + const message = foldLeftRight(checked); expect(getPaths(left(message.errors))).toEqual([ 'Invalid value "undefined" supplied to "rules_prebuilt_installed_count"', @@ -113,7 +112,7 @@ describe('Rules info response schema', () => { }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); + const message = foldLeftRight(checked); expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "tags"']); expect(message.schema).toEqual({}); From d348da7099643e3d2aeb9750df5e4372fdb7dbc5 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Mon, 5 Dec 2022 19:05:21 +0100 Subject: [PATCH 16/35] add explicit @ts-expect-error for testing invalid values --- .../rule_management/api/rules/info/response_schema.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts index 610d8795b1f1b..586b7e1c3ae95 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts @@ -108,7 +108,8 @@ describe('Rules info response schema', () => { const payload: RulesInfoResponse = { rules_custom_count: 0, rules_prebuilt_installed_count: 0, - tags: [1] as unknown as string[], + // @ts-expect-error Passing an invalid value for the test + tags: [1], }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); From b5545e9b3548570d9dd43b99b188496f5603b8b2 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Mon, 5 Dec 2022 19:08:34 +0100 Subject: [PATCH 17/35] get rid of unnecessary prebuilt rules status invalidation --- .../rule_management/api/hooks/use_bulk_action_mutation.ts | 4 ---- .../rule_management/api/hooks/use_create_rule_mutation.ts | 3 --- 2 files changed, 7 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts index a6064622d2073..3d507e50fa6a7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts @@ -11,7 +11,6 @@ import { BulkActionType } from '../../../../../common/detection_engine/rule_mana import type { BulkActionErrorResponse, BulkActionResponse, PerformBulkActionProps } from '../api'; import { performBulkAction } from '../api'; import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../common/constants'; -import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFindRulesQuery, useUpdateRulesCache } from './use_find_rules_query'; import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; import { useInvalidateFetchRulesInfoQuery } from './use_fetch_rules_info_query'; @@ -28,7 +27,6 @@ export const useBulkActionMutation = ( const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); - const invalidateFetchPrebuiltRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); const updateRulesCache = useUpdateRulesCache(); return useMutation< @@ -67,12 +65,10 @@ export const useBulkActionMutation = ( invalidateFindRulesQuery(); invalidateFetchRuleByIdQuery(); invalidateFetchRulesInfo(); - invalidateFetchPrebuiltRulesStatusQuery(); break; case BulkActionType.duplicate: invalidateFindRulesQuery(); invalidateFetchRulesInfo(); - invalidateFetchPrebuiltRulesStatusQuery(); break; case BulkActionType.edit: if (updatedRules) { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts index c06807855e846..3e59348a3d61d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts @@ -13,7 +13,6 @@ import type { } from '../../../../../common/detection_engine/rule_schema'; import { transformOutput } from '../../../../detections/containers/detection_engine/rules/transforms'; import { createRule } from '../api'; -import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFetchRulesInfoQuery } from './use_fetch_rules_info_query'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; @@ -24,7 +23,6 @@ export const useCreateRuleMutation = ( ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); - const invalidateFetchPrePackagedRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); return useMutation( (rule: RuleCreateProps) => createRule({ rule: transformOutput(rule) }), @@ -32,7 +30,6 @@ export const useCreateRuleMutation = ( ...options, mutationKey: CREATE_RULE_MUTATION_KEY, onSettled: (...args) => { - invalidateFetchPrePackagedRulesStatusQuery(); invalidateFindRulesQuery(); invalidateFetchRulesInfo(); From 26345c2ecc4d30c518135ecb4a1b28573d26ba87 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Mon, 5 Dec 2022 19:25:06 +0100 Subject: [PATCH 18/35] replace readTags with the new implementation --- .../rule_management/api/rules/info/route.ts | 18 +---- .../api/tags/read_tags/read_tags.test.ts | 80 ++----------------- .../api/tags/read_tags/read_tags.ts | 38 +++------ 3 files changed, 19 insertions(+), 117 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts index 2d3942a138e53..a83de7bebedc5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts @@ -13,6 +13,7 @@ import { RULES_INFO_URL } from '../../../../../../../common/detection_engine/rul import { buildSiemResponse } from '../../../../routes/utils'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; import { findRules } from '../../../logic/search/find_rules'; +import { readTags } from '../../tags/read_tags/read_tags'; interface RulesCount { prebuilt: number; @@ -47,21 +48,6 @@ async function fetchRulesCount(rulesClient: RulesClient): Promise { }; } -// This is a contrived max limit on the number of tags. In fact it can exceed this number and will be truncated to the hardcoded number. -const EXPECTED_MAX_TAGS = 500; - -async function fetchRuleTags(rulesClient: RulesClient): Promise { - const res = await rulesClient.aggregate({ - options: { - fields: ['tags'], - filter: undefined, - maxTags: EXPECTED_MAX_TAGS, - }, - }); - - return res.ruleTags ?? []; -} - export const getRulesInfo = (router: SecuritySolutionPluginRouter) => { router.get( { @@ -78,7 +64,7 @@ export const getRulesInfo = (router: SecuritySolutionPluginRouter) => { try { const [{ prebuilt: prebuiltRulesCount, custom: customRulesCount }, tags] = - await Promise.all([fetchRulesCount(rulesClient), fetchRuleTags(rulesClient)]); + await Promise.all([fetchRulesCount(rulesClient), readTags({ rulesClient })]); const responseBody: RulesInfoResponse = { rules_custom_count: customRulesCount, rules_prebuilt_installed_count: prebuiltRulesCount, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts index ba9b00c01e3cf..db61d540170af 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts @@ -19,85 +19,17 @@ describe('read_tags', () => { }); describe('readTags', () => { - test('it should return the intersection of tags to where none are repeating', async () => { - const result1 = getRuleMock(getQueryRuleParams()); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - result1.tags = ['tag 1', 'tag 2', 'tag 3']; - - const result2 = getRuleMock(getQueryRuleParams()); - result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result2.params.ruleId = 'rule-2'; - result2.tags = ['tag 1', 'tag 2', 'tag 3', 'tag 4']; - + test('it should return tags from the aggregation', async () => { const rulesClient = rulesClientMock.create(); - rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] })); + rulesClient.aggregate.mockResolvedValue({ + alertExecutionStatus: {}, + ruleLastRunOutcome: {}, + ruleTags: ['tag 1', 'tag 2', 'tag 3', 'tag 4'], + }); const tags = await readTags({ rulesClient }); expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']); }); - - test('it should return the intersection of tags to where some are repeating values', async () => { - const result1 = getRuleMock(getQueryRuleParams()); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3']; - - const result2 = getRuleMock(getQueryRuleParams()); - result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result2.params.ruleId = 'rule-2'; - result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; - - const rulesClient = rulesClientMock.create(); - rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] })); - - const tags = await readTags({ rulesClient }); - expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']); - }); - - test('it should work with no tags defined between two results', async () => { - const result1 = getRuleMock(getQueryRuleParams()); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - result1.tags = []; - - const result2 = getRuleMock(getQueryRuleParams()); - result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result2.params.ruleId = 'rule-2'; - result2.tags = []; - - const rulesClient = rulesClientMock.create(); - rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] })); - - const tags = await readTags({ rulesClient }); - expect(tags).toEqual([]); - }); - - test('it should work with a single tag which has repeating values in it', async () => { - const result1 = getRuleMock(getQueryRuleParams()); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - result1.tags = ['tag 1', 'tag 1', 'tag 1', 'tag 2']; - - const rulesClient = rulesClientMock.create(); - rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] })); - - const tags = await readTags({ rulesClient }); - expect(tags).toEqual(['tag 1', 'tag 2']); - }); - - test('it should work with a single tag which has empty tags', async () => { - const result1 = getRuleMock(getQueryRuleParams()); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - result1.tags = []; - - const rulesClient = rulesClientMock.create(); - rulesClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] })); - - const tags = await readTags({ rulesClient }); - expect(tags).toEqual([]); - }); }); describe('convertTagsToSet', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts index 8819d95f366d8..bfef4866a2c3f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts @@ -7,7 +7,6 @@ import { has } from 'lodash/fp'; import type { RulesClient } from '@kbn/alerting-plugin/server'; -import { findRules } from '../../../logic/search/find_rules'; export interface TagType { id: string; @@ -33,37 +32,22 @@ export const convertTagsToSet = (tagObjects: object[]): Set => { return new Set(convertToTags(tagObjects)); }; -// Note: This is doing an in-memory aggregation of the tags by calling each of the alerting -// records in batches of this const setting and uses the fields to try to get the least -// amount of data per record back. If saved objects at some point supports aggregations -// then this should be replaced with a an aggregation call. -// Ref: https://www.elastic.co/guide/en/kibana/master/saved-objects-api.html +// This is a contrived max limit on the number of tags. In fact it can exceed this number and will be truncated to the hardcoded number. +const EXPECTED_MAX_TAGS = 500; + export const readTags = async ({ rulesClient, }: { rulesClient: RulesClient; perPage?: number; }): Promise => { - // Get just one record so we can get the total count - const firstTags = await findRules({ - rulesClient, - fields: ['tags'], - perPage: 1, - page: 1, - sortField: 'createdAt', - sortOrder: 'desc', - filter: undefined, - }); - // Get all the rules to aggregate over all the tags of the rules - const rules = await findRules({ - rulesClient, - fields: ['tags'], - perPage: firstTags.total, - sortField: 'createdAt', - sortOrder: 'desc', - page: 1, - filter: undefined, + const res = await rulesClient.aggregate({ + options: { + fields: ['tags'], + filter: undefined, + maxTags: EXPECTED_MAX_TAGS, + }, }); - const tagSet = convertTagsToSet(rules.data); - return Array.from(tagSet); + + return res.ruleTags ?? []; }; From 8872d6d95e2b618acfff0b6f943c638cc14c14e5 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Mon, 5 Dec 2022 19:27:26 +0100 Subject: [PATCH 19/35] update the comment --- .../rule_management/api/hooks/use_fetch_rules_info_query.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts index 74ae35bcb9bd4..640897d5f1318 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts @@ -29,7 +29,7 @@ export const useFetchRulesInfoQuery = (options?: UseQueryOptions Date: Mon, 5 Dec 2022 19:42:26 +0100 Subject: [PATCH 20/35] split rule management filters response into categories --- .../api/rules/info/response_schema.test.ts | 92 ++++++++++++------- .../api/rules/info/response_schema.ts | 10 +- .../bulk_actions/forms/tags_form.tsx | 3 +- .../rules_table_filters.tsx | 8 +- .../components/rules_table/rules_tables.tsx | 6 +- .../rule_management/api/rules/info/route.ts | 10 +- 6 files changed, 84 insertions(+), 45 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts index 586b7e1c3ae95..9f5ceda0e2cde 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts @@ -13,9 +13,13 @@ import { RulesInfoResponse } from './response_schema'; describe('Rules info response schema', () => { test('it should validate an empty response with defaults', () => { const payload: RulesInfoResponse = { - rules_custom_count: 0, - rules_prebuilt_installed_count: 0, - tags: [], + rules_summary: { + custom_count: 0, + prebuilt_installed_count: 0, + }, + aggregated_fields: { + tags: [], + }, }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); @@ -27,9 +31,13 @@ describe('Rules info response schema', () => { test('it should validate an non empty response with defaults', () => { const payload: RulesInfoResponse = { - rules_custom_count: 10, - rules_prebuilt_installed_count: 20, - tags: ['a', 'b', 'c'], + rules_summary: { + custom_count: 10, + prebuilt_installed_count: 20, + }, + aggregated_fields: { + tags: ['a', 'b', 'c'], + }, }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); @@ -41,9 +49,13 @@ describe('Rules info response schema', () => { test('it should not validate an extra invalid field added', () => { const payload: RulesInfoResponse & { invalid_field: string } = { - rules_custom_count: 0, - rules_prebuilt_installed_count: 0, - tags: [], + rules_summary: { + custom_count: 0, + prebuilt_installed_count: 0, + }, + aggregated_fields: { + tags: [], + }, invalid_field: 'invalid', }; const decoded = RulesInfoResponse.decode(payload); @@ -54,68 +66,86 @@ describe('Rules info response schema', () => { expect(message.schema).toEqual({}); }); - test('it should NOT validate an empty response with a negative "rules_prebuilt_installed_count" number', () => { + test('it should NOT validate an empty response with a negative "summary.prebuilt_installed_count" number', () => { const payload: RulesInfoResponse = { - rules_custom_count: 0, - rules_prebuilt_installed_count: -1, - tags: [], + rules_summary: { + custom_count: 0, + prebuilt_installed_count: -1, + }, + aggregated_fields: { + tags: [], + }, }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "rules_prebuilt_installed_count"', + 'Invalid value "-1" supplied to "rules_summary,prebuilt_installed_count"', ]); expect(message.schema).toEqual({}); }); - test('it should NOT validate an empty response with a negative "rules_custom_count"', () => { + test('it should NOT validate an empty response with a negative "summary.custom_count"', () => { const payload: RulesInfoResponse = { - rules_custom_count: -1, - rules_prebuilt_installed_count: 0, - tags: [], + rules_summary: { + custom_count: -1, + prebuilt_installed_count: 0, + }, + aggregated_fields: { + tags: [], + }, }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "rules_custom_count"', + 'Invalid value "-1" supplied to "rules_summary,custom_count"', ]); expect(message.schema).toEqual({}); }); - test('it should NOT validate an empty prepackaged response if "rules_prebuilt_installed_count" is not there', () => { + test('it should NOT validate an empty prepackaged response if "summary.prebuilt_installed_count" is not there', () => { const payload: RulesInfoResponse = { - rules_custom_count: 0, - rules_prebuilt_installed_count: 0, - tags: [], + rules_summary: { + custom_count: 0, + prebuilt_installed_count: 0, + }, + aggregated_fields: { + tags: [], + }, }; // @ts-expect-error - delete payload.rules_prebuilt_installed_count; + delete payload.rules_summary.prebuilt_installed_count; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "rules_prebuilt_installed_count"', + 'Invalid value "undefined" supplied to "rules_summary,prebuilt_installed_count"', ]); expect(message.schema).toEqual({}); }); - test('it should NOT validate an empty response with wrong "tags"', () => { + test('it should NOT validate an empty response with wrong "aggregated_fields.tags"', () => { const payload: RulesInfoResponse = { - rules_custom_count: 0, - rules_prebuilt_installed_count: 0, - // @ts-expect-error Passing an invalid value for the test - tags: [1], + rules_summary: { + custom_count: 0, + prebuilt_installed_count: 0, + }, + aggregated_fields: { + // @ts-expect-error Passing an invalid value for the test + tags: [1], + }, }; const decoded = RulesInfoResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "tags"']); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "aggregated_fields,tags"', + ]); expect(message.schema).toEqual({}); }); }); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.ts index 925223ccb8ba3..4332440e6620d 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.ts @@ -11,8 +11,12 @@ import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; export type RulesInfoResponse = t.TypeOf; export const RulesInfoResponse = t.exact( t.type({ - rules_custom_count: PositiveInteger, - rules_prebuilt_installed_count: PositiveInteger, - tags: t.array(t.string), + rules_summary: t.type({ + custom_count: PositiveInteger, + prebuilt_installed_count: PositiveInteger, + }), + aggregated_fields: t.type({ + tags: t.array(t.string), + }), }) ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx index 0574b3f13f492..2a3b73056d6c6 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx @@ -78,7 +78,8 @@ interface TagsFormProps { } const TagsFormComponent = ({ editAction, rulesCount, onClose, onConfirm }: TagsFormProps) => { - const { data: { tags } = { tags: [] } } = useRulesInfo(); + const { data: ruleManagementFilters } = useRulesInfo(); + const tags = ruleManagementFilters?.aggregated_fields.tags ?? []; const { form } = useForm({ defaultValue: initialFormData, schema, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx index 9d9b64cd98db3..8202311513dd9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx @@ -31,10 +31,10 @@ const RulesTableFiltersComponent = () => { state: { filterOptions }, actions: { setFilterOptions }, } = useRulesTableContext(); - const { data: rulesInfo } = useRulesInfo(); - const allTags = rulesInfo?.tags ?? []; - const rulesCustomCount = rulesInfo?.rules_custom_count; - const rulesPrebuiltInstalledCount = rulesInfo?.rules_prebuilt_installed_count; + const { data: ruleManagementFields } = useRulesInfo(); + const allTags = ruleManagementFields?.aggregated_fields.tags ?? []; + const rulesCustomCount = ruleManagementFields?.rules_summary.custom_count; + const rulesPrebuiltInstalledCount = ruleManagementFields?.rules_summary.prebuilt_installed_count; const { showCustomRules, showElasticRules, tags: selectedTags } = filterOptions; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx index 246673f4caa64..e8e9df649b589 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx @@ -65,7 +65,7 @@ export const RulesTables = React.memo(({ selectedTab }) => { const tableRef = useRef(null); const rulesTableContext = useRulesTableContext(); - const { data: rulesInfo, isLoading: isRulesInfoLoading } = useRulesInfo(); + const { data: ruleManagementFilters, isLoading: isRulesInfoLoading } = useRulesInfo(); const { state: { @@ -214,8 +214,8 @@ export const RulesTables = React.memo(({ selectedTab }) => { const isTableEmpty = !isRulesInfoLoading && - rulesInfo?.rules_custom_count === 0 && - rulesInfo?.rules_prebuilt_installed_count === 0; + ruleManagementFilters?.rules_summary.custom_count === 0 && + ruleManagementFilters?.rules_summary.prebuilt_installed_count === 0; const shouldShowRulesTable = !isRulesInfoLoading && !isLoading && !isTableEmpty; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts index a83de7bebedc5..7600ef8981e84 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts @@ -66,9 +66,13 @@ export const getRulesInfo = (router: SecuritySolutionPluginRouter) => { const [{ prebuilt: prebuiltRulesCount, custom: customRulesCount }, tags] = await Promise.all([fetchRulesCount(rulesClient), readTags({ rulesClient })]); const responseBody: RulesInfoResponse = { - rules_custom_count: customRulesCount, - rules_prebuilt_installed_count: prebuiltRulesCount, - tags, + rules_summary: { + custom_count: customRulesCount, + prebuilt_installed_count: prebuiltRulesCount, + }, + aggregated_fields: { + tags, + }, }; const [validatedBody, validationError] = validate(responseBody, RulesInfoResponse); From 7a8ec6e59667ed372381996bf8a07dddf0c06086 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Mon, 5 Dec 2022 23:33:38 +0100 Subject: [PATCH 21/35] update rules filters fetch failure message --- .../detection_engine/rule_management/logic/translations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts index 0780cd410347e..f63449b6698ea 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts @@ -17,7 +17,7 @@ export const RULE_AND_TIMELINE_FETCH_FAILURE = i18n.translate( export const RULES_INFO_FETCH_FAILURE = i18n.translate( 'xpack.securitySolution.containers.detectionEngine.ruleManagementFiltersFetchFailure', { - defaultMessage: 'Failed to fetch rules information', + defaultMessage: 'Failed to fetch rule filters', } ); From 52bd7624b3d14e848ed081fc926abc86a201932a Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Mon, 5 Dec 2022 23:58:22 +0100 Subject: [PATCH 22/35] rename the new endpoint --- .../{info => filters}/response_schema.test.ts | 2 +- .../{info => filters}/response_schema.ts | 0 .../rule_management/api/urls.ts | 2 +- .../rule_management/api/api.ts | 10 +++++----- .../api/hooks/use_bulk_action_mutation.ts | 4 ++-- .../use_create_prebuilt_rules_mutation.ts | 4 ++-- .../api/hooks/use_create_rule_mutation.ts | 4 ++-- ...se_fetch_rule_management_filters_query.ts} | 20 ++++++++++--------- .../api/hooks/use_update_rule_mutation.ts | 4 ++-- .../rule_management/logic/translations.ts | 2 +- ...info.ts => use_rule_management_filters.ts} | 8 ++++---- .../bulk_actions/forms/tags_form.tsx | 10 ++++++---- .../rules_table_filters.tsx | 4 ++-- .../components/rules_table/rules_tables.tsx | 4 ++-- .../pages/rule_management/index.tsx | 4 ++-- .../routes/__mocks__/request_responses.ts | 4 ++-- .../rule_management/api/register_routes.ts | 4 ++-- .../api/rules/{info => filters}/route.test.ts | 16 +++++++++------ .../api/rules/{info => filters}/route.ts | 8 ++++---- ...info.ts => get_rule_management_filters.ts} | 16 +++++++-------- 20 files changed, 69 insertions(+), 61 deletions(-) rename x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/{info => filters}/response_schema.test.ts (98%) rename x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/{info => filters}/response_schema.ts (100%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/{use_fetch_rules_info_query.ts => use_fetch_rule_management_filters_query.ts} (61%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/{use_rules_info.ts => use_rule_management_filters.ts} (61%) rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/{info => filters}/route.test.ts (87%) rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/{info => filters}/route.ts (89%) rename x-pack/test/detection_engine_api_integration/security_and_spaces/group1/{get_rules_info.ts => get_rule_management_filters.ts} (89%) diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.test.ts similarity index 98% rename from x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.test.ts index 9f5ceda0e2cde..e2dd94cbb1dde 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.test.ts @@ -10,7 +10,7 @@ import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts import { RulesInfoResponse } from './response_schema'; -describe('Rules info response schema', () => { +describe('Rule management filters response schema', () => { test('it should validate an empty response with defaults', () => { const payload: RulesInfoResponse = { rules_summary: { diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.ts similarity index 100% rename from x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/info/response_schema.ts rename to x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.ts diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts index c5b673a48749f..4a4cae72cf04d 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/urls.ts @@ -7,4 +7,4 @@ import { INTERNAL_DETECTION_ENGINE_URL } from '../../../constants'; -export const RULES_INFO_URL = `${INTERNAL_DETECTION_ENGINE_URL}/rules/_info`; +export const RULE_MANAGEMENT_FILTERS_URL = `${INTERNAL_DETECTION_ENGINE_URL}/rules/_rule_management_filters`; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index fcb684526e1fc..64b71b158d081 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -11,8 +11,8 @@ import type { ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import type { RulesInfoResponse } from '../../../../common/detection_engine/rule_management/api/rules/info/response_schema'; -import { RULES_INFO_URL } from '../../../../common/detection_engine/rule_management/api/urls'; +import type { RulesInfoResponse } from '../../../../common/detection_engine/rule_management/api/rules/filters/response_schema'; +import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../common/detection_engine/rule_management/api/urls'; import type { BulkActionsDryRunErrCode } from '../../../../common/constants'; import { DETECTION_ENGINE_RULES_BULK_ACTION, @@ -389,18 +389,18 @@ export const exportRules = async ({ }; /** - * Fetch rules information like installed count, tags and etc + * Fetch rule filters related information like installed rules count, tags and etc * * @param signal to cancel request * * @throws An error if response is not OK */ -export const fetchRulesInfo = async ({ +export const fetchRuleManagementFilters = async ({ signal, }: { signal?: AbortSignal; }): Promise => - KibanaServices.get().http.fetch(RULES_INFO_URL, { + KibanaServices.get().http.fetch(RULE_MANAGEMENT_FILTERS_URL, { method: 'GET', signal, }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts index 3d507e50fa6a7..04060bbd41e7a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts @@ -13,7 +13,7 @@ import { performBulkAction } from '../api'; import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../common/constants'; import { useInvalidateFindRulesQuery, useUpdateRulesCache } from './use_find_rules_query'; import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; -import { useInvalidateFetchRulesInfoQuery } from './use_fetch_rules_info_query'; +import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; export const BULK_ACTION_MUTATION_KEY = ['POST', DETECTION_ENGINE_RULES_BULK_ACTION]; @@ -26,7 +26,7 @@ export const useBulkActionMutation = ( ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); - const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); + const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); const updateRulesCache = useUpdateRulesCache(); return useMutation< diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts index 8be2539653b4b..6dc10d7e3091a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts @@ -11,7 +11,7 @@ import type { CreatePrepackagedRulesResponse } from '../api'; import { createPrepackagedRules } from '../api'; import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; -import { useInvalidateFetchRulesInfoQuery } from './use_fetch_rules_info_query'; +import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; export const CREATE_PREBUILT_RULES_MUTATION_KEY = ['PUT', PREBUILT_RULES_URL]; @@ -20,7 +20,7 @@ export const useCreatePrebuiltRulesMutation = ( ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidatePrePackagedRulesStatus = useInvalidateFetchPrebuiltRulesStatusQuery(); - const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); + const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); return useMutation(() => createPrepackagedRules(), { ...options, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts index 3e59348a3d61d..2d32e6a521a5f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts @@ -13,7 +13,7 @@ import type { } from '../../../../../common/detection_engine/rule_schema'; import { transformOutput } from '../../../../detections/containers/detection_engine/rules/transforms'; import { createRule } from '../api'; -import { useInvalidateFetchRulesInfoQuery } from './use_fetch_rules_info_query'; +import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; export const CREATE_RULE_MUTATION_KEY = ['POST', DETECTION_ENGINE_RULES_URL]; @@ -22,7 +22,7 @@ export const useCreateRuleMutation = ( options?: UseMutationOptions ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); + const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); return useMutation( (rule: RuleCreateProps) => createRule({ rule: transformOutput(rule) }), diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts similarity index 61% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts index 640897d5f1318..7992c7fc27d47 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rules_info_query.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts @@ -7,18 +7,20 @@ import { useCallback } from 'react'; import type { UseQueryOptions } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query'; -import type { RulesInfoResponse } from '../../../../../common/detection_engine/rule_management/api/rules/info/response_schema'; -import { RULES_INFO_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; -import { fetchRulesInfo } from '../api'; +import type { RulesInfoResponse } from '../../../../../common/detection_engine/rule_management/api/rules/filters/response_schema'; +import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; +import { fetchRuleManagementFilters } from '../api'; import { DEFAULT_QUERY_OPTIONS } from './constants'; -export const RULES_INFO_QUERY_KEY = ['GET', RULES_INFO_URL]; +export const RULE_MANAGEMENT_FILTERS_QUERY_KEY = ['GET', RULE_MANAGEMENT_FILTERS_URL]; -export const useFetchRulesInfoQuery = (options?: UseQueryOptions) => { +export const useFetchRuleManagementFiltersQuery = ( + options?: UseQueryOptions +) => { return useQuery( - RULES_INFO_QUERY_KEY, + RULE_MANAGEMENT_FILTERS_QUERY_KEY, async ({ signal }) => { - const response = await fetchRulesInfo({ signal }); + const response = await fetchRuleManagementFilters({ signal }); return response; }, { @@ -35,11 +37,11 @@ export const useFetchRulesInfoQuery = (options?: UseQueryOptions { +export const useInvalidateFetchRuleManagementFiltersQuery = () => { const queryClient = useQueryClient(); return useCallback(() => { - queryClient.invalidateQueries(RULES_INFO_QUERY_KEY, { + queryClient.invalidateQueries(RULE_MANAGEMENT_FILTERS_QUERY_KEY, { refetchType: 'active', }); }, [queryClient]); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts index bdfc5fe8eced9..6f3033e5e2a43 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts @@ -15,7 +15,7 @@ import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { updateRule } from '../api'; import { useInvalidateFindRulesQuery } from './use_find_rules_query'; import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; -import { useInvalidateFetchRulesInfoQuery } from './use_fetch_rules_info_query'; +import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; export const UPDATE_RULE_MUTATION_KEY = ['PUT', DETECTION_ENGINE_RULES_URL]; @@ -23,7 +23,7 @@ export const useUpdateRuleMutation = ( options?: UseMutationOptions ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); + const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); return useMutation( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts index f63449b6698ea..56ebc3e133775 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/translations.ts @@ -14,7 +14,7 @@ export const RULE_AND_TIMELINE_FETCH_FAILURE = i18n.translate( } ); -export const RULES_INFO_FETCH_FAILURE = i18n.translate( +export const RULE_MANAGEMENT_FILTERS_FETCH_FAILURE = i18n.translate( 'xpack.securitySolution.containers.detectionEngine.ruleManagementFiltersFetchFailure', { defaultMessage: 'Failed to fetch rule filters', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rules_info.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_management_filters.ts similarity index 61% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rules_info.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_management_filters.ts index 19a9b7dcc8490..a16f433b993a1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rules_info.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_management_filters.ts @@ -5,15 +5,15 @@ * 2.0. */ import { useAppToasts } from '../../../common/hooks/use_app_toasts'; -import { useFetchRulesInfoQuery } from '../api/hooks/use_fetch_rules_info_query'; +import { useFetchRuleManagementFiltersQuery } from '../api/hooks/use_fetch_rule_management_filters_query'; import * as i18n from './translations'; -export const useRulesInfo = () => { +export const useRuleManagementFilters = () => { const { addError } = useAppToasts(); - return useFetchRulesInfoQuery({ + return useFetchRuleManagementFiltersQuery({ onError: (err) => { - addError(err, { title: i18n.RULES_INFO_FETCH_FAILURE }); + addError(err, { title: i18n.RULE_MANAGEMENT_FILTERS_FETCH_FAILURE }); }, }); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx index 2a3b73056d6c6..3e09b5dd3bed7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/tags_form.tsx @@ -9,7 +9,7 @@ import { EuiCallOut, EuiFormRow } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import React, { useMemo } from 'react'; -import { useRulesInfo } from '../../../../../rule_management/logic/use_rules_info'; +import { useRuleManagementFilters } from '../../../../../rule_management/logic/use_rule_management_filters'; import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import { BulkActionEditType } from '../../../../../../../common/detection_engine/rule_management/api/rules/bulk_actions/request_schema'; import * as i18n from '../../../../../../detections/pages/detection_engine/rules/translations'; @@ -78,14 +78,16 @@ interface TagsFormProps { } const TagsFormComponent = ({ editAction, rulesCount, onClose, onConfirm }: TagsFormProps) => { - const { data: ruleManagementFilters } = useRulesInfo(); - const tags = ruleManagementFilters?.aggregated_fields.tags ?? []; + const { data: ruleManagementFilters } = useRuleManagementFilters(); const { form } = useForm({ defaultValue: initialFormData, schema, }); const [{ overwrite }] = useFormData({ form, watch: ['overwrite'] }); - const sortedTags = useMemo(() => caseInsensitiveSort(tags), [tags]); + const sortedTags = useMemo( + () => caseInsensitiveSort(ruleManagementFilters?.aggregated_fields.tags ?? []), + [ruleManagementFilters] + ); const { tagsLabel, tagsHelpText, formTitle } = getFormConfig(editAction); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx index 8202311513dd9..2fa5a3806874a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rules_table_filters.tsx @@ -9,7 +9,7 @@ import { EuiFilterButton, EuiFilterGroup, EuiFlexGroup, EuiFlexItem } from '@ela import { isEqual } from 'lodash/fp'; import React, { useCallback } from 'react'; import styled from 'styled-components'; -import { useRulesInfo } from '../../../../rule_management/logic/use_rules_info'; +import { useRuleManagementFilters } from '../../../../rule_management/logic/use_rule_management_filters'; import { RULES_TABLE_ACTIONS } from '../../../../../common/lib/apm/user_actions'; import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; @@ -31,7 +31,7 @@ const RulesTableFiltersComponent = () => { state: { filterOptions }, actions: { setFilterOptions }, } = useRulesTableContext(); - const { data: ruleManagementFields } = useRulesInfo(); + const { data: ruleManagementFields } = useRuleManagementFilters(); const allTags = ruleManagementFields?.aggregated_fields.tags ?? []; const rulesCustomCount = ruleManagementFields?.rules_summary.custom_count; const rulesPrebuiltInstalledCount = ruleManagementFields?.rules_summary.prebuilt_installed_count; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx index e8e9df649b589..4941eaa9fd8eb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx @@ -38,7 +38,7 @@ import { useBulkDuplicateExceptionsConfirmation } from './bulk_actions/use_bulk_ import { BulkActionDuplicateExceptionsConfirmation } from './bulk_actions/bulk_duplicate_exceptions_confirmation'; import { useStartMlJobs } from '../../../rule_management/logic/use_start_ml_jobs'; import { RULES_TABLE_PAGE_SIZE_OPTIONS } from './constants'; -import { useRulesInfo } from '../../../rule_management/logic/use_rules_info'; +import { useRuleManagementFilters } from '../../../rule_management/logic/use_rule_management_filters'; const INITIAL_SORT_FIELD = 'enabled'; @@ -65,7 +65,7 @@ export const RulesTables = React.memo(({ selectedTab }) => { const tableRef = useRef(null); const rulesTableContext = useRulesTableContext(); - const { data: ruleManagementFilters, isLoading: isRulesInfoLoading } = useRulesInfo(); + const { data: ruleManagementFilters, isLoading: isRulesInfoLoading } = useRuleManagementFilters(); const { state: { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx index 03147fd526fc5..db98382403c6f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx @@ -41,14 +41,14 @@ import { RulesTableContextProvider } from '../../components/rules_table/rules_ta import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; import { RulesPageTourComponent } from '../../components/rules_table/alternative_tour/tour'; -import { useInvalidateFetchRulesInfoQuery } from '../../../rule_management/api/hooks/use_fetch_rules_info_query'; +import { useInvalidateFetchRuleManagementFiltersQuery } from '../../../rule_management/api/hooks/use_fetch_rule_management_filters_query'; const RulesPageComponent: React.FC = () => { const [isImportModalVisible, showImportModal, hideImportModal] = useBoolState(); const [isValueListFlyoutVisible, showValueListFlyout, hideValueListFlyout] = useBoolState(); const { navigateToApp } = useKibana().services.application; const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchRulesInfo = useInvalidateFetchRulesInfoQuery(); + const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateRules = useCallback(() => { invalidateFindRulesQuery(); invalidateFetchRulesInfo(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 68ec467c52993..2d29058072abe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -24,7 +24,7 @@ import { DETECTION_ENGINE_RULES_BULK_CREATE, DETECTION_ENGINE_RULES_URL_FIND, } from '../../../../../common/constants'; -import { RULES_INFO_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; +import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; import { PREBUILT_RULES_STATUS_URL, @@ -194,7 +194,7 @@ export const getPrepackagedRulesStatusRequest = () => export const getRulesInfoRequest = () => requestMock.create({ method: 'get', - path: RULES_INFO_URL, + path: RULE_MANAGEMENT_FILTERS_URL, }); export interface FindHit { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts index a0f9b187c8eb7..53c4e54484e18 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/register_routes.ts @@ -20,7 +20,7 @@ import { deleteRuleRoute } from './rules/delete_rule/route'; import { exportRulesRoute } from './rules/export_rules/route'; import { findRulesRoute } from './rules/find_rules/route'; import { importRulesRoute } from './rules/import_rules/route'; -import { getRulesInfo } from './rules/info/route'; +import { getRuleManagementFilters } from './rules/filters/route'; import { patchRuleRoute } from './rules/patch_rule/route'; import { readRuleRoute } from './rules/read_rule/route'; import { updateRuleRoute } from './rules/update_rule/route'; @@ -59,5 +59,5 @@ export const registerRuleManagementRoutes = ( readTagsRoute(router); // Rules filters - getRulesInfo(router); + getRuleManagementFilters(router); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.test.ts similarity index 87% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.test.ts index 58f43810369d0..4d54abd8eb37b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { getRulesInfo } from './route'; +import { getRuleManagementFilters } from './route'; import { getEmptyFindResult, @@ -14,7 +14,7 @@ import { } from '../../../../routes/__mocks__/request_responses'; import { requestContextMock, serverMock } from '../../../../routes/__mocks__'; -describe('Rules info route', () => { +describe('Rule management filters route', () => { let server: ReturnType; let { clients, context } = requestContextMock.createTools(); @@ -25,7 +25,7 @@ describe('Rules info route', () => { clients.rulesClient.find.mockResolvedValue(getEmptyFindResult()); - getRulesInfo(server.router); + getRuleManagementFilters(server.router); }); describe('status codes', () => { @@ -66,9 +66,13 @@ describe('Rules info route', () => { expect(response.status).toEqual(200); expect(response.body).toEqual({ - rules_custom_count: 1, - rules_prebuilt_installed_count: 1, - tags: ['a', 'b', 'c'], + rules_summary: { + custom_count: 1, + prebuilt_installed_count: 1, + }, + aggregated_fields: { + tags: ['a', 'b', 'c'], + }, }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts similarity index 89% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts index 7600ef8981e84..ecc58723151ad 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/info/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts @@ -8,8 +8,8 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { validate } from '@kbn/securitysolution-io-ts-utils'; import type { RulesClient } from '@kbn/alerting-plugin/server'; -import { RulesInfoResponse } from '../../../../../../../common/detection_engine/rule_management/api/rules/info/response_schema'; -import { RULES_INFO_URL } from '../../../../../../../common/detection_engine/rule_management/api/urls'; +import { RulesInfoResponse } from '../../../../../../../common/detection_engine/rule_management/api/rules/filters/response_schema'; +import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../../../common/detection_engine/rule_management/api/urls'; import { buildSiemResponse } from '../../../../routes/utils'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; import { findRules } from '../../../logic/search/find_rules'; @@ -48,10 +48,10 @@ async function fetchRulesCount(rulesClient: RulesClient): Promise { }; } -export const getRulesInfo = (router: SecuritySolutionPluginRouter) => { +export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) => { router.get( { - path: RULES_INFO_URL, + path: RULE_MANAGEMENT_FILTERS_URL, validate: false, options: { tags: ['access:securitySolution'], diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts similarity index 89% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts rename to x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts index 605f9bf1b013a..c5e29679ec17e 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rules_info.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { PREBUILT_RULES_URL } from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; -import { RULES_INFO_URL } from '@kbn/security-solution-plugin/common/detection_engine/rule_management/api/urls'; +import { RULE_MANAGEMENT_FILTERS_URL } from '@kbn/security-solution-plugin/common/detection_engine/rule_management/api/urls'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { @@ -26,7 +26,7 @@ export default ({ getService }: FtrProviderContext): void => { const es = getService('es'); const log = getService('log'); - describe('get_rules_info', () => { + describe('get_rule_management_filters', () => { beforeEach(async () => { await createSignalsIndex(supertest, log); }); @@ -39,7 +39,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return expected JSON keys', async () => { const { body } = await supertest - .get(RULES_INFO_URL) + .get(RULE_MANAGEMENT_FILTERS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -53,7 +53,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return the correct result when there are no rules', async () => { const { body } = await supertest - .get(RULES_INFO_URL) + .get(RULE_MANAGEMENT_FILTERS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -76,7 +76,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return the correct number of custom rules', async () => { const { body } = await supertest - .get(RULES_INFO_URL) + .get(RULE_MANAGEMENT_FILTERS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -86,7 +86,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return correct tags', async () => { const { body } = await supertest - .get(RULES_INFO_URL) + .get(RULE_MANAGEMENT_FILTERS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -101,7 +101,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return the correct number of installed prepacked rules after pre-packaged rules have been installed', async () => { const { body } = await supertest - .get(RULES_INFO_URL) + .get(RULE_MANAGEMENT_FILTERS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -111,7 +111,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should return correct tags', async () => { const { body } = await supertest - .get(RULES_INFO_URL) + .get(RULE_MANAGEMENT_FILTERS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); From 51bc5fdaad76fbda8dc9c32a20c8d64efc59745f Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Tue, 6 Dec 2022 00:03:43 +0100 Subject: [PATCH 23/35] display rules table without waiting for filters to load --- .../components/rules_table/rules_tables.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx index 4941eaa9fd8eb..95fc837a8e8f5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx @@ -65,7 +65,7 @@ export const RulesTables = React.memo(({ selectedTab }) => { const tableRef = useRef(null); const rulesTableContext = useRulesTableContext(); - const { data: ruleManagementFilters, isLoading: isRulesInfoLoading } = useRuleManagementFilters(); + const { data: ruleManagementFilters } = useRuleManagementFilters(); const { state: { @@ -213,11 +213,10 @@ export const RulesTables = React.memo(({ selectedTab }) => { }, [rules, isAllSelected, setIsAllSelected, setSelectedRuleIds]); const isTableEmpty = - !isRulesInfoLoading && ruleManagementFilters?.rules_summary.custom_count === 0 && ruleManagementFilters?.rules_summary.prebuilt_installed_count === 0; - const shouldShowRulesTable = !isRulesInfoLoading && !isLoading && !isTableEmpty; + const shouldShowRulesTable = !isLoading && !isTableEmpty; const tableProps = selectedTab === AllRulesTabs.rules From 30496a6ca67bd067514a80933b3fdf98982d8e3c Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Tue, 6 Dec 2022 00:46:37 +0100 Subject: [PATCH 24/35] restructure integration tests --- .../group1/get_rule_management_filters.ts | 112 ++++++++++++++---- .../security_and_spaces/group1/index.ts | 2 +- 2 files changed, 89 insertions(+), 25 deletions(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts index c5e29679ec17e..e543bdb460671 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts @@ -37,29 +37,22 @@ export default ({ getService }: FtrProviderContext): void => { await deleteAllTimelines(es); }); - it('should return expected JSON keys', async () => { - const { body } = await supertest - .get(RULE_MANAGEMENT_FILTERS_URL) - .set('kbn-xsrf', 'true') - .send() - .expect(200); - - expect(Object.keys(body)).to.eql([ - 'rules_custom_count', - 'rules_prebuilt_installed_count', - 'tags', - ]); - }); - it('should return the correct result when there are no rules', async () => { const { body } = await supertest .get(RULE_MANAGEMENT_FILTERS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); - expect(body.rules_custom_count).to.eql(0); - expect(body.rules_prebuilt_installed_count).to.eql(0); - expect(body.tags).to.eql([]); + + expect(body).to.eql({ + rules_summary: { + custom_count: 0, + prebuilt_installed_count: 0, + }, + aggregated_fields: { + tags: [], + }, + }); }); describe('when there is a custom rule', () => { @@ -80,8 +73,9 @@ export default ({ getService }: FtrProviderContext): void => { .set('kbn-xsrf', 'true') .send() .expect(200); - expect(body.rules_custom_count).to.eql(1); - expect(body.rules_prebuilt_installed_count).to.eql(0); + + expect(body.rules_summary.custom_count).to.eql(1); + expect(body.rules_summary.prebuilt_installed_count).to.eql(0); }); it('should return correct tags', async () => { @@ -90,7 +84,8 @@ export default ({ getService }: FtrProviderContext): void => { .set('kbn-xsrf', 'true') .send() .expect(200); - expect(body.tags).to.eql(['tag-a']); + + expect(body.aggregated_fields.tags).to.eql(['tag-a']); }); }); @@ -105,17 +100,86 @@ export default ({ getService }: FtrProviderContext): void => { .set('kbn-xsrf', 'true') .send() .expect(200); - expect(body.rules_prebuilt_installed_count).to.be.greaterThan(0); - expect(body.rules_custom_count).to.eql(0); + + expect(body.rules_summary.prebuilt_installed_count).to.eql(723); + expect(body.rules_summary.custom_count).to.eql(0); }); - it('should return correct tags', async () => { + it('should return installed prebuilt rules tags', async () => { const { body } = await supertest .get(RULE_MANAGEMENT_FILTERS_URL) .set('kbn-xsrf', 'true') .send() .expect(200); - expect(body.tags.length).to.be.greaterThan(0); + + expect(body.aggregated_fields.tags).to.eql([ + 'APM', + 'AWS', + 'Active Directory', + 'Application', + 'Asset Visibility', + 'Authentication', + 'Azure', + 'BPFDoor', + 'CVE-2020-1313', + 'CVE-2020-9613', + 'CVE-2020-9614', + 'CVE-2020-9615', + 'CVE_2020_9771', + 'Cloud', + 'Collection', + 'Command and Control', + 'Communication', + 'Configuration Audit', + 'Continuous Monitoring', + 'Credential Access', + 'Data Protection', + 'Defense Evasion', + 'Discovery', + 'Elastic', + 'Elastic Endgame', + 'Endpoint Security', + 'Example', + 'Execution', + 'Exfiltration', + 'GCP', + 'GTFOBins', + 'Google Workspace', + 'Guided Onboarding', + 'Higher-Order Rules', + 'Host', + 'Identity', + 'Identity and Access', + 'Impact', + 'Impair Defenses', + 'Initial Access', + 'Investigation Guide', + 'Kubernetes', + 'Lateral Movement', + 'Lightning Framework', + 'Linux', + 'Log Auditing', + 'ML', + 'Microsoft 365', + 'Monitoring', + 'Network', + 'Network Security', + 'Okta', + 'Orbit', + 'Persistence', + 'Post-Execution', + 'Privilege Escalation', + 'Resource Development', + 'Rootkit', + 'SecOps', + 'Sysmon Only', + 'Threat Detection', + 'TripleCross', + 'Windows', + 'Zoom', + 'cyberarkpas', + 'macOS', + ]); }); }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts index f1e2672e31484..24e0d5389a018 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts @@ -31,6 +31,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./find_rules')); loadTestFile(require.resolve('./find_rule_exception_references')); loadTestFile(require.resolve('./get_prepackaged_rules_status')); - loadTestFile(require.resolve('./get_rules_info')); + loadTestFile(require.resolve('./get_rule_management_filters')); }); }; From 44942f14da6e06b7a534a91e9c50e4375050fa79 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Tue, 6 Dec 2022 10:18:35 +0100 Subject: [PATCH 25/35] revert prebuilt rules invalidation upon rules deletion --- .../rule_management/api/hooks/use_bulk_action_mutation.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts index 04060bbd41e7a..9b20c212bb53e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts @@ -11,6 +11,7 @@ import { BulkActionType } from '../../../../../common/detection_engine/rule_mana import type { BulkActionErrorResponse, BulkActionResponse, PerformBulkActionProps } from '../api'; import { performBulkAction } from '../api'; import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../common/constants'; +import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFindRulesQuery, useUpdateRulesCache } from './use_find_rules_query'; import { useInvalidateFetchRuleByIdQuery } from './use_fetch_rule_by_id_query'; import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; @@ -27,6 +28,7 @@ export const useBulkActionMutation = ( const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchPrebuiltRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); const updateRulesCache = useUpdateRulesCache(); return useMutation< @@ -65,6 +67,7 @@ export const useBulkActionMutation = ( invalidateFindRulesQuery(); invalidateFetchRuleByIdQuery(); invalidateFetchRulesInfo(); + invalidateFetchPrebuiltRulesStatusQuery(); break; case BulkActionType.duplicate: invalidateFindRulesQuery(); From aa374e9b55a6ff3a318ef9f582e36d8baa1c4658 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Tue, 6 Dec 2022 20:06:28 +0100 Subject: [PATCH 26/35] fix integration tests --- .../group1/get_rule_management_filters.ts | 95 +++---------------- .../create_prebuilt_rule_saved_objects.ts | 3 + 2 files changed, 14 insertions(+), 84 deletions(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts index e543bdb460671..9d95505e3db65 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/get_rule_management_filters.ts @@ -8,17 +8,12 @@ import expect from '@kbn/expect'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; -import { PREBUILT_RULES_URL } from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; import { RULE_MANAGEMENT_FILTERS_URL } from '@kbn/security-solution-plugin/common/detection_engine/rule_management/api/urls'; - +import { PREBUILT_RULES_URL } from '@kbn/security-solution-plugin/common/detection_engine/prebuilt_rules'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - createSignalsIndex, - deleteAllAlerts, - deleteSignalsIndex, - getSimpleRule, - deleteAllTimelines, -} from '../../utils'; +import { deleteAllAlerts, getSimpleRule } from '../../utils'; +import { createPrebuiltRuleAssetSavedObjects } from '../../utils/create_prebuilt_rule_saved_objects'; +import { deleteAllPrebuiltRules } from '../../utils/delete_all_prebuilt_rules'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { @@ -28,13 +23,7 @@ export default ({ getService }: FtrProviderContext): void => { describe('get_rule_management_filters', () => { beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteSignalsIndex(supertest, log); await deleteAllAlerts(supertest, log); - await deleteAllTimelines(es); }); it('should return the correct result when there are no rules', async () => { @@ -91,9 +80,14 @@ export default ({ getService }: FtrProviderContext): void => { describe('when there are installed prebuilt rules', () => { beforeEach(async () => { + await createPrebuiltRuleAssetSavedObjects(es); await supertest.put(PREBUILT_RULES_URL).set('kbn-xsrf', 'true').send().expect(200); }); + afterEach(async () => { + await deleteAllPrebuiltRules(es); + }); + it('should return the correct number of installed prepacked rules after pre-packaged rules have been installed', async () => { const { body } = await supertest .get(RULE_MANAGEMENT_FILTERS_URL) @@ -101,7 +95,7 @@ export default ({ getService }: FtrProviderContext): void => { .send() .expect(200); - expect(body.rules_summary.prebuilt_installed_count).to.eql(723); + expect(body.rules_summary.prebuilt_installed_count).to.eql(3); expect(body.rules_summary.custom_count).to.eql(0); }); @@ -112,74 +106,7 @@ export default ({ getService }: FtrProviderContext): void => { .send() .expect(200); - expect(body.aggregated_fields.tags).to.eql([ - 'APM', - 'AWS', - 'Active Directory', - 'Application', - 'Asset Visibility', - 'Authentication', - 'Azure', - 'BPFDoor', - 'CVE-2020-1313', - 'CVE-2020-9613', - 'CVE-2020-9614', - 'CVE-2020-9615', - 'CVE_2020_9771', - 'Cloud', - 'Collection', - 'Command and Control', - 'Communication', - 'Configuration Audit', - 'Continuous Monitoring', - 'Credential Access', - 'Data Protection', - 'Defense Evasion', - 'Discovery', - 'Elastic', - 'Elastic Endgame', - 'Endpoint Security', - 'Example', - 'Execution', - 'Exfiltration', - 'GCP', - 'GTFOBins', - 'Google Workspace', - 'Guided Onboarding', - 'Higher-Order Rules', - 'Host', - 'Identity', - 'Identity and Access', - 'Impact', - 'Impair Defenses', - 'Initial Access', - 'Investigation Guide', - 'Kubernetes', - 'Lateral Movement', - 'Lightning Framework', - 'Linux', - 'Log Auditing', - 'ML', - 'Microsoft 365', - 'Monitoring', - 'Network', - 'Network Security', - 'Okta', - 'Orbit', - 'Persistence', - 'Post-Execution', - 'Privilege Escalation', - 'Resource Development', - 'Rootkit', - 'SecOps', - 'Sysmon Only', - 'Threat Detection', - 'TripleCross', - 'Windows', - 'Zoom', - 'cyberarkpas', - 'macOS', - ]); + expect(body.aggregated_fields.tags).to.eql(['test-tag-1', 'test-tag-2', 'test-tag-3']); }); }); }); diff --git a/x-pack/test/detection_engine_api_integration/utils/create_prebuilt_rule_saved_objects.ts b/x-pack/test/detection_engine_api_integration/utils/create_prebuilt_rule_saved_objects.ts index 15778e41a3be6..c97f97d3a62a3 100644 --- a/x-pack/test/detection_engine_api_integration/utils/create_prebuilt_rule_saved_objects.ts +++ b/x-pack/test/detection_engine_api_integration/utils/create_prebuilt_rule_saved_objects.ts @@ -21,6 +21,7 @@ export const SAMPLE_PREBUILT_RULES = [ 'security-rule': { ...getPrebuiltRuleWithExceptionsMock(), rule_id: ELASTIC_SECURITY_RULE_ID, + tags: ['test-tag-1'], enabled: true, }, type: 'security-rule', @@ -33,6 +34,7 @@ export const SAMPLE_PREBUILT_RULES = [ 'security-rule': { ...getPrebuiltRuleMock(), rule_id: '000047bb-b27a-47ec-8b62-ef1a5d2c9e19', + tags: ['test-tag-2'], }, type: 'security-rule', references: [], @@ -44,6 +46,7 @@ export const SAMPLE_PREBUILT_RULES = [ 'security-rule': { ...getPrebuiltRuleMock(), rule_id: '00140285-b827-4aee-aa09-8113f58a08f3', + tags: ['test-tag-3'], }, type: 'security-rule', references: [], From 113a35681708762720c7dcab8adb29d6088f6876 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Thu, 8 Dec 2022 11:06:01 +0100 Subject: [PATCH 27/35] remove unused local functions --- .../api/tags/read_tags/read_tags.test.ts | 105 +----------------- .../api/tags/read_tags/read_tags.ts | 25 ----- 2 files changed, 1 insertion(+), 129 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts index db61d540170af..1750cecdf1673 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.test.ts @@ -6,12 +6,7 @@ */ import { rulesClientMock } from '@kbn/alerting-plugin/server/mocks'; -import { - getRuleMock, - getFindResultWithMultiHits, -} from '../../../../routes/__mocks__/request_responses'; -import { getQueryRuleParams } from '../../../../rule_schema/mocks'; -import { readTags, convertTagsToSet, convertToTags, isTags } from './read_tags'; +import { readTags } from './read_tags'; describe('read_tags', () => { afterEach(() => { @@ -31,102 +26,4 @@ describe('read_tags', () => { expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']); }); }); - - describe('convertTagsToSet', () => { - test('it should convert the intersection of two tag systems without duplicates', () => { - const result1 = getRuleMock(getQueryRuleParams()); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3']; - - const result2 = getRuleMock(getQueryRuleParams()); - result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result2.params.ruleId = 'rule-2'; - result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; - - const findResult = getFindResultWithMultiHits({ data: [result1, result2] }); - const set = convertTagsToSet(findResult.data); - expect(Array.from(set)).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']); - }); - - test('it should with with an empty array', () => { - const set = convertTagsToSet([]); - expect(Array.from(set)).toEqual([]); - }); - }); - - describe('convertToTags', () => { - test('it should convert the two tag systems together with duplicates', () => { - const result1 = getRuleMock(getQueryRuleParams()); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3']; - - const result2 = getRuleMock(getQueryRuleParams()); - result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result2.params.ruleId = 'rule-2'; - result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; - - const findResult = getFindResultWithMultiHits({ data: [result1, result2] }); - const tags = convertToTags(findResult.data); - expect(tags).toEqual([ - 'tag 1', - 'tag 2', - 'tag 2', - 'tag 3', - 'tag 1', - 'tag 2', - 'tag 2', - 'tag 3', - 'tag 4', - ]); - }); - - test('it should filter out anything that is not a tag', () => { - const result1 = getRuleMock(getQueryRuleParams()); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3']; - - const result2 = getRuleMock(getQueryRuleParams()); - result2.id = '99979e67-19a7-455f-b452-8eded6135716'; - result2.params.ruleId = 'rule-2'; - // @ts-expect-error - delete result2.tags; - - const result3 = getRuleMock(getQueryRuleParams()); - result3.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result3.params.ruleId = 'rule-2'; - result3.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; - - const findResult = getFindResultWithMultiHits({ data: [result1, result2, result3] }); - const tags = convertToTags(findResult.data); - expect(tags).toEqual([ - 'tag 1', - 'tag 2', - 'tag 2', - 'tag 3', - 'tag 1', - 'tag 2', - 'tag 2', - 'tag 3', - 'tag 4', - ]); - }); - - test('it should with with an empty array', () => { - const tags = convertToTags([]); - expect(tags).toEqual([]); - }); - }); - - describe('isTags', () => { - test('it should return true if the object has a tags on it', () => { - expect(isTags({ tags: [] })).toBe(true); - }); - - test('it should return false if the object does not have a tags on it', () => { - expect(isTags({})).toBe(false); - }); - }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts index bfef4866a2c3f..7bf2ac5445a30 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts @@ -5,33 +5,8 @@ * 2.0. */ -import { has } from 'lodash/fp'; import type { RulesClient } from '@kbn/alerting-plugin/server'; -export interface TagType { - id: string; - tags: string[]; -} - -export const isTags = (obj: object): obj is TagType => { - return has('tags', obj); -}; - -export const convertToTags = (tagObjects: object[]): string[] => { - const tags = tagObjects.reduce((acc, tagObj) => { - if (isTags(tagObj)) { - return [...acc, ...tagObj.tags]; - } else { - return acc; - } - }, []); - return tags; -}; - -export const convertTagsToSet = (tagObjects: object[]): Set => { - return new Set(convertToTags(tagObjects)); -}; - // This is a contrived max limit on the number of tags. In fact it can exceed this number and will be truncated to the hardcoded number. const EXPECTED_MAX_TAGS = 500; From 8012ce5fbb5827da010baa522671c125d397b477 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Thu, 8 Dec 2022 11:07:15 +0100 Subject: [PATCH 28/35] increase the max number of tags --- .../rule_management/api/tags/read_tags/read_tags.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts index 7bf2ac5445a30..4ee3f49980cdb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts @@ -8,7 +8,7 @@ import type { RulesClient } from '@kbn/alerting-plugin/server'; // This is a contrived max limit on the number of tags. In fact it can exceed this number and will be truncated to the hardcoded number. -const EXPECTED_MAX_TAGS = 500; +const EXPECTED_MAX_TAGS = 65536; export const readTags = async ({ rulesClient, From 6eadf46e0d71a20d9e17e4f03d271f904d5a2b7a Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Thu, 8 Dec 2022 11:14:33 +0100 Subject: [PATCH 29/35] rename unrenamed leftovers --- .../api/rules/filters/response_schema.test.ts | 30 +++++++++---------- .../api/rules/filters/response_schema.ts | 4 +-- .../rule_management/api/api.ts | 6 ++-- .../api/hooks/use_bulk_action_mutation.ts | 8 ++--- .../use_create_prebuilt_rules_mutation.ts | 4 +-- .../api/hooks/use_create_rule_mutation.ts | 4 +-- ...use_fetch_rule_management_filters_query.ts | 6 ++-- .../api/hooks/use_update_rule_mutation.ts | 4 +-- .../pages/rule_management/index.tsx | 6 ++-- .../routes/__mocks__/request_responses.ts | 2 +- .../api/rules/filters/route.test.ts | 8 ++--- .../api/rules/filters/route.ts | 9 ++++-- 12 files changed, 47 insertions(+), 44 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.test.ts index e2dd94cbb1dde..85a28a3042092 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.test.ts @@ -8,11 +8,11 @@ import { left } from 'fp-ts/lib/Either'; import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { RulesInfoResponse } from './response_schema'; +import { RuleManagementFiltersResponse } from './response_schema'; describe('Rule management filters response schema', () => { test('it should validate an empty response with defaults', () => { - const payload: RulesInfoResponse = { + const payload: RuleManagementFiltersResponse = { rules_summary: { custom_count: 0, prebuilt_installed_count: 0, @@ -21,7 +21,7 @@ describe('Rule management filters response schema', () => { tags: [], }, }; - const decoded = RulesInfoResponse.decode(payload); + const decoded = RuleManagementFiltersResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); @@ -30,7 +30,7 @@ describe('Rule management filters response schema', () => { }); test('it should validate an non empty response with defaults', () => { - const payload: RulesInfoResponse = { + const payload: RuleManagementFiltersResponse = { rules_summary: { custom_count: 10, prebuilt_installed_count: 20, @@ -39,7 +39,7 @@ describe('Rule management filters response schema', () => { tags: ['a', 'b', 'c'], }, }; - const decoded = RulesInfoResponse.decode(payload); + const decoded = RuleManagementFiltersResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); @@ -48,7 +48,7 @@ describe('Rule management filters response schema', () => { }); test('it should not validate an extra invalid field added', () => { - const payload: RulesInfoResponse & { invalid_field: string } = { + const payload: RuleManagementFiltersResponse & { invalid_field: string } = { rules_summary: { custom_count: 0, prebuilt_installed_count: 0, @@ -58,7 +58,7 @@ describe('Rule management filters response schema', () => { }, invalid_field: 'invalid', }; - const decoded = RulesInfoResponse.decode(payload); + const decoded = RuleManagementFiltersResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); @@ -67,7 +67,7 @@ describe('Rule management filters response schema', () => { }); test('it should NOT validate an empty response with a negative "summary.prebuilt_installed_count" number', () => { - const payload: RulesInfoResponse = { + const payload: RuleManagementFiltersResponse = { rules_summary: { custom_count: 0, prebuilt_installed_count: -1, @@ -76,7 +76,7 @@ describe('Rule management filters response schema', () => { tags: [], }, }; - const decoded = RulesInfoResponse.decode(payload); + const decoded = RuleManagementFiltersResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); @@ -87,7 +87,7 @@ describe('Rule management filters response schema', () => { }); test('it should NOT validate an empty response with a negative "summary.custom_count"', () => { - const payload: RulesInfoResponse = { + const payload: RuleManagementFiltersResponse = { rules_summary: { custom_count: -1, prebuilt_installed_count: 0, @@ -96,7 +96,7 @@ describe('Rule management filters response schema', () => { tags: [], }, }; - const decoded = RulesInfoResponse.decode(payload); + const decoded = RuleManagementFiltersResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); @@ -107,7 +107,7 @@ describe('Rule management filters response schema', () => { }); test('it should NOT validate an empty prepackaged response if "summary.prebuilt_installed_count" is not there', () => { - const payload: RulesInfoResponse = { + const payload: RuleManagementFiltersResponse = { rules_summary: { custom_count: 0, prebuilt_installed_count: 0, @@ -118,7 +118,7 @@ describe('Rule management filters response schema', () => { }; // @ts-expect-error delete payload.rules_summary.prebuilt_installed_count; - const decoded = RulesInfoResponse.decode(payload); + const decoded = RuleManagementFiltersResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); @@ -129,7 +129,7 @@ describe('Rule management filters response schema', () => { }); test('it should NOT validate an empty response with wrong "aggregated_fields.tags"', () => { - const payload: RulesInfoResponse = { + const payload: RuleManagementFiltersResponse = { rules_summary: { custom_count: 0, prebuilt_installed_count: 0, @@ -139,7 +139,7 @@ describe('Rule management filters response schema', () => { tags: [1], }, }; - const decoded = RulesInfoResponse.decode(payload); + const decoded = RuleManagementFiltersResponse.decode(payload); const checked = exactCheck(payload, decoded); const message = foldLeftRight(checked); diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.ts index 4332440e6620d..89d12bff729b3 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/filters/response_schema.ts @@ -8,8 +8,8 @@ import * as t from 'io-ts'; import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; -export type RulesInfoResponse = t.TypeOf; -export const RulesInfoResponse = t.exact( +export type RuleManagementFiltersResponse = t.TypeOf; +export const RuleManagementFiltersResponse = t.exact( t.type({ rules_summary: t.type({ custom_count: PositiveInteger, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index 64b71b158d081..9e4f22484a00d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -11,7 +11,7 @@ import type { ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import type { RulesInfoResponse } from '../../../../common/detection_engine/rule_management/api/rules/filters/response_schema'; +import type { RuleManagementFiltersResponse } from '../../../../common/detection_engine/rule_management/api/rules/filters/response_schema'; import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../common/detection_engine/rule_management/api/urls'; import type { BulkActionsDryRunErrCode } from '../../../../common/constants'; import { @@ -399,8 +399,8 @@ export const fetchRuleManagementFilters = async ({ signal, }: { signal?: AbortSignal; -}): Promise => - KibanaServices.get().http.fetch(RULE_MANAGEMENT_FILTERS_URL, { +}): Promise => + KibanaServices.get().http.fetch(RULE_MANAGEMENT_FILTERS_URL, { method: 'GET', signal, }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts index 9b20c212bb53e..2647dfae6934e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts @@ -27,7 +27,7 @@ export const useBulkActionMutation = ( ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); - const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateFetchPrebuiltRulesStatusQuery = useInvalidateFetchPrebuiltRulesStatusQuery(); const updateRulesCache = useUpdateRulesCache(); @@ -66,12 +66,12 @@ export const useBulkActionMutation = ( case BulkActionType.delete: invalidateFindRulesQuery(); invalidateFetchRuleByIdQuery(); - invalidateFetchRulesInfo(); + invalidateFetchRuleManagementFilters(); invalidateFetchPrebuiltRulesStatusQuery(); break; case BulkActionType.duplicate: invalidateFindRulesQuery(); - invalidateFetchRulesInfo(); + invalidateFetchRuleManagementFilters(); break; case BulkActionType.edit: if (updatedRules) { @@ -82,7 +82,7 @@ export const useBulkActionMutation = ( invalidateFindRulesQuery(); } invalidateFetchRuleByIdQuery(); - invalidateFetchRulesInfo(); + invalidateFetchRuleManagementFilters(); break; } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts index 6dc10d7e3091a..41bce8f0cc154 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_prebuilt_rules_mutation.ts @@ -20,7 +20,7 @@ export const useCreatePrebuiltRulesMutation = ( ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidatePrePackagedRulesStatus = useInvalidateFetchPrebuiltRulesStatusQuery(); - const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); return useMutation(() => createPrepackagedRules(), { ...options, @@ -30,7 +30,7 @@ export const useCreatePrebuiltRulesMutation = ( // the number of rules might change after the installation invalidatePrePackagedRulesStatus(); invalidateFindRulesQuery(); - invalidateFetchRulesInfo(); + invalidateFetchRuleManagementFilters(); if (options?.onSettled) { options.onSettled(...args); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts index 2d32e6a521a5f..6d17505cdac29 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_create_rule_mutation.ts @@ -22,7 +22,7 @@ export const useCreateRuleMutation = ( options?: UseMutationOptions ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); return useMutation( (rule: RuleCreateProps) => createRule({ rule: transformOutput(rule) }), @@ -31,7 +31,7 @@ export const useCreateRuleMutation = ( mutationKey: CREATE_RULE_MUTATION_KEY, onSettled: (...args) => { invalidateFindRulesQuery(); - invalidateFetchRulesInfo(); + invalidateFetchRuleManagementFilters(); if (options?.onSettled) { options.onSettled(...args); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts index 7992c7fc27d47..32b2a206970a3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_management_filters_query.ts @@ -7,7 +7,7 @@ import { useCallback } from 'react'; import type { UseQueryOptions } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query'; -import type { RulesInfoResponse } from '../../../../../common/detection_engine/rule_management/api/rules/filters/response_schema'; +import type { RuleManagementFiltersResponse } from '../../../../../common/detection_engine/rule_management/api/rules/filters/response_schema'; import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../common/detection_engine/rule_management/api/urls'; import { fetchRuleManagementFilters } from '../api'; import { DEFAULT_QUERY_OPTIONS } from './constants'; @@ -15,9 +15,9 @@ import { DEFAULT_QUERY_OPTIONS } from './constants'; export const RULE_MANAGEMENT_FILTERS_QUERY_KEY = ['GET', RULE_MANAGEMENT_FILTERS_URL]; export const useFetchRuleManagementFiltersQuery = ( - options?: UseQueryOptions + options?: UseQueryOptions ) => { - return useQuery( + return useQuery( RULE_MANAGEMENT_FILTERS_QUERY_KEY, async ({ signal }) => { const response = await fetchRuleManagementFilters({ signal }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts index 6f3033e5e2a43..21d0c78f49b41 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts @@ -23,7 +23,7 @@ export const useUpdateRuleMutation = ( options?: UseMutationOptions ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateFetchRuleByIdQuery = useInvalidateFetchRuleByIdQuery(); return useMutation( @@ -34,7 +34,7 @@ export const useUpdateRuleMutation = ( onSettled: (...args) => { invalidateFindRulesQuery(); invalidateFetchRuleByIdQuery(); - invalidateFetchRulesInfo(); + invalidateFetchRuleManagementFilters(); if (options?.onSettled) { options.onSettled(...args); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx index db98382403c6f..f02075809a46d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx @@ -48,11 +48,11 @@ const RulesPageComponent: React.FC = () => { const [isValueListFlyoutVisible, showValueListFlyout, hideValueListFlyout] = useBoolState(); const { navigateToApp } = useKibana().services.application; const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchRulesInfo = useInvalidateFetchRuleManagementFiltersQuery(); + const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateRules = useCallback(() => { invalidateFindRulesQuery(); - invalidateFetchRulesInfo(); - }, [invalidateFindRulesQuery, invalidateFetchRulesInfo]); + invalidateFetchRuleManagementFilters(); + }, [invalidateFindRulesQuery, invalidateFetchRuleManagementFilters]); const [ { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 2d29058072abe..8239108728304 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -191,7 +191,7 @@ export const getPrepackagedRulesStatusRequest = () => path: PREBUILT_RULES_STATUS_URL, }); -export const getRulesInfoRequest = () => +export const getRuleManagementFiltersRequest = () => requestMock.create({ method: 'get', path: RULE_MANAGEMENT_FILTERS_URL, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.test.ts index 4d54abd8eb37b..969c8c1480df6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.test.ts @@ -10,7 +10,7 @@ import { getRuleManagementFilters } from './route'; import { getEmptyFindResult, getFindResultWithSingleHit, - getRulesInfoRequest, + getRuleManagementFiltersRequest, } from '../../../../routes/__mocks__/request_responses'; import { requestContextMock, serverMock } from '../../../../routes/__mocks__'; @@ -31,7 +31,7 @@ describe('Rule management filters route', () => { describe('status codes', () => { test('returns 200', async () => { const response = await server.inject( - getRulesInfoRequest(), + getRuleManagementFiltersRequest(), requestContextMock.convertContext(context) ); expect(response.status).toEqual(200); @@ -42,7 +42,7 @@ describe('Rule management filters route', () => { throw new Error('Test error'); }); const response = await server.inject( - getRulesInfoRequest(), + getRuleManagementFiltersRequest(), requestContextMock.convertContext(context) ); expect(response.status).toEqual(500); @@ -61,7 +61,7 @@ describe('Rule management filters route', () => { ruleLastRunOutcome: {}, ruleTags: ['a', 'b', 'c'], }); - const request = getRulesInfoRequest(); + const request = getRuleManagementFiltersRequest(); const response = await server.inject(request, requestContextMock.convertContext(context)); expect(response.status).toEqual(200); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts index ecc58723151ad..aa9c332c0e231 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts @@ -8,7 +8,7 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { validate } from '@kbn/securitysolution-io-ts-utils'; import type { RulesClient } from '@kbn/alerting-plugin/server'; -import { RulesInfoResponse } from '../../../../../../../common/detection_engine/rule_management/api/rules/filters/response_schema'; +import { RuleManagementFiltersResponse } from '../../../../../../../common/detection_engine/rule_management/api/rules/filters/response_schema'; import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../../../../common/detection_engine/rule_management/api/urls'; import { buildSiemResponse } from '../../../../routes/utils'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; @@ -65,7 +65,7 @@ export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) = try { const [{ prebuilt: prebuiltRulesCount, custom: customRulesCount }, tags] = await Promise.all([fetchRulesCount(rulesClient), readTags({ rulesClient })]); - const responseBody: RulesInfoResponse = { + const responseBody: RuleManagementFiltersResponse = { rules_summary: { custom_count: customRulesCount, prebuilt_installed_count: prebuiltRulesCount, @@ -74,7 +74,10 @@ export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) = tags, }, }; - const [validatedBody, validationError] = validate(responseBody, RulesInfoResponse); + const [validatedBody, validationError] = validate( + responseBody, + RuleManagementFiltersResponse + ); if (validationError != null) { return siemResponse.error({ statusCode: 500, body: validationError }); From 4f8d0ef1b1b445d92f963b311a3cc7b794ebfb4b Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Thu, 8 Dec 2022 11:17:51 +0100 Subject: [PATCH 30/35] removed unused core context --- .../detection_engine/rule_management/api/rules/filters/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts index aa9c332c0e231..d7d974aa8d9ef 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts @@ -59,7 +59,7 @@ export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) = }, async (context, _, response) => { const siemResponse = buildSiemResponse(response); - const ctx = await context.resolve(['core', 'alerting']); + const ctx = await context.resolve(['alerting']); const rulesClient = ctx.alerting.getRulesClient(); try { From 6022760cd21118c97628702f4d106d8ccecbe801 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Thu, 8 Dec 2022 11:32:58 +0100 Subject: [PATCH 31/35] add max tags limit --- .../alerting/server/rules_client/methods/aggregate.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/alerting/server/rules_client/methods/aggregate.ts b/x-pack/plugins/alerting/server/rules_client/methods/aggregate.ts index 79a07b3ebad49..2c9b991618aa1 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/aggregate.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/aggregate.ts @@ -22,6 +22,7 @@ export interface AggregateOptions extends IndexType { id: string; }; filter?: string | KueryNode; + maxTags?: number; } interface IndexType { @@ -79,7 +80,9 @@ export interface RuleAggregation { export async function aggregate( context: RulesClientContext, - { options: { fields, filter, ...options } = {} }: { options?: AggregateOptions } = {} + { + options: { fields, filter, maxTags = 50, ...options } = {}, + }: { options?: AggregateOptions } = {} ): Promise { let authorizationTuple; try { @@ -123,7 +126,7 @@ export async function aggregate( terms: { field: 'alert.attributes.muteAll' }, }, tags: { - terms: { field: 'alert.attributes.tags', order: { _key: 'asc' }, size: 50 }, + terms: { field: 'alert.attributes.tags', order: { _key: 'asc' }, size: maxTags }, }, snoozed: { nested: { From 665ee5e8eaa92e8c3199866ddf1fc49bb8adedaa Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sat, 17 Dec 2022 09:15:07 +0100 Subject: [PATCH 32/35] fetch only security rule tags --- .../rule_management/api/tags/read_tags/read_tags.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts index 4ee3f49980cdb..1453bb4796246 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/read_tags.ts @@ -6,6 +6,7 @@ */ import type { RulesClient } from '@kbn/alerting-plugin/server'; +import { enrichFilterWithRuleTypeMapping } from '../../../logic/search/enrich_filter_with_rule_type_mappings'; // This is a contrived max limit on the number of tags. In fact it can exceed this number and will be truncated to the hardcoded number. const EXPECTED_MAX_TAGS = 65536; @@ -19,7 +20,7 @@ export const readTags = async ({ const res = await rulesClient.aggregate({ options: { fields: ['tags'], - filter: undefined, + filter: enrichFilterWithRuleTypeMapping(undefined), maxTags: EXPECTED_MAX_TAGS, }, }); From 8f6f904aa049e65ad2655d226c83641ede691ec7 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sat, 17 Dec 2022 09:16:29 +0100 Subject: [PATCH 33/35] add tags number limit unit tests --- .../spaces_only/tests/alerting/aggregate.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts index ff24b25d89fa2..1633d99a3ff7f 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts @@ -137,6 +137,35 @@ export default function createAggregateTests({ getService }: FtrProviderContext) }); }); + describe('tags limit', () => { + it('should be 50 be default', async () => { + const numOfAlerts = 3; + const numOfTagsPerAlert = 30; + + await Promise.all( + [...Array(numOfAlerts)].map(async (_, alertIndex) => { + const okAlertId = await createTestAlert( + { + rule_type_id: 'test.noop', + schedule: { interval: '1s' }, + tags: [...Array(numOfTagsPerAlert)].map( + (_, i) => `tag-${i + numOfTagsPerAlert * alertIndex}` + ), + }, + 'ok' + ); + objectRemover.add(Spaces.space1.id, okAlertId, 'rule', 'alerting'); + }) + ); + + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_aggregate` + ); + + expect(response.body.rule_tags.length).to.eql(50); + }); + }); + describe('legacy', () => { it('should aggregate alert status totals', async () => { const NumOkAlerts = 4; From 9755803f8d568a4536921333eaf925f28171d9ec Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sat, 17 Dec 2022 09:16:47 +0100 Subject: [PATCH 34/35] add a functional test on the tags limit --- .../rules_client/tests/aggregate.test.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/x-pack/plugins/alerting/server/rules_client/tests/aggregate.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/aggregate.test.ts index 937c027ed04ce..7a9e7db434818 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/aggregate.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/aggregate.test.ts @@ -310,4 +310,38 @@ describe('aggregate()', () => { }) ); }); + + describe('tags number limit', () => { + test('sets to default (50) if it is not provided', async () => { + const rulesClient = new RulesClient(rulesClientParams); + + await rulesClient.aggregate(); + + expect(unsecuredSavedObjectsClient.find.mock.calls[0]).toMatchObject([ + { + aggs: { + tags: { + terms: { size: 50 }, + }, + }, + }, + ]); + }); + + test('sets to the provided value', async () => { + const rulesClient = new RulesClient(rulesClientParams); + + await rulesClient.aggregate({ options: { maxTags: 1000 } }); + + expect(unsecuredSavedObjectsClient.find.mock.calls[0]).toMatchObject([ + { + aggs: { + tags: { + terms: { size: 1000 }, + }, + }, + }, + ]); + }); + }); }); From f1533699a7f8fc3a109ff1b1c5ab67dfe8d476f1 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Sat, 17 Dec 2022 10:16:06 +0100 Subject: [PATCH 35/35] fix linting errors --- .../spaces_only/tests/alerting/aggregate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts index 1633d99a3ff7f..602bf75a7ef2b 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/aggregate.ts @@ -149,7 +149,7 @@ export default function createAggregateTests({ getService }: FtrProviderContext) rule_type_id: 'test.noop', schedule: { interval: '1s' }, tags: [...Array(numOfTagsPerAlert)].map( - (_, i) => `tag-${i + numOfTagsPerAlert * alertIndex}` + (__, i) => `tag-${i + numOfTagsPerAlert * alertIndex}` ), }, 'ok'