diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.test.ts b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.test.ts index e8019659d49c6..9eb4acbdb6164 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.test.ts +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.test.ts @@ -501,10 +501,8 @@ describe('Detections Rules API', () => { test('check parameter url, query', async () => { await getRuleStatusById({ id: 'mySuperRuleId', signal: abortCtrl.signal }); expect(fetchMock).toHaveBeenCalledWith('/api/detection_engine/rules/_find_statuses', { - query: { - ids: '["mySuperRuleId"]', - }, - method: 'GET', + body: '{"ids":["mySuperRuleId"]}', + method: 'POST', signal: abortCtrl.signal, }); }); diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.ts b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.ts index 2dd6955581eff..5cc73e17662c6 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.ts +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/api.ts @@ -266,8 +266,8 @@ export const getRuleStatusById = async ({ signal: AbortSignal; }): Promise => KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_STATUS_URL, { - method: 'GET', - query: { ids: JSON.stringify([id]) }, + method: 'POST', + body: JSON.stringify({ ids: [id] }), signal, }); @@ -289,8 +289,8 @@ export const getRulesStatusByIds = async ({ const res = await KibanaServices.get().http.fetch( DETECTION_ENGINE_RULES_STATUS_URL, { - method: 'GET', - query: { ids: JSON.stringify(ids) }, + method: 'POST', + body: JSON.stringify({ ids }), signal, } ); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index e400360a5a5b2..94097df48949f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -254,9 +254,9 @@ export const getFindResultWithMultiHits = ({ export const ruleStatusRequest = () => requestMock.create({ - method: 'get', + method: 'post', path: `${DETECTION_ENGINE_RULES_URL}/_find_statuses`, - query: { ids: ['someId'] }, + body: { ids: ['someId'] }, }); export const getImportRulesRequest = (hapiStream?: HapiReadableStream) => diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts index 89c9f34027120..d7c6d317227fa 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts @@ -60,9 +60,9 @@ describe('find_statuses', () => { describe('request validation', () => { test('disallows singular id query param', async () => { const request = requestMock.create({ - method: 'get', + method: 'post', path: `${DETECTION_ENGINE_RULES_URL}/_find_statuses`, - query: { id: ['someId'] }, + body: { id: ['someId'] }, }); const result = server.validate(request); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts index 6fee4d71a904e..8eed146537718 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts @@ -22,18 +22,18 @@ import { } from '../utils'; export const findRulesStatusesRoute = (router: IRouter) => { - router.get( + router.post( { path: `${DETECTION_ENGINE_RULES_URL}/_find_statuses`, validate: { - query: buildRouteValidation(findRulesStatusesSchema), + body: buildRouteValidation(findRulesStatusesSchema), }, options: { tags: ['access:siem'], }, }, async (context, request, response) => { - const { query } = request; + const { body } = request; const siemResponse = buildSiemResponse(response); const alertsClient = context.alerting?.getAlertsClient(); const savedObjectsClient = context.core.savedObjects.client; @@ -50,7 +50,7 @@ export const findRulesStatusesRoute = (router: IRouter) => { } */ try { - const statuses = await query.ids.reduce>( + const statuses = await body.ids.reduce>( async (acc, id) => { const lastFiveErrorsForId = await savedObjectsClient.find< IRuleSavedAttributesSavedObjectAttributes diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/find_rules_statuses_by_ids.sh b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/find_rules_statuses_by_ids.sh index 543c019067e8e..5ae4904e9e4ec 100755 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/find_rules_statuses_by_ids.sh +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/find_rules_statuses_by_ids.sh @@ -10,8 +10,12 @@ set -e ./check_env_variables.sh -# Example: ./find_rules_statuses_by_ids.sh '["12345","6789abc"]' +# Example: ./find_rules_statuses_by_ids.sh [\"12345\",\"6789abc\"] curl -g -k \ + -s \ + -H 'Content-Type: application/json' \ + -H 'kbn-xsrf: 123' \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X GET "${KIBANA_URL}${SPACE_URL}/api/detection_engine/rules/_find_statuses?ids=$1" \ + -X POST "${KIBANA_URL}${SPACE_URL}/api/detection_engine/rules/_find_statuses" \ + -d "{\"ids\": $1}" \ | jq . diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/find_statuses.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/find_statuses.ts new file mode 100644 index 0000000000000..45805f03f8c0c --- /dev/null +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/find_statuses.ts @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { DETECTION_ENGINE_RULES_URL } from '../../../../legacy/plugins/siem/common/constants'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { + createSignalsIndex, + deleteAllAlerts, + deleteSignalsIndex, + deleteAllRulesStatuses, + getSimpleRule, +} from './utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('legacyEs'); + + describe('find_statuses', () => { + beforeEach(async () => { + await createSignalsIndex(supertest); + }); + + afterEach(async () => { + await deleteSignalsIndex(supertest); + await deleteAllAlerts(es); + await deleteAllRulesStatuses(es); + }); + + it('should return an empty find statuses body correctly if no statuses are loaded', async () => { + const { body } = await supertest + .post(`${DETECTION_ENGINE_RULES_URL}/_find_statuses`) + .set('kbn-xsrf', 'true') + .send({ ids: [] }) + .expect(200); + + expect(body).to.eql({}); + }); + + it('should return a single rule status when a single rule is loaded from a find status with defaults added', async () => { + // add a single rule + const { body: resBody } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(getSimpleRule()) + .expect(200); + + await new Promise(resolve => setTimeout(resolve, 1000)).then(async () => { + // query the single rule from _find + const { body } = await supertest + .post(`${DETECTION_ENGINE_RULES_URL}/_find_statuses`) + .set('kbn-xsrf', 'true') + .send({ ids: [resBody.id] }) + .expect(200); + + // expected result for status should be 'going to run' or 'succeeded + expect(['succeeded', 'going to run']).to.contain(body[resBody.id].current_status.status); + }); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts index b8034fd92e988..917654e50cb99 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts @@ -18,6 +18,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./delete_rules_bulk')); loadTestFile(require.resolve('./export_rules')); loadTestFile(require.resolve('./find_rules')); + loadTestFile(require.resolve('./find_statuses')); loadTestFile(require.resolve('./get_prepackaged_rules_status')); loadTestFile(require.resolve('./import_rules')); loadTestFile(require.resolve('./read_rules')); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts index 7b725a7830c56..0a5b2def3eb18 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts @@ -196,6 +196,19 @@ export const deleteAllAlerts = async (es: any): Promise => { }); }; +/** + * Remove all rules statuses from the .kibana index + * @param es The ElasticSearch handle + */ +export const deleteAllRulesStatuses = async (es: any): Promise => { + await es.deleteByQuery({ + index: '.kibana', + q: 'type:siem-detection-engine-rule-status', + waitForCompletion: true, + refresh: 'wait_for', + }); +}; + /** * Creates the signals index for use inside of beforeEach blocks of tests * @param supertest The supertest client library