diff --git a/.eslintrc.js b/.eslintrc.js index 109be71acddcb..56fe621c99bb4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1013,6 +1013,7 @@ module.exports = { 'x-pack/plugins/ecs_data_quality_dashboard/common/**/*.{js,mjs,ts,tsx}', 'x-pack/plugins/elastic_assistant/common/**/*.{js,mjs,ts,tsx}', 'x-pack/packages/kbn-elastic-assistant/**/*.{js,mjs,ts,tsx}', + 'x-pack/packages/kbn-elastic-assistant-common/**/*.{js,mjs,ts,tsx}', 'x-pack/packages/security-solution/**/*.{js,mjs,ts,tsx}', 'x-pack/plugins/security_solution/public/**/*.{js,mjs,ts,tsx}', 'x-pack/plugins/security_solution_ess/public/**/*.{js,mjs,ts,tsx}', @@ -1046,6 +1047,7 @@ module.exports = { 'x-pack/plugins/ecs_data_quality_dashboard/**/*.{ts,tsx}', 'x-pack/plugins/elastic_assistant/**/*.{ts,tsx}', 'x-pack/packages/kbn-elastic-assistant/**/*.{ts,tsx}', + 'x-pack/packages/kbn-elastic-assistant-common/**/*.{ts,tsx}', 'x-pack/packages/security-solution/**/*.{ts,tsx}', 'x-pack/plugins/security_solution/**/*.{ts,tsx}', 'x-pack/plugins/security_solution_ess/**/*.{ts,tsx}', @@ -1057,6 +1059,7 @@ module.exports = { 'x-pack/plugins/ecs_data_quality_dashboard/**/*.{test,mock,test_helper}.{ts,tsx}', 'x-pack/plugins/elastic_assistant/**/*.{test,mock,test_helper}.{ts,tsx}', 'x-pack/packages/kbn-elastic-assistant/**/*.{test,mock,test_helper}.{ts,tsx}', + 'x-pack/packages/kbn-elastic-assistant-common/**/*.{test,mock,test_helper}.{ts,tsx}', 'x-pack/packages/security-solution/**/*.{test,mock,test_helper}.{ts,tsx}', 'x-pack/plugins/security_solution/**/*.{test,mock,test_helper}.{ts,tsx}', 'x-pack/plugins/security_solution_ess/**/*.{test,mock,test_helper}.{ts,tsx}', @@ -1074,6 +1077,7 @@ module.exports = { 'x-pack/plugins/ecs_data_quality_dashboard/**/*.{ts,tsx}', 'x-pack/plugins/elastic_assistant/**/*.{ts,tsx}', 'x-pack/packages/kbn-elastic-assistant/**/*.{ts,tsx}', + 'x-pack/packages/kbn-elastic-assistant-common/**/*.{ts,tsx}', 'x-pack/packages/security-solution/**/*.{ts,tsx}', 'x-pack/plugins/security_solution/**/*.{ts,tsx}', 'x-pack/plugins/security_solution_ess/**/*.{ts,tsx}', @@ -1110,6 +1114,7 @@ module.exports = { 'x-pack/plugins/ecs_data_quality_dashboard/**/*.{js,mjs,ts,tsx}', 'x-pack/plugins/elastic_assistant/**/*.{js,mjs,ts,tsx}', 'x-pack/packages/kbn-elastic-assistant/**/*.{js,mjs,ts,tsx}', + 'x-pack/packages/kbn-elastic-assistant-common/**/*.{js,mjs,ts,tsx}', 'x-pack/packages/security-solution/**/*.{js,mjs,ts,tsx}', 'x-pack/plugins/security_solution/**/*.{js,mjs,ts,tsx}', 'x-pack/plugins/security_solution_ess/**/*.{js,mjs,ts,tsx}', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e1a7f24c96f90..31fecbc283765 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -354,6 +354,7 @@ x-pack/packages/security-solution/ecs_data_quality_dashboard @elastic/security-t x-pack/plugins/ecs_data_quality_dashboard @elastic/security-threat-hunting-investigations packages/kbn-elastic-agent-utils @elastic/obs-ux-logs-team x-pack/packages/kbn-elastic-assistant @elastic/security-solution +x-pack/packages/kbn-elastic-assistant-common @elastic/security-solution x-pack/plugins/elastic_assistant @elastic/security-solution test/plugin_functional/plugins/elasticsearch_client_plugin @elastic/kibana-core x-pack/test/plugin_api_integration/plugins/elasticsearch_client @elastic/kibana-core diff --git a/package.json b/package.json index be000b3b1967e..f91f9061ec9e2 100644 --- a/package.json +++ b/package.json @@ -399,6 +399,7 @@ "@kbn/ecs-data-quality-dashboard-plugin": "link:x-pack/plugins/ecs_data_quality_dashboard", "@kbn/elastic-agent-utils": "link:packages/kbn-elastic-agent-utils", "@kbn/elastic-assistant": "link:x-pack/packages/kbn-elastic-assistant", + "@kbn/elastic-assistant-common": "link:x-pack/packages/kbn-elastic-assistant-common", "@kbn/elastic-assistant-plugin": "link:x-pack/plugins/elastic_assistant", "@kbn/elasticsearch-client-plugin": "link:test/plugin_functional/plugins/elasticsearch_client_plugin", "@kbn/elasticsearch-client-xpack-plugin": "link:x-pack/test/plugin_api_integration/plugins/elasticsearch_client", diff --git a/tsconfig.base.json b/tsconfig.base.json index 9a6a7e7a868e0..5f25914be2352 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -702,6 +702,8 @@ "@kbn/elastic-agent-utils/*": ["packages/kbn-elastic-agent-utils/*"], "@kbn/elastic-assistant": ["x-pack/packages/kbn-elastic-assistant"], "@kbn/elastic-assistant/*": ["x-pack/packages/kbn-elastic-assistant/*"], + "@kbn/elastic-assistant-common": ["x-pack/packages/kbn-elastic-assistant-common"], + "@kbn/elastic-assistant-common/*": ["x-pack/packages/kbn-elastic-assistant-common/*"], "@kbn/elastic-assistant-plugin": ["x-pack/plugins/elastic_assistant"], "@kbn/elastic-assistant-plugin/*": ["x-pack/plugins/elastic_assistant/*"], "@kbn/elasticsearch-client-plugin": ["test/plugin_functional/plugins/elasticsearch_client_plugin"], diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 3a6b3bc95a812..3088e60b110f4 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -24,6 +24,7 @@ "xpack.discover": "plugins/discover_enhanced", "xpack.crossClusterReplication": "plugins/cross_cluster_replication", "xpack.elasticAssistant": "packages/kbn-elastic-assistant", + "xpack.elasticAssistantCommon": "packages/kbn-elastic-assistant-common", "xpack.ecsDataQualityDashboard": "plugins/ecs_data_quality_dashboard", "xpack.embeddableEnhanced": "plugins/embeddable_enhanced", "xpack.endpoint": "plugins/endpoint", diff --git a/x-pack/packages/kbn-elastic-assistant-common/README.md b/x-pack/packages/kbn-elastic-assistant-common/README.md new file mode 100644 index 0000000000000..b6b696561bf29 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/README.md @@ -0,0 +1,20 @@ +# @kbn/elastic-assistant-common + +This package provides common code consumed in both the browser, i.e. the +`packages/kbn-elastic-assistant` package, and on the server, i.e. the +`plugins/elastic_assistant` plugin. + +For example, the data anonymization functions exported by this package +are be used in both the browser, and on the server. + +## Maintainers + +Maintained by the Security Solution team + +## Running unit tests with code coverage + +To (interactively) run unit tests with code coverage, run the following command: + +```sh +cd $KIBANA_HOME && node scripts/jest --watch x-pack/packages/kbn-elastic-assistant-common --coverage +``` diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.test.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_data/index.test.ts similarity index 100% rename from x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.test.ts rename to x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_data/index.test.ts diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_data/index.ts similarity index 84% rename from x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.ts rename to x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_data/index.ts index a0ecd88234313..d70bc86ab303d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_data/index.ts @@ -5,8 +5,7 @@ * 2.0. */ -import type { SelectedPromptContext } from '../../assistant/prompt_context/types'; -import { isAllowed } from '../../data_anonymization_editor/helpers'; +import { isAllowed } from '../helpers'; import type { AnonymizedData, GetAnonymizedValues } from '../types'; export const getAnonymizedData = ({ @@ -17,8 +16,8 @@ export const getAnonymizedData = ({ getAnonymizedValues, rawData, }: { - allow: SelectedPromptContext['allow']; - allowReplacement: SelectedPromptContext['allowReplacement']; + allow: string[]; + allowReplacement: string[]; currentReplacements: Record | undefined; getAnonymizedValue: ({ currentReplacements, @@ -28,7 +27,7 @@ export const getAnonymizedData = ({ rawValue: string; }) => string; getAnonymizedValues: GetAnonymizedValues; - rawData: Record; + rawData: Record; }): AnonymizedData => Object.keys(rawData).reduce( (acc, field) => { diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_value/index.test.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_value/index.test.ts new file mode 100644 index 0000000000000..a3235c2c4012b --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_value/index.test.ts @@ -0,0 +1,45 @@ +/* + * 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 { invert } from 'lodash/fp'; + +import { getAnonymizedValue } from '.'; + +jest.mock('uuid', () => ({ + v4: () => 'test-uuid', +})); + +describe('getAnonymizedValue', () => { + beforeEach(() => jest.clearAllMocks()); + + it('returns a new UUID when currentReplacements is not provided', () => { + const currentReplacements = undefined; + const rawValue = 'test'; + + const result = getAnonymizedValue({ currentReplacements, rawValue }); + + expect(result).toBe('test-uuid'); + }); + + it('returns an existing anonymized value when currentReplacements contains an entry for it', () => { + const rawValue = 'test'; + const currentReplacements = { anonymized: 'test' }; + const rawValueToReplacement = invert(currentReplacements); + + const result = getAnonymizedValue({ currentReplacements, rawValue }); + expect(result).toBe(rawValueToReplacement[rawValue]); + }); + + it('returns a new UUID with currentReplacements if no existing match', () => { + const rawValue = 'test'; + const currentReplacements = { anonymized: 'other' }; + + const result = getAnonymizedValue({ currentReplacements, rawValue }); + + expect(result).toBe('test-uuid'); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_value/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_value/index.ts new file mode 100644 index 0000000000000..455e9700882fb --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_value/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { invert } from 'lodash/fp'; +import { v4 } from 'uuid'; + +export const getAnonymizedValue = ({ + currentReplacements, + rawValue, +}: { + currentReplacements: Record | undefined; + rawValue: string; +}): string => { + if (currentReplacements != null) { + const rawValueToReplacement: Record = invert(currentReplacements); + const existingReplacement: string | undefined = rawValueToReplacement[rawValue]; + + return existingReplacement != null ? existingReplacement : v4(); + } + + return v4(); +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.test.tsx b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_values/index.test.tsx similarity index 100% rename from x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.test.tsx rename to x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_values/index.test.tsx diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_values/index.ts similarity index 75% rename from x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.ts rename to x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_values/index.ts index db846f93bf112..f6ecf0725c801 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_values/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { isAllowed, isAnonymized } from '../../data_anonymization_editor/helpers'; +import { isAllowed, isAnonymized } from '../helpers'; import { AnonymizedValues, GetAnonymizedValues } from '../types'; export const getAnonymizedValues: GetAnonymizedValues = ({ @@ -20,19 +20,24 @@ export const getAnonymizedValues: GetAnonymizedValues = ({ return rawValues.reduce( (acc, rawValue) => { + const stringValue = `${rawValue}`; + if (isAllowed({ allowSet, field }) && isAnonymized({ allowReplacementSet, field })) { - const anonymizedValue = getAnonymizedValue({ currentReplacements, rawValue }); + const anonymizedValue = `${getAnonymizedValue({ + currentReplacements, + rawValue: stringValue, + })}`; return { anonymizedValues: [...acc.anonymizedValues, anonymizedValue], replacements: { ...acc.replacements, - [anonymizedValue]: rawValue, + [anonymizedValue]: stringValue, }, }; } else if (isAllowed({ allowSet, field })) { return { - anonymizedValues: [...acc.anonymizedValues, rawValue], // no anonymization for this value + anonymizedValues: [...acc.anonymizedValues, stringValue], // no anonymization for this value replacements: { ...acc.replacements, // no additional replacements }, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_csv_from_data/index.test.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_csv_from_data/index.test.ts similarity index 100% rename from x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_csv_from_data/index.test.ts rename to x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_csv_from_data/index.test.ts diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_csv_from_data/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_csv_from_data/index.ts similarity index 100% rename from x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_csv_from_data/index.ts rename to x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_csv_from_data/index.ts diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/helpers/index.test.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/helpers/index.test.ts new file mode 100644 index 0000000000000..4dc8925bfab4e --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/helpers/index.test.ts @@ -0,0 +1,97 @@ +/* + * 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 { isAllowed, isAnonymized, isDenied, getIsDataAnonymizable } from '.'; + +describe('helpers', () => { + beforeEach(() => jest.clearAllMocks()); + + describe('getIsDataAnonymizable', () => { + it('returns false for string data', () => { + const rawData = 'this will not be anonymized'; + + const result = getIsDataAnonymizable(rawData); + + expect(result).toBe(false); + }); + + it('returns true for key / values data', () => { + const rawData = { key: ['value1', 'value2'] }; + + const result = getIsDataAnonymizable(rawData); + + expect(result).toBe(true); + }); + }); + + describe('isAllowed', () => { + it('returns true when the field is present in the allowSet', () => { + const allowSet = new Set(['fieldName1', 'fieldName2', 'fieldName3']); + + expect(isAllowed({ allowSet, field: 'fieldName1' })).toBe(true); + }); + + it('returns false when the field is NOT present in the allowSet', () => { + const allowSet = new Set(['fieldName1', 'fieldName2', 'fieldName3']); + + expect(isAllowed({ allowSet, field: 'nonexistentField' })).toBe(false); + }); + }); + + describe('isDenied', () => { + it('returns true when the field is NOT in the allowSet', () => { + const allowSet = new Set(['field1', 'field2']); + const field = 'field3'; + + expect(isDenied({ allowSet, field })).toBe(true); + }); + + it('returns false when the field is in the allowSet', () => { + const allowSet = new Set(['field1', 'field2']); + const field = 'field1'; + + expect(isDenied({ allowSet, field })).toBe(false); + }); + + it('returns true for an empty allowSet', () => { + const allowSet = new Set(); + const field = 'field1'; + + expect(isDenied({ allowSet, field })).toBe(true); + }); + + it('returns false when the field is an empty string and allowSet contains the empty string', () => { + const allowSet = new Set(['', 'field1']); + const field = ''; + + expect(isDenied({ allowSet, field })).toBe(false); + }); + }); + + describe('isAnonymized', () => { + const allowReplacementSet = new Set(['user.name', 'host.name']); + + it('returns true when the field is in the allowReplacementSet', () => { + const field = 'user.name'; + + expect(isAnonymized({ allowReplacementSet, field })).toBe(true); + }); + + it('returns false when the field is NOT in the allowReplacementSet', () => { + const field = 'foozle'; + + expect(isAnonymized({ allowReplacementSet, field })).toBe(false); + }); + + it('returns false when allowReplacementSet is empty', () => { + const emptySet = new Set(); + const field = 'user.name'; + + expect(isAnonymized({ allowReplacementSet: emptySet, field })).toBe(false); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/helpers/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/helpers/index.ts new file mode 100644 index 0000000000000..410ef5fc8cc48 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/helpers/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const getIsDataAnonymizable = (rawData: string | Record): boolean => + typeof rawData !== 'string'; + +export const isAllowed = ({ allowSet, field }: { allowSet: Set; field: string }): boolean => + allowSet.has(field); + +export const isDenied = ({ allowSet, field }: { allowSet: Set; field: string }): boolean => + !allowSet.has(field); + +export const isAnonymized = ({ + allowReplacementSet, + field, +}: { + allowReplacementSet: Set; + field: string; +}): boolean => allowReplacementSet.has(field); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.test.tsx b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/transform_raw_data/index.test.tsx similarity index 81% rename from x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.test.tsx rename to x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/transform_raw_data/index.test.tsx index 48caf7ca226dc..fb8b1c5b42f6b 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/transform_raw_data/index.test.tsx @@ -5,13 +5,12 @@ * 2.0. */ -import { SelectedPromptContext } from '../../assistant/prompt_context/types'; import { mockGetAnonymizedValue } from '../../mock/get_anonymized_value'; import { transformRawData } from '.'; describe('transformRawData', () => { it('returns non-anonymized data when rawData is a string', () => { - const inputRawData: SelectedPromptContext = { + const inputRawData = { allow: ['field1'], allowReplacement: ['field1', 'field2'], promptContextId: 'abcd', @@ -19,17 +18,19 @@ describe('transformRawData', () => { }; const result = transformRawData({ + allow: inputRawData.allow, + allowReplacement: inputRawData.allowReplacement, currentReplacements: {}, getAnonymizedValue: mockGetAnonymizedValue, onNewReplacements: () => {}, - selectedPromptContext: inputRawData, + rawData: inputRawData.rawData, }); expect(result).toEqual('this will not be anonymized'); }); it('calls onNewReplacements with the expected replacements', () => { - const inputRawData: SelectedPromptContext = { + const inputRawData = { allow: ['field1'], allowReplacement: ['field1'], promptContextId: 'abcd', @@ -39,17 +40,19 @@ describe('transformRawData', () => { const onNewReplacements = jest.fn(); transformRawData({ + allow: inputRawData.allow, + allowReplacement: inputRawData.allowReplacement, currentReplacements: {}, getAnonymizedValue: mockGetAnonymizedValue, onNewReplacements, - selectedPromptContext: inputRawData, + rawData: inputRawData.rawData, }); expect(onNewReplacements).toHaveBeenCalledWith({ '1eulav': 'value1' }); }); it('returns the expected mix of anonymized and non-anonymized data as a CSV string', () => { - const inputRawData: SelectedPromptContext = { + const inputRawData = { allow: ['field1', 'field2'], allowReplacement: ['field1'], // only field 1 will be anonymized promptContextId: 'abcd', @@ -57,17 +60,19 @@ describe('transformRawData', () => { }; const result = transformRawData({ + allow: inputRawData.allow, + allowReplacement: inputRawData.allowReplacement, currentReplacements: {}, getAnonymizedValue: mockGetAnonymizedValue, onNewReplacements: () => {}, - selectedPromptContext: inputRawData, + rawData: inputRawData.rawData, }); expect(result).toEqual('field1,1eulav,2eulav\nfield2,value3,value4'); // only field 1 is anonymized }); it('omits fields that are not included in the `allow` list, even if they are members of `allowReplacement`', () => { - const inputRawData: SelectedPromptContext = { + const inputRawData = { allow: ['field1', 'field2'], // field3 is NOT allowed allowReplacement: ['field1', 'field3'], // field3 is requested to be anonymized promptContextId: 'abcd', @@ -79,10 +84,12 @@ describe('transformRawData', () => { }; const result = transformRawData({ + allow: inputRawData.allow, + allowReplacement: inputRawData.allowReplacement, currentReplacements: {}, getAnonymizedValue: mockGetAnonymizedValue, onNewReplacements: () => {}, - selectedPromptContext: inputRawData, + rawData: inputRawData.rawData, }); expect(result).toEqual('field1,1eulav,2eulav\nfield2,value3,value4'); // field 3 is not included diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.tsx b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/transform_raw_data/index.tsx similarity index 74% rename from x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.tsx rename to x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/transform_raw_data/index.tsx index c478b0ab39f68..f1fe5e9331344 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/transform_raw_data/index.tsx @@ -5,17 +5,20 @@ * 2.0. */ -import { SelectedPromptContext } from '../../assistant/prompt_context/types'; import { getAnonymizedData } from '../get_anonymized_data'; import { getAnonymizedValues } from '../get_anonymized_values'; import { getCsvFromData } from '../get_csv_from_data'; export const transformRawData = ({ + allow, + allowReplacement, currentReplacements, getAnonymizedValue, onNewReplacements, - selectedPromptContext, + rawData, }: { + allow: string[]; + allowReplacement: string[]; currentReplacements: Record | undefined; getAnonymizedValue: ({ currentReplacements, @@ -25,17 +28,17 @@ export const transformRawData = ({ rawValue: string; }) => string; onNewReplacements?: (replacements: Record) => void; - selectedPromptContext: SelectedPromptContext; + rawData: string | Record; }): string => { - if (typeof selectedPromptContext.rawData === 'string') { - return selectedPromptContext.rawData; + if (typeof rawData === 'string') { + return rawData; } const anonymizedData = getAnonymizedData({ - allow: selectedPromptContext.allow, - allowReplacement: selectedPromptContext.allowReplacement, + allow, + allowReplacement, currentReplacements, - rawData: selectedPromptContext.rawData, + rawData, getAnonymizedValue, getAnonymizedValues, }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/types.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/types.ts similarity index 96% rename from x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/types.ts rename to x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/types.ts index 59ca12414b640..cc3d9a8ab1ccf 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/types.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/types.ts @@ -40,5 +40,5 @@ export type GetAnonymizedValues = ({ currentReplacements: Record | undefined; rawValue: string; }) => string; - rawData: Record; + rawData: Record; }) => AnonymizedValues; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/mock/get_anonymized_value/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/mock/get_anonymized_value/index.ts new file mode 100644 index 0000000000000..1ec76a90d292b --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/mock/get_anonymized_value/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** This mock returns the reverse of `value` */ +export const mockGetAnonymizedValue = ({ + currentReplacements, + rawValue, +}: { + currentReplacements: Record | undefined; + rawValue: string; +}): string => rawValue.split('').reverse().join(''); diff --git a/x-pack/packages/kbn-elastic-assistant-common/index.ts b/x-pack/packages/kbn-elastic-assistant-common/index.ts new file mode 100644 index 0000000000000..f17e13a33af3d --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/index.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. + */ + +export { getAnonymizedValue } from './impl/data_anonymization/get_anonymized_value'; + +export { + getIsDataAnonymizable, + isAllowed, + isAnonymized, + isDenied, +} from './impl/data_anonymization/helpers'; + +export { transformRawData } from './impl/data_anonymization/transform_raw_data'; diff --git a/x-pack/packages/kbn-elastic-assistant-common/jest.config.js b/x-pack/packages/kbn-elastic-assistant-common/jest.config.js new file mode 100644 index 0000000000000..1da38998cc4d2 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/jest.config.js @@ -0,0 +1,23 @@ +/* + * 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. + */ + +module.exports = { + coverageDirectory: + '/target/kibana-coverage/jest/x-pack/packages/kbn_elastic_assistant_common_impl', + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/packages/kbn-elastic-assistant-common/impl/**/*.{ts,tsx}', + '!/x-pack/packages/kbn-elastic-assistant-common/impl/{__test__,__snapshots__,__examples__,*mock*,tests,test_helpers,integration_tests,types}/**/*', + '!/x-pack/packages/kbn-elastic-assistant-common/impl/*mock*.{ts,tsx}', + '!/x-pack/packages/kbn-elastic-assistant-common/impl/*.test.{ts,tsx}', + '!/x-pack/packages/kbn-elastic-assistant-common/impl/*.d.ts', + '!/x-pack/packages/kbn-elastic-assistant-common/impl/*.config.ts', + ], + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/x-pack/packages/kbn-elastic-assistant-common'], +}; diff --git a/x-pack/packages/kbn-elastic-assistant-common/kibana.jsonc b/x-pack/packages/kbn-elastic-assistant-common/kibana.jsonc new file mode 100644 index 0000000000000..ac5d32f00c8d3 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "id": "@kbn/elastic-assistant-common", + "owner": "@elastic/security-solution", + "type": "shared-common" +} diff --git a/x-pack/packages/kbn-elastic-assistant-common/package.json b/x-pack/packages/kbn-elastic-assistant-common/package.json new file mode 100644 index 0000000000000..0f3f3f36814cc --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/elastic-assistant-common", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} \ No newline at end of file diff --git a/x-pack/packages/kbn-elastic-assistant-common/setup_tests.ts b/x-pack/packages/kbn-elastic-assistant-common/setup_tests.ts new file mode 100644 index 0000000000000..72e0edd0d07f7 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/setup_tests.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line import/no-extraneous-dependencies +import '@testing-library/jest-dom'; diff --git a/x-pack/packages/kbn-elastic-assistant-common/tsconfig.json b/x-pack/packages/kbn-elastic-assistant-common/tsconfig.json new file mode 100644 index 0000000000000..94b099694eaf4 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + ] +} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx new file mode 100644 index 0000000000000..beb2bd77d8512 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx @@ -0,0 +1,105 @@ +/* + * 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 { render, screen, fireEvent } from '@testing-library/react'; +import React from 'react'; + +import { AlertsSettings } from './alerts_settings'; +import { KnowledgeBaseConfig } from '../../assistant/types'; +import { DEFAULT_LATEST_ALERTS } from '../../assistant_context/constants'; + +describe('AlertsSettings', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('updates the knowledgeBase settings when the switch is toggled', () => { + const knowledgeBase: KnowledgeBaseConfig = { + alerts: false, + assistantLangChain: false, + latestAlerts: DEFAULT_LATEST_ALERTS, + }; + const setUpdatedKnowledgeBaseSettings = jest.fn(); + + render( + + ); + + const alertsSwitch = screen.getByTestId('alertsSwitch'); + fireEvent.click(alertsSwitch); + + expect(setUpdatedKnowledgeBaseSettings).toHaveBeenCalledWith({ + alerts: true, + assistantLangChain: false, + latestAlerts: DEFAULT_LATEST_ALERTS, + }); + }); + + it('updates the knowledgeBase settings when the alerts range slider is changed', () => { + const setUpdatedKnowledgeBaseSettings = jest.fn(); + const knowledgeBase: KnowledgeBaseConfig = { + alerts: true, + assistantLangChain: false, + latestAlerts: DEFAULT_LATEST_ALERTS, + }; + + render( + + ); + + const rangeSlider = screen.getByTestId('alertsRange'); + fireEvent.change(rangeSlider, { target: { value: '10' } }); + + expect(setUpdatedKnowledgeBaseSettings).toHaveBeenCalledWith({ + alerts: true, + assistantLangChain: false, + latestAlerts: 10, + }); + }); + + it('enables the alerts range slider when knowledgeBase.alerts is true', () => { + const setUpdatedKnowledgeBaseSettings = jest.fn(); + const knowledgeBase: KnowledgeBaseConfig = { + alerts: true, // <-- true + assistantLangChain: false, + latestAlerts: DEFAULT_LATEST_ALERTS, + }; + + render( + + ); + + expect(screen.getByTestId('alertsRange')).not.toBeDisabled(); + }); + + it('disables the alerts range slider when knowledgeBase.alerts is false', () => { + const setUpdatedKnowledgeBaseSettings = jest.fn(); + const knowledgeBase: KnowledgeBaseConfig = { + alerts: false, // <-- false + assistantLangChain: false, + latestAlerts: DEFAULT_LATEST_ALERTS, + }; + + render( + + ); + + expect(screen.getByTestId('alertsRange')).toBeDisabled(); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx new file mode 100644 index 0000000000000..2e0bf6504d289 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx @@ -0,0 +1,117 @@ +/* + * 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 { + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiRange, + EuiSpacer, + EuiSwitch, + EuiSwitchEvent, + EuiText, + useGeneratedHtmlId, +} from '@elastic/eui'; +import { css } from '@emotion/react'; +import React, { useCallback } from 'react'; + +import { KnowledgeBaseConfig } from '../../assistant/types'; +import * as i18n from '../../knowledge_base/translations'; + +export const MIN_LATEST_ALERTS = 10; +export const MAX_LATEST_ALERTS = 100; +export const TICK_INTERVAL = 10; +export const RANGE_CONTAINER_WIDTH = 300; // px +const LABEL_WRAPPER_MIN_WIDTH = 95; // px + +interface Props { + knowledgeBase: KnowledgeBaseConfig; + setUpdatedKnowledgeBaseSettings: React.Dispatch>; +} + +const AlertsSettingsComponent = ({ knowledgeBase, setUpdatedKnowledgeBaseSettings }: Props) => { + const inputRangeSliderId = useGeneratedHtmlId({ prefix: 'inputRangeSlider' }); + + const onEnableAlertsChange = useCallback( + (event: EuiSwitchEvent) => { + setUpdatedKnowledgeBaseSettings({ + ...knowledgeBase, + alerts: event.target.checked, + }); + }, + [knowledgeBase, setUpdatedKnowledgeBaseSettings] + ); + + return ( + <> + + + + + + + + + + {i18n.ASK_QUESTIONS_ABOUT} + + + + + + + setUpdatedKnowledgeBaseSettings({ + ...knowledgeBase, + latestAlerts: Number(e.currentTarget.value), + }) + } + showTicks + step={TICK_INTERVAL} + value={knowledgeBase.latestAlerts} + /> + + + + + + {i18n.LATEST_AND_RISKIEST_OPEN_ALERTS} + + + + + ); +}; + +export const AlertsSettings = React.memo(AlertsSettingsComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx index 882a0f1541404..a4dd40e4f1c4d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx @@ -35,11 +35,14 @@ const messages: Message[] = [ { content: 'This is a test', role: 'user', timestamp: new Date().toLocaleString() }, ]; const fetchConnectorArgs: FetchConnectorExecuteAction = { + alerts: false, + apiConfig, assistantLangChain: true, + assistantStreamingEnabled: true, http: mockHttp, messages, - apiConfig, - assistantStreamingEnabled: true, + onNewReplacements: jest.fn(), + ragOnAlerts: false, }; describe('API tests', () => { beforeEach(() => { @@ -81,6 +84,33 @@ describe('API tests', () => { ); }); + it('calls the actions connector with the expected optional request parameters', async () => { + const testProps: FetchConnectorExecuteAction = { + ...fetchConnectorArgs, + alerts: true, + alertsIndexPattern: '.alerts-security.alerts-default', + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 'c'], + ragOnAlerts: true, + replacements: { auuid: 'real.hostname' }, + size: 30, + }; + + await fetchConnectorExecuteAction(testProps); + + expect(mockHttp.fetch).toHaveBeenCalledWith( + '/internal/elastic_assistant/actions/connector/foo/_execute', + { + body: '{"params":{"subActionParams":{"model":"gpt-4","messages":[{"role":"user","content":"This is a test"}],"n":1,"stop":null,"temperature":0.2},"subAction":"invokeAI"},"assistantLangChain":true,"alertsIndexPattern":".alerts-security.alerts-default","allow":["a","b","c"],"allowReplacement":["b","c"],"replacements":{"auuid":"real.hostname"},"size":30}', + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + signal: undefined, + } + ); + }); + it('calls the actions connector api with invoke when assistantStreamingEnabled is false when assistantLangChain is false', async () => { const testProps: FetchConnectorExecuteAction = { ...fetchConnectorArgs, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx index 03da81643f836..9b1d3d74035fe 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx @@ -11,16 +11,28 @@ import { HttpSetup, IHttpFetchError } from '@kbn/core-http-browser'; import type { Conversation, Message } from '../assistant_context/types'; import { API_ERROR } from './translations'; import { MODEL_GPT_3_5_TURBO } from '../connectorland/models/model_selector/model_selector'; -import { getFormattedMessageContent } from './helpers'; +import { + getFormattedMessageContent, + getOptionalRequestParams, + hasParsableResponse, +} from './helpers'; import { PerformEvaluationParams } from './settings/evaluation_settings/use_perform_evaluation'; export interface FetchConnectorExecuteAction { + alerts: boolean; + alertsIndexPattern?: string; + allow?: string[]; + allowReplacement?: string[]; assistantLangChain: boolean; + assistantStreamingEnabled: boolean; apiConfig: Conversation['apiConfig']; http: HttpSetup; messages: Message[]; + onNewReplacements: (newReplacements: Record) => void; + ragOnAlerts: boolean; + replacements?: Record; signal?: AbortSignal | undefined; - assistantStreamingEnabled: boolean; + size?: number; } export interface FetchConnectorExecuteResponse { @@ -34,12 +46,20 @@ export interface FetchConnectorExecuteResponse { } export const fetchConnectorExecuteAction = async ({ + alerts, + alertsIndexPattern, + allow, + allowReplacement, assistantLangChain, + assistantStreamingEnabled, http, messages, + onNewReplacements, + ragOnAlerts, + replacements, apiConfig, signal, - assistantStreamingEnabled, + size, }: FetchConnectorExecuteAction): Promise => { const outboundMessages = messages.map((msg) => ({ role: msg.role, @@ -65,6 +85,16 @@ export const fetchConnectorExecuteAction = async ({ // In part 3 I will make enhancements to langchain to introduce streaming // Once implemented, invokeAI can be removed const isStream = assistantStreamingEnabled && !assistantLangChain; + const optionalRequestParams = getOptionalRequestParams({ + alerts, + alertsIndexPattern, + allow, + allowReplacement, + ragOnAlerts, + replacements, + size, + }); + const requestBody = isStream ? { params: { @@ -72,6 +102,7 @@ export const fetchConnectorExecuteAction = async ({ subAction: 'invokeStream', }, assistantLangChain, + ...optionalRequestParams, } : { params: { @@ -79,6 +110,7 @@ export const fetchConnectorExecuteAction = async ({ subAction: 'invokeAI', }, assistantLangChain, + ...optionalRequestParams, }; try { @@ -117,6 +149,7 @@ export const fetchConnectorExecuteAction = async ({ connector_id: string; status: string; data: string; + replacements?: Record; service_message?: string; trace_data?: { transaction_id: string; @@ -153,14 +186,24 @@ export const fetchConnectorExecuteAction = async ({ } : undefined; + onNewReplacements(response.replacements ?? {}); + return { - response: assistantLangChain ? getFormattedMessageContent(response.data) : response.data, + response: hasParsableResponse({ + alerts, + assistantLangChain, + ragOnAlerts, + }) + ? getFormattedMessageContent(response.data) + : response.data, isError: false, isStream: false, traceData, }; } catch (error) { - const reader = error?.response?.body?.getReader(); + const getReader = error?.response?.body?.getReader; + const reader = + isStream && typeof getReader === 'function' ? getReader.call(error.response.body) : null; if (!reader) { return { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.test.tsx index 8dfa8699048ac..da03b876813bc 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.test.tsx @@ -13,6 +13,7 @@ import { defaultSystemPrompt, mockSystemPrompt } from '../../mock/system_prompt' import { useChatSend, UseChatSendProps } from './use_chat_send'; import { renderHook } from '@testing-library/react-hooks'; import { waitFor } from '@testing-library/react'; +import { TestProviders } from '../../mock/test_providers/test_providers'; jest.mock('../use_send_messages'); jest.mock('../use_conversation'); @@ -61,7 +62,9 @@ describe('use chat send', () => { }); }); it('handleOnChatCleared clears the conversation', () => { - const { result } = renderHook(() => useChatSend(testProps)); + const { result } = renderHook(() => useChatSend(testProps), { + wrapper: TestProviders, + }); result.current.handleOnChatCleared(); expect(clearConversation).toHaveBeenCalled(); expect(setPromptTextPreview).toHaveBeenCalledWith(''); @@ -71,14 +74,18 @@ describe('use chat send', () => { expect(setEditingSystemPromptId).toHaveBeenCalledWith(defaultSystemPrompt.id); }); it('handlePromptChange updates prompt successfully', () => { - const { result } = renderHook(() => useChatSend(testProps)); + const { result } = renderHook(() => useChatSend(testProps), { + wrapper: TestProviders, + }); result.current.handlePromptChange('new prompt'); expect(setPromptTextPreview).toHaveBeenCalledWith('new prompt'); expect(setUserPrompt).toHaveBeenCalledWith('new prompt'); }); it('handleButtonSendMessage sends message with context prompt when a valid prompt text is provided', async () => { const promptText = 'prompt text'; - const { result } = renderHook(() => useChatSend(testProps)); + const { result } = renderHook(() => useChatSend(testProps), { + wrapper: TestProviders, + }); result.current.handleButtonSendMessage(promptText); expect(setUserPrompt).toHaveBeenCalledWith(''); @@ -96,8 +103,11 @@ describe('use chat send', () => { }); it('handleButtonSendMessage sends message with only provided prompt text and context already exists in convo history', async () => { const promptText = 'prompt text'; - const { result } = renderHook(() => - useChatSend({ ...testProps, currentConversation: welcomeConvo }) + const { result } = renderHook( + () => useChatSend({ ...testProps, currentConversation: welcomeConvo }), + { + wrapper: TestProviders, + } ); result.current.handleButtonSendMessage(promptText); @@ -109,8 +119,11 @@ describe('use chat send', () => { }); }); it('handleRegenerateResponse removes the last message of the conversation, resends the convo to GenAI, and appends the message received', async () => { - const { result } = renderHook(() => - useChatSend({ ...testProps, currentConversation: welcomeConvo }) + const { result } = renderHook( + () => useChatSend({ ...testProps, currentConversation: welcomeConvo }), + { + wrapper: TestProviders, + } ); result.current.handleRegenerateResponse(); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx index 83a2ad33e55fb..2c35ae9c495e4 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx @@ -55,7 +55,6 @@ export const useChatSend = ({ setUserPrompt, }: UseChatSendProps): UseChatSend => { const { isLoading, sendMessages } = useSendMessages(); - const { appendMessage, appendReplacements, clearConversation, removeLastMessage } = useConversation(); @@ -94,40 +93,57 @@ export const useChatSend = ({ setPromptTextPreview(''); const rawResponse = await sendMessages({ - http, apiConfig: currentConversation.apiConfig, + http, messages: updatedMessages, + onNewReplacements, + replacements: currentConversation.replacements ?? {}, }); + const responseMessage: Message = getMessageFromRawResponse(rawResponse); appendMessage({ conversationId: currentConversation.id, message: responseMessage }); }, [ allSystemPrompts, - currentConversation, - selectedPromptContexts, appendMessage, - setSelectedPromptContexts, - setPromptTextPreview, - sendMessages, - http, appendReplacements, + currentConversation.apiConfig, + currentConversation.id, + currentConversation.messages.length, + currentConversation.replacements, editingSystemPromptId, + http, + selectedPromptContexts, + sendMessages, + setPromptTextPreview, + setSelectedPromptContexts, ] ); const handleRegenerateResponse = useCallback(async () => { + const onNewReplacements = (newReplacements: Record) => + appendReplacements({ + conversationId: currentConversation.id, + replacements: newReplacements, + }); + const updatedMessages = removeLastMessage(currentConversation.id); + const rawResponse = await sendMessages({ - http, apiConfig: currentConversation.apiConfig, + http, messages: updatedMessages, + onNewReplacements, + replacements: currentConversation.replacements ?? {}, }); const responseMessage: Message = getMessageFromRawResponse(rawResponse); appendMessage({ conversationId: currentConversation.id, message: responseMessage }); }, [ appendMessage, + appendReplacements, currentConversation.apiConfig, currentConversation.id, + currentConversation.replacements, http, removeLastMessage, sendMessages, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts index f2b89a07c319e..0c3c5a579d274 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts @@ -9,6 +9,8 @@ import { getBlockBotConversation, getDefaultConnector, getFormattedMessageContent, + getOptionalRequestParams, + hasParsableResponse, } from './helpers'; import { enterpriseMessaging } from './use_conversation/sample_conversations'; import { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; @@ -231,4 +233,106 @@ describe('getBlockBotConversation', () => { expect(getFormattedMessageContent(content)).toBe(content); }); }); + + describe('getOptionalRequestParams', () => { + it('should return an empty object when ragOnAlerts is false', () => { + const params = { + alerts: true, + alertsIndexPattern: 'indexPattern', + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 'c'], + ragOnAlerts: false, // <-- false + replacements: { key: 'value' }, + size: 10, + }; + + const result = getOptionalRequestParams(params); + + expect(result).toEqual({}); + }); + + it('should return an empty object when alerts is false', () => { + const params = { + alerts: false, // <-- false + alertsIndexPattern: 'indexPattern', + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 'c'], + ragOnAlerts: true, + replacements: { key: 'value' }, + size: 10, + }; + + const result = getOptionalRequestParams(params); + + expect(result).toEqual({}); + }); + + it('should return the optional request params when ragOnAlerts is true and alerts is true', () => { + const params = { + alerts: true, + alertsIndexPattern: 'indexPattern', + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 'c'], + ragOnAlerts: true, + replacements: { key: 'value' }, + size: 10, + }; + + const result = getOptionalRequestParams(params); + + expect(result).toEqual({ + alertsIndexPattern: 'indexPattern', + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 'c'], + replacements: { key: 'value' }, + size: 10, + }); + }); + + it('should return (only) the optional request params that are defined when some optional params are not provided', () => { + const params = { + alerts: true, + ragOnAlerts: true, + allow: ['a', 'b', 'c'], // all the others are undefined + }; + + const result = getOptionalRequestParams(params); + + expect(result).toEqual({ + allow: ['a', 'b', 'c'], + }); + }); + }); + + describe('hasParsableResponse', () => { + it('returns true when assistantLangChain is true', () => { + const result = hasParsableResponse({ + alerts: false, + assistantLangChain: true, + ragOnAlerts: false, + }); + + expect(result).toBe(true); + }); + + it('returns true when ragOnAlerts is true and alerts is true', () => { + const result = hasParsableResponse({ + alerts: true, + assistantLangChain: false, + ragOnAlerts: true, + }); + + expect(result).toBe(true); + }); + + it('returns false when assistantLangChain, ragOnAlerts, and alerts are all false', () => { + const result = hasParsableResponse({ + alerts: false, + assistantLangChain: false, + ragOnAlerts: false, + }); + + expect(result).toBe(false); + }); + }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts index fa9617d00a6e1..688416d2e738c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts @@ -87,3 +87,60 @@ export const getFormattedMessageContent = (content: string): string => { return content; }; + +interface OptionalRequestParams { + alertsIndexPattern?: string; + allow?: string[]; + allowReplacement?: string[]; + replacements?: Record; + size?: number; +} + +export const getOptionalRequestParams = ({ + alerts, + alertsIndexPattern, + allow, + allowReplacement, + ragOnAlerts, + replacements, + size, +}: { + alerts: boolean; + alertsIndexPattern?: string; + allow?: string[]; + allowReplacement?: string[]; + ragOnAlerts: boolean; + replacements?: Record; + size?: number; +}): OptionalRequestParams => { + const optionalAlertsIndexPattern = alertsIndexPattern ? { alertsIndexPattern } : undefined; + const optionalAllow = allow ? { allow } : undefined; + const optionalAllowReplacement = allowReplacement ? { allowReplacement } : undefined; + const optionalReplacements = replacements ? { replacements } : undefined; + const optionalSize = size ? { size } : undefined; + + if ( + !ragOnAlerts || // the feature flag must be enabled + !alerts // the settings toggle must also be enabled + ) { + return {}; // don't send any optional params + } + + return { + ...optionalAlertsIndexPattern, + ...optionalAllow, + ...optionalAllowReplacement, + ...optionalReplacements, + ...optionalSize, + }; +}; + +export const hasParsableResponse = ({ + alerts, + assistantLangChain, + ragOnAlerts, +}: { + alerts: boolean; + assistantLangChain: boolean; + ragOnAlerts: boolean; +}): boolean => assistantLangChain || (ragOnAlerts && alerts); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.ts index cbf2259489505..26058e05ee697 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.ts @@ -5,10 +5,10 @@ * 2.0. */ +import { transformRawData } from '@kbn/elastic-assistant-common'; + import type { Message } from '../../assistant_context/types'; import { SYSTEM_PROMPT_CONTEXT_NON_I18N } from '../../content/prompts/system/translations'; - -import { transformRawData } from '../../data_anonymization/transform_raw_data'; import { getAnonymizedValue as defaultGetAnonymizedValue } from '../get_anonymized_value'; import type { SelectedPromptContext } from '../prompt_context/types'; import type { Prompt } from '../types'; @@ -60,10 +60,12 @@ export async function getCombinedMessage({ .sort() .map((id) => { const promptContext = transformRawData({ + allow: selectedPromptContexts[id].allow, + allowReplacement: selectedPromptContexts[id].allowReplacement, currentReplacements, getAnonymizedValue, onNewReplacements, - selectedPromptContext: selectedPromptContexts[id], + rawData: selectedPromptContexts[id].rawData, }); return `${SYSTEM_PROMPT_CONTEXT_NON_I18N(promptContext)}`; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_button.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_button.tsx index f559ae8aa76dd..fe7f2217f8c1d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_button.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_button.tsx @@ -7,8 +7,8 @@ import React, { useCallback } from 'react'; import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'; - import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/common/openai/constants'; + import { Conversation } from '../../..'; import { AssistantSettings, CONVERSATIONS_TAB } from './assistant_settings'; import * as i18n from './translations'; @@ -37,7 +37,7 @@ export const AssistantSettingsButton: React.FC = React.memo( selectedConversation, setSelectedConversationId, }) => { - const { setSelectedSettingsTab } = useAssistantContext(); + const { toasts, setSelectedSettingsTab } = useAssistantContext(); // Modal control functions const cleanupAndCloseModal = useCallback(() => { @@ -50,7 +50,11 @@ export const AssistantSettingsButton: React.FC = React.memo( const handleSave = useCallback(() => { cleanupAndCloseModal(); - }, [cleanupAndCloseModal]); + toasts?.addSuccess({ + iconType: 'check', + title: i18n.SETTINGS_UPDATED_TOAST_TITLE, + }); + }, [cleanupAndCloseModal, toasts]); const handleShowConversationSettings = useCallback(() => { setSelectedSettingsTab(CONVERSATIONS_TAB); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/translations.ts index 7842d900265a6..78d6f462fd3fe 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/translations.ts @@ -21,6 +21,13 @@ export const SETTINGS_TOOLTIP = i18n.translate( } ); +export const SETTINGS_UPDATED_TOAST_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.settingsUpdatedToastTitle', + { + defaultMessage: 'Settings updated', + } +); + export const CONVERSATIONS_MENU_ITEM = i18n.translate( 'xpack.elasticAssistant.assistant.settings.settingsConversationsMenuItemTitle', { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.test.tsx index 14037c4a954a2..975e5c8e27db7 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.test.tsx @@ -5,6 +5,8 @@ * 2.0. */ import { act, renderHook } from '@testing-library/react-hooks'; + +import { DEFAULT_LATEST_ALERTS } from '../../../assistant_context/constants'; import { alertConvo, customConvo, welcomeConvo } from '../../../mock/conversation'; import { useSettingsUpdater } from './use_settings_updater'; import { Prompt } from '../../../..'; @@ -56,7 +58,9 @@ const updatedValues = { defaultAllow: ['allow2'], defaultAllowReplacement: ['replacement2'], knowledgeBase: { + alerts: false, assistantLangChain: false, + latestAlerts: DEFAULT_LATEST_ALERTS, }, }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/types.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/types.ts index e9ffd8f8014e8..303aae0f6ff9c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/types.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/types.ts @@ -17,5 +17,7 @@ export interface Prompt { } export interface KnowledgeBaseConfig { + alerts: boolean; assistantLangChain: boolean; + latestAlerts: number; } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/helpers.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/helpers.test.ts new file mode 100644 index 0000000000000..39fcc86812e0c --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/helpers.test.ts @@ -0,0 +1,45 @@ +/* + * 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 { getOptionalRequestParams, OptionalRequestParams } from './helpers'; + +describe('getOptionalRequestParams', () => { + it('returns the correct optional request params', () => { + const params: OptionalRequestParams = { + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 'c'], + replacements: { key: 'value' }, + }; + + const result = getOptionalRequestParams(params); + + expect(result).toEqual({ + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 'c'], + replacements: { key: 'value' }, + }); + }); + + it('returns an empty object if no optional params are provided', () => { + const params = {}; + + const result = getOptionalRequestParams(params); + + expect(result).toEqual({}); + }); + + it('returns only the provided optional params', () => { + const params = { + allowReplacement: ['b', 'c'], + }; + + const result = getOptionalRequestParams(params); + + expect(result).toEqual({ + allowReplacement: ['b', 'c'], + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/helpers.ts new file mode 100644 index 0000000000000..60d4630703d50 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/helpers.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface OptionalRequestParams { + allow?: string[]; + allowReplacement?: string[]; + replacements?: Record; +} + +export const getOptionalRequestParams = ({ + allow, + allowReplacement, + replacements, +}: OptionalRequestParams): OptionalRequestParams => { + const optionalAllow = allow ? { allow } : {}; + const optionalAllowReplacement = allowReplacement ? { allowReplacement } : {}; + const optionalReplacements = replacements ? { replacements } : {}; + + return { + ...optionalAllow, + ...optionalAllowReplacement, + ...optionalReplacements, + }; +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/index.tsx index aa964e0230faa..fcfbadb574bbd 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/index.tsx @@ -5,18 +5,21 @@ * 2.0. */ -import { useCallback, useState } from 'react'; - import { HttpSetup } from '@kbn/core-http-browser'; +import { useCallback, useState } from 'react'; import { useAssistantContext } from '../../assistant_context'; import { Conversation, Message } from '../../assistant_context/types'; import { fetchConnectorExecuteAction, FetchConnectorExecuteResponse } from '../api'; interface SendMessagesProps { + allow?: string[]; + allowReplacement?: string[]; + apiConfig: Conversation['apiConfig']; http: HttpSetup; messages: Message[]; - apiConfig: Conversation['apiConfig']; + onNewReplacements: (newReplacements: Record) => void; + replacements?: Record; } interface UseSendMessages { @@ -29,25 +32,50 @@ interface UseSendMessages { } export const useSendMessages = (): UseSendMessages => { - const { assistantStreamingEnabled, knowledgeBase } = useAssistantContext(); + const { + alertsIndexPattern, + assistantStreamingEnabled, + defaultAllow, + defaultAllowReplacement, + ragOnAlerts, + knowledgeBase, + } = useAssistantContext(); const [isLoading, setIsLoading] = useState(false); const sendMessages = useCallback( - async ({ apiConfig, http, messages }: SendMessagesProps) => { + async ({ apiConfig, http, messages, onNewReplacements, replacements }: SendMessagesProps) => { setIsLoading(true); + try { return await fetchConnectorExecuteAction({ + alerts: knowledgeBase.alerts, // settings toggle + alertsIndexPattern, + allow: defaultAllow, + allowReplacement: defaultAllowReplacement, + apiConfig, assistantLangChain: knowledgeBase.assistantLangChain, + assistantStreamingEnabled, http, + ragOnAlerts, // feature flag + replacements, messages, - apiConfig, - assistantStreamingEnabled, + size: knowledgeBase.latestAlerts, + onNewReplacements, }); } finally { setIsLoading(false); } }, - [assistantStreamingEnabled, knowledgeBase.assistantLangChain] + [ + alertsIndexPattern, + assistantStreamingEnabled, + defaultAllow, + defaultAllowReplacement, + knowledgeBase.alerts, + knowledgeBase.assistantLangChain, + knowledgeBase.latestAlerts, + ragOnAlerts, + ] ); return { isLoading, sendMessages }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx index fbf1f68e05e0d..780a2a04a9728 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx @@ -13,6 +13,11 @@ export const SYSTEM_PROMPT_LOCAL_STORAGE_KEY = 'systemPrompts'; export const LAST_CONVERSATION_ID_LOCAL_STORAGE_KEY = 'lastConversationId'; export const KNOWLEDGE_BASE_LOCAL_STORAGE_KEY = 'knowledgeBase'; +/** The default `n` latest alerts, ordered by risk score, sent as context to the assistant */ +export const DEFAULT_LATEST_ALERTS = 20; + export const DEFAULT_KNOWLEDGE_BASE_SETTINGS: KnowledgeBaseConfig = { + alerts: false, assistantLangChain: false, + latestAlerts: DEFAULT_LATEST_ALERTS, }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx index e151e6fcaa418..4d0eec97f2639 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx @@ -9,7 +9,7 @@ import { EuiCommentProps } from '@elastic/eui'; import type { HttpSetup } from '@kbn/core-http-browser'; import { omit, uniq } from 'lodash/fp'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; - +import type { IToasts } from '@kbn/core-notifications-browser'; import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public'; import { useLocalStorage } from 'react-use'; import type { DocLinksStart } from '@kbn/core-doc-links-browser'; @@ -50,6 +50,7 @@ type ShowAssistantOverlay = ({ }: ShowAssistantOverlayProps) => void; export interface AssistantProviderProps { actionTypeRegistry: ActionTypeRegistryContract; + alertsIndexPattern?: string; assistantAvailability: AssistantAvailability; assistantStreamingEnabled?: boolean; assistantTelemetry?: AssistantTelemetry; @@ -87,14 +88,17 @@ export interface AssistantProviderProps { getInitialConversations: () => Record; modelEvaluatorEnabled?: boolean; nameSpace?: string; + ragOnAlerts?: boolean; setConversations: React.Dispatch>>; setDefaultAllow: React.Dispatch>; setDefaultAllowReplacement: React.Dispatch>; title?: string; + toasts?: IToasts; } export interface UseAssistantContext { actionTypeRegistry: ActionTypeRegistryContract; + alertsIndexPattern: string | undefined; assistantAvailability: AssistantAvailability; assistantStreamingEnabled: boolean; assistantTelemetry?: AssistantTelemetry; @@ -136,6 +140,7 @@ export interface UseAssistantContext { promptContexts: Record; modelEvaluatorEnabled: boolean; nameSpace: string; + ragOnAlerts: boolean; registerPromptContext: RegisterPromptContext; selectedSettingsTab: SettingsTabs; setAllQuickPrompts: React.Dispatch>; @@ -149,6 +154,7 @@ export interface UseAssistantContext { setShowAssistantOverlay: (showAssistantOverlay: ShowAssistantOverlay) => void; showAssistantOverlay: ShowAssistantOverlay; title: string; + toasts: IToasts | undefined; unRegisterPromptContext: UnRegisterPromptContext; } @@ -156,6 +162,7 @@ const AssistantContext = React.createContext(un export const AssistantProvider: React.FC = ({ actionTypeRegistry, + alertsIndexPattern, assistantAvailability, assistantStreamingEnabled = false, assistantTelemetry, @@ -175,10 +182,12 @@ export const AssistantProvider: React.FC = ({ getInitialConversations, modelEvaluatorEnabled = false, nameSpace = DEFAULT_ASSISTANT_NAMESPACE, + ragOnAlerts = false, setConversations, setDefaultAllow, setDefaultAllowReplacement, title = DEFAULT_ASSISTANT_TITLE, + toasts, }) => { /** * Local storage for all quick prompts, prefixed by assistant nameSpace @@ -286,6 +295,7 @@ export const AssistantProvider: React.FC = ({ const value = useMemo( () => ({ actionTypeRegistry, + alertsIndexPattern, assistantAvailability, assistantStreamingEnabled, assistantTelemetry, @@ -309,6 +319,7 @@ export const AssistantProvider: React.FC = ({ modelEvaluatorEnabled, promptContexts, nameSpace, + ragOnAlerts, registerPromptContext, selectedSettingsTab, setAllQuickPrompts: setLocalStorageQuickPrompts, @@ -321,12 +332,14 @@ export const AssistantProvider: React.FC = ({ setShowAssistantOverlay, showAssistantOverlay, title, + toasts, unRegisterPromptContext, localStorageLastConversationId, setLastConversationId: setLocalStorageLastConversationId, }), [ actionTypeRegistry, + alertsIndexPattern, assistantAvailability, assistantStreamingEnabled, assistantTelemetry, @@ -352,6 +365,7 @@ export const AssistantProvider: React.FC = ({ nameSpace, onConversationsUpdated, promptContexts, + ragOnAlerts, registerPromptContext, selectedSettingsTab, setDefaultAllow, @@ -360,9 +374,9 @@ export const AssistantProvider: React.FC = ({ setLocalStorageLastConversationId, setLocalStorageQuickPrompts, setLocalStorageSystemPrompts, - setSelectedSettingsTab, showAssistantOverlay, title, + toasts, unRegisterPromptContext, ] ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx index d4d2d1672b2ca..982b74faabf8d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx @@ -16,6 +16,7 @@ export interface MessagePresentation { export interface Message { role: ConversationRole; reader?: ReadableStreamDefaultReader; + replacements?: Record; content?: string; timestamp: string; isError?: boolean; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_rows/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_rows/index.ts index 279f75272372f..1582783f9c8f7 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_rows/index.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_rows/index.ts @@ -5,8 +5,9 @@ * 2.0. */ +import { isAllowed, isAnonymized, isDenied } from '@kbn/elastic-assistant-common'; + import { SelectedPromptContext } from '../../../assistant/prompt_context/types'; -import { isAllowed, isAnonymized, isDenied } from '../../helpers'; import { ContextEditorRow } from '../types'; export const getRows = ({ diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/get_stats/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/get_stats/index.ts index fbed27e5ac740..995ea09674bb7 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/get_stats/index.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/get_stats/index.ts @@ -5,8 +5,10 @@ * 2.0. */ +import { isAllowed, isAnonymized, isDenied } from '@kbn/elastic-assistant-common'; + import type { SelectedPromptContext } from '../../assistant/prompt_context/types'; -import { Stats, isAllowed, isAnonymized, isDenied } from '../helpers'; +import { Stats } from '../helpers'; export const getStats = ({ allow, allowReplacement, rawData }: SelectedPromptContext): Stats => { const ZERO_STATS = { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx index e2180c20a4da6..06c1b33bfda85 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx @@ -7,14 +7,41 @@ import React from 'react'; import { fireEvent, render } from '@testing-library/react'; + +import { DEFAULT_LATEST_ALERTS } from '../assistant_context/constants'; import { KnowledgeBaseSettings } from './knowledge_base_settings'; import { TestProviders } from '../mock/test_providers/test_providers'; import { useKnowledgeBaseStatus } from './use_knowledge_base_status'; +import { mockSystemPrompts } from '../mock/system_prompt'; + +const mockUseAssistantContext = { + allSystemPrompts: mockSystemPrompts, + conversations: {}, + http: { + basePath: { + prepend: jest.fn(), + }, + }, + ragOnAlerts: true, + setAllSystemPrompts: jest.fn(), + setConversations: jest.fn(), +}; + +jest.mock('../assistant_context', () => { + const original = jest.requireActual('../assistant_context'); + return { + ...original, + + useAssistantContext: jest.fn().mockImplementation(() => mockUseAssistantContext), + }; +}); const setUpdatedKnowledgeBaseSettings = jest.fn(); const defaultProps = { knowledgeBase: { assistantLangChain: true, + alerts: false, + latestAlerts: DEFAULT_LATEST_ALERTS, }, setUpdatedKnowledgeBaseSettings, }; @@ -99,7 +126,9 @@ describe('Knowledge base settings', () => { ); fireEvent.click(getByTestId('assistantLangChainSwitch')); expect(setUpdatedKnowledgeBaseSettings).toHaveBeenCalledWith({ + alerts: false, assistantLangChain: false, + latestAlerts: DEFAULT_LATEST_ALERTS, }); expect(mockSetup).not.toHaveBeenCalled(); @@ -111,6 +140,8 @@ describe('Knowledge base settings', () => { {...defaultProps} knowledgeBase={{ assistantLangChain: false, + alerts: false, + latestAlerts: DEFAULT_LATEST_ALERTS, }} /> @@ -118,6 +149,8 @@ describe('Knowledge base settings', () => { fireEvent.click(getByTestId('assistantLangChainSwitch')); expect(setUpdatedKnowledgeBaseSettings).toHaveBeenCalledWith({ assistantLangChain: true, + alerts: false, + latestAlerts: DEFAULT_LATEST_ALERTS, }); expect(mockSetup).toHaveBeenCalledWith('esql'); @@ -176,4 +209,14 @@ describe('Knowledge base settings', () => { ); expect(queryByTestId('knowledgeBaseActionButton')).not.toBeInTheDocument(); }); + + it('renders the alerts settings when ragOnAlerts is true', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('alertsSwitch')).toBeInTheDocument(); + }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx index e49602a52411a..bd41f5b888c93 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx @@ -23,17 +23,17 @@ import { EuiToolTip, EuiSwitch, } from '@elastic/eui'; - import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; -import * as i18n from './translations'; + +import { AlertsSettings } from '../alerts/settings/alerts_settings'; import { useAssistantContext } from '../assistant_context'; +import type { KnowledgeBaseConfig } from '../assistant/types'; +import * as i18n from './translations'; import { useDeleteKnowledgeBase } from './use_delete_knowledge_base'; import { useKnowledgeBaseStatus } from './use_knowledge_base_status'; import { useSetupKnowledgeBase } from './use_setup_knowledge_base'; -import type { KnowledgeBaseConfig } from '../assistant/types'; - const ESQL_RESOURCE = 'esql'; const KNOWLEDGE_BASE_INDEX_PATTERN = '.kibana-elastic-ai-assistant-kb'; @@ -47,7 +47,7 @@ interface Props { */ export const KnowledgeBaseSettings: React.FC = React.memo( ({ knowledgeBase, setUpdatedKnowledgeBaseSettings }) => { - const { http } = useAssistantContext(); + const { http, ragOnAlerts } = useAssistantContext(); const { data: kbStatus, isLoading, @@ -300,6 +300,15 @@ export const KnowledgeBaseSettings: React.FC = React.memo( + + + + {ragOnAlerts && ( + + )} ); } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts index 1aa295e311e68..3c7cdda10f924 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts @@ -7,6 +7,35 @@ import { i18n } from '@kbn/i18n'; +export const ALERTS_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.alertsLabel', + { + defaultMessage: 'Alerts', + } +); + +export const ASK_QUESTIONS_ABOUT = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.askQuestionsAboutLabel', + { + defaultMessage: 'Ask questions about the', + } +); + +export const LATEST_AND_RISKIEST_OPEN_ALERTS = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.latestAndRiskiestOpenAlertsLabel', + { + defaultMessage: + 'latest and riskiest open alerts in your environment. Your Anonymization settings will be applied to the alerts', + } +); + +export const ALERTS_RANGE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.alertsRangeSliderLabel', + { + defaultMessage: 'Alerts range', + } +); + export const SETTINGS_TITLE = i18n.translate( 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.settingsTitle', { diff --git a/x-pack/packages/kbn-elastic-assistant/tsconfig.json b/x-pack/packages/kbn-elastic-assistant/tsconfig.json index a4f71df75c834..eea97cfc917dc 100644 --- a/x-pack/packages/kbn-elastic-assistant/tsconfig.json +++ b/x-pack/packages/kbn-elastic-assistant/tsconfig.json @@ -16,6 +16,7 @@ "target/**/*" ], "kbn_references": [ + "@kbn/elastic-assistant-common", "@kbn/core-http-browser", "@kbn/i18n", "@kbn/stack-connectors-plugin", diff --git a/x-pack/plugins/elastic_assistant/server/__mocks__/alerts.ts b/x-pack/plugins/elastic_assistant/server/__mocks__/alerts.ts new file mode 100644 index 0000000000000..27ae22df0ab6f --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/__mocks__/alerts.ts @@ -0,0 +1,3210 @@ +/* + * 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. + */ + +/** + * Mock alerts in the JSON format returned by the `fields` API, with the + * following distribution of severity: + * + * 1x severity: 'low', + * 1x severity: 'medium' + * 2x severity: 'high', + * 1x severity: 'critical', + */ +export const mockAlertsFieldsApi = [ + { + _index: '.internal.alerts-security.alerts-default-000001', + _id: 'a54e079f8daafeaaf68ba52d522b5398da2afb53f973ced6c2b04d6cfb5d7205', + _score: 1, + fields: { + 'kibana.alert.severity': ['low'], + 'process.hash.md5': ['f1fcae8f-9b45-4892-b6c3-656640ad2342'], + 'host.os.full.text': ['Debian 10.12'], + 'kibana.alert.rule.updated_by': ['elastic'], + 'signal.ancestors.depth': [0], + 'event.category': ['process'], + 'host.os.name.text': ['Linux'], + 'process.parent.pid': [4323], + 'host.hostname': ['Host-81ln9xzp5s'], + 'kibana.alert.rule.tags': ['test'], + 'host.mac': ['9e-c7-bc-45-66-fc'], + 'kibana.alert.ancestors.depth': [0], + 'signal.rule.enabled': ['true'], + 'host.os.version': ['10.12'], + 'signal.rule.max_signals': [100], + 'kibana.alert.risk_score': [21], + 'signal.rule.updated_at': ['2023-10-27T16:34:23.296Z'], + 'event.agent_id_status': ['auth_metadata_missing'], + 'kibana.alert.original_event.id': ['79f24016-0ba8-48ef-8d85-b94bf54f5438'], + 'event.outcome': [''], + 'host.os.type': ['linux'], + 'process.Ext.ancestry': ['z9xm979x4m', 'igg6hj8x2n'], + 'kibana.alert.rule.interval': ['5m'], + 'kibana.alert.rule.type': ['query'], + 'signal.original_event.sequence': [16], + 'host.architecture': ['61ba1d520z'], + 'kibana.alert.start': ['2023-11-07T21:08:11.441Z'], + 'kibana.alert.rule.immutable': ['false'], + 'kibana.alert.original_event.type': ['end'], + 'agent.id': ['daa69c95-3301-461b-a70d-5a751b213a97'], + 'signal.rule.from': ['now-360s'], + 'process.group_leader.entity_id': ['si2hn9yj3q'], + 'kibana.alert.rule.enabled': ['true'], + 'kibana.alert.rule.version': ['2'], + 'kibana.alert.ancestors.type': ['event'], + 'process.session_leader.name.text': ['fake session'], + 'process.entry_leader.name': ['fake entry'], + 'signal.ancestors.index': ['.ds-logs-endpoint.events.process-default-2023.10.27-000001'], + 'user.name': ['wbtb966ixa'], + 'signal.original_event.outcome': [''], + 'process.working_directory': ['/home/wbtb966ixa/'], + 'process.entity_id': ['phi0pjn7ur'], + 'host.ip': ['10.18.144.54', '10.168.191.54', '10.7.54.83'], + 'agent.type': ['endpoint'], + 'process.executable.text': ['C:\\iexlorer.exe'], + 'signal.original_event.category': ['process'], + 'signal.original_event.id': ['79f24016-0ba8-48ef-8d85-b94bf54f5438'], + 'signal.rule.threat.framework': ['MITRE ATT&CK'], + 'user.domain': ['z2yjh930s6'], + 'host.id': ['e9c7c172-7749-48e7-8000-ac72ba8603aa'], + 'signal.original_event.type': ['end'], + 'kibana.alert.rule.max_signals': [100], + 'process.working_directory.text': ['/home/wbtb966ixa/'], + 'kibana.alert.rule.risk_score': [21], + 'process.code_signature.status': ['trusted'], + 'kibana.alert.rule.consumer': ['siem'], + 'process.group_leader.name.text': ['fake leader'], + 'kibana.alert.rule.indices': [ + 'apm-*-transaction*', + 'traces-apm*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + 'kibana.alert.rule.category': ['Custom Query Rule'], + 'host.os.Ext.variant': ['Debian'], + 'event.ingested': ['2023-10-27T16:55:40.000Z'], + '@timestamp': ['2023-11-07T21:08:11.421Z'], + 'signal.rule.updated_by': ['elastic'], + 'host.os.platform': ['debian'], + 'process.session_leader.entity_id': ['si2hn9yj3q'], + 'kibana.alert.rule.severity': ['low'], + 'kibana.alert.original_event.agent_id_status': ['auth_metadata_missing'], + 'data_stream.dataset': ['endpoint.events.process'], + 'kibana.alert.rule.execution.uuid': ['76a1af57-29fa-4129-b84b-4c89bc1de2c9'], + 'kibana.alert.uuid': ['a54e079f8daafeaaf68ba52d522b5398da2afb53f973ced6c2b04d6cfb5d7205'], + 'kibana.alert.rule.meta.kibana_siem_app_url': ['http://localhost:5601/app/security'], + 'kibana.version': ['8.12.0'], + 'event.id': ['79f24016-0ba8-48ef-8d85-b94bf54f5438'], + 'process.entry_leader.pid': [14], + 'signal.rule.license': [''], + 'signal.ancestors.type': ['event'], + 'kibana.alert.rule.rule_id': ['f544e86c-4d83-496f-9e5b-c60965b1eb83'], + 'user.name.text': ['wbtb966ixa'], + 'process.session_leader.pid': [569], + 'signal.rule.type': ['query'], + 'kibana.alert.ancestors.id': ['udsQcosBklDc-Wq0HnmB'], + 'process.name.text': ['iexlorer.exe'], + 'process.group_leader.name': ['fake leader'], + 'host.os.full': ['Debian 10.12'], + 'kibana.alert.rule.description': ['matches almost everything'], + 'process.pid': [3036], + 'kibana.alert.rule.producer': ['siem'], + 'kibana.alert.rule.to': ['now'], + 'signal.rule.created_by': ['elastic'], + 'signal.rule.interval': ['5m'], + 'kibana.alert.rule.created_by': ['elastic'], + 'kibana.alert.original_event.ingested': ['2023-10-27T16:55:40.000Z'], + 'signal.rule.id': ['af873d40-74e6-11ee-b0ed-29fb31c95fbe'], + 'process.code_signature.subject_name': ['Microsoft'], + 'process.parent.entity_id': ['z9xm979x4m'], + 'signal.reason': [ + 'process event with process iexlorer.exe, by wbtb966ixa on Host-81ln9xzp5s created low alert matches everything.', + ], + 'signal.rule.risk_score': [21], + 'host.os.name': ['Linux'], + 'kibana.alert.rule.name': ['matches everything'], + 'host.name': ['Host-81ln9xzp5s'], + 'signal.status': ['open'], + 'event.kind': ['signal'], + 'signal.rule.created_at': ['2023-10-27T16:34:23.296Z'], + 'signal.rule.tags': ['test'], + 'kibana.alert.workflow_status': ['open'], + 'kibana.alert.rule.threat.tactic.name': ['Reconnaissance'], + 'kibana.alert.rule.uuid': ['af873d40-74e6-11ee-b0ed-29fb31c95fbe'], + 'kibana.alert.original_event.category': ['process'], + 'kibana.alert.reason': [ + 'process event with process iexlorer.exe, by wbtb966ixa on Host-81ln9xzp5s created low alert matches everything.', + ], + 'signal.rule.threat.tactic.id': ['TA0043'], + 'data_stream.type': ['logs'], + 'signal.ancestors.id': ['udsQcosBklDc-Wq0HnmB'], + 'signal.original_time': ['2023-11-07T21:07:31.911Z'], + 'process.name': ['iexlorer.exe'], + 'ecs.version': ['1.4.0'], + 'signal.rule.severity': ['low'], + 'kibana.alert.ancestors.index': [ + '.ds-logs-endpoint.events.process-default-2023.10.27-000001', + ], + 'process.entry_leader.name.text': ['fake entry'], + 'agent.version': ['8.12.0'], + 'kibana.alert.depth': [1], + 'host.os.family': ['debian'], + 'kibana.alert.rule.from': ['now-360s'], + 'kibana.alert.rule.parameters': [ + { + description: 'matches almost everything', + risk_score: 21, + severity: 'low', + license: '', + meta: { + from: '1m', + kibana_siem_app_url: 'http://localhost:5601/app/security', + }, + author: [], + false_positives: [], + from: 'now-360s', + rule_id: 'f544e86c-4d83-496f-9e5b-c60965b1eb83', + max_signals: 100, + risk_score_mapping: [], + severity_mapping: [], + threat: [ + { + framework: 'MITRE ATT&CK', + tactic: { + id: 'TA0043', + name: 'Reconnaissance', + reference: 'https://attack.mitre.org/tactics/TA0043', + }, + technique: [], + }, + ], + to: 'now', + references: [], + version: 2, + exceptions_list: [], + immutable: false, + related_integrations: [], + required_fields: [], + setup: '', + type: 'query', + language: 'kuery', + index: [ + 'apm-*-transaction*', + 'traces-apm*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + query: '_id: *', + filters: [], + }, + ], + 'kibana.alert.rule.revision': [0], + 'kibana.alert.rule.threat.tactic.id': ['TA0043'], + 'signal.rule.version': ['2'], + 'signal.original_event.kind': ['event'], + 'kibana.alert.status': ['active'], + 'kibana.alert.last_detected': ['2023-11-07T21:08:11.441Z'], + 'signal.depth': [1], + 'signal.rule.immutable': ['false'], + 'process.group_leader.pid': [737], + 'event.sequence': [16], + 'kibana.alert.rule.rule_type_id': ['siem.queryRule'], + 'process.session_leader.name': ['fake session'], + 'signal.rule.name': ['matches everything'], + 'signal.rule.rule_id': ['f544e86c-4d83-496f-9e5b-c60965b1eb83'], + 'host.os.kernel': ['4.19.0-21-cloud-amd64 #1 SMP Debian 4.19.249-2 (2022-06-30)'], + 'signal.rule.threat.tactic.reference': ['https://attack.mitre.org/tactics/TA0043'], + 'kibana.alert.rule.license': [''], + 'kibana.alert.original_event.kind': ['event'], + 'process.executable': ['C:\\iexlorer.exe'], + 'process.entry_leader.start': ['1970-01-01T00:00:00.000Z'], + 'signal.rule.threat.tactic.name': ['Reconnaissance'], + 'kibana.alert.rule.threat.framework': ['MITRE ATT&CK'], + 'kibana.alert.rule.updated_at': ['2023-10-27T16:34:23.296Z'], + 'signal.rule.description': ['matches almost everything'], + 'data_stream.namespace': ['default'], + 'process.args': ['"C:\\iexlorer.exe"', '--pbr'], + 'kibana.alert.original_event.outcome': [''], + 'kibana.alert.original_event.sequence': [16], + 'kibana.alert.rule.threat.tactic.reference': ['https://attack.mitre.org/tactics/TA0043'], + 'kibana.alert.rule.created_at': ['2023-10-27T16:34:23.296Z'], + 'signal.rule.to': ['now'], + 'event.type': ['end'], + 'kibana.space_ids': ['default'], + 'process.entry_leader.entity_id': ['si2hn9yj3q'], + 'kibana.alert.rule.meta.from': ['1m'], + 'kibana.alert.original_time': ['2023-11-07T21:07:31.911Z'], + }, + }, + { + _index: '.internal.alerts-security.alerts-default-000001', + _id: '7a401ca5e5dac578d08ec0e929bf3c735446752f66c569cb0e910215f0a8b7e5', + _score: 1, + fields: { + 'process.hash.md5': ['fake md5'], + 'host.os.full.text': ['Windows 10'], + 'kibana.alert.rule.updated_by': ['elastic'], + 'host.os.name.text': ['Windows'], + 'kibana.alert.rule.rule_name_override': ['message'], + 'Endpoint.capabilities': [ + 'isolation', + 'kill_process', + 'suspend_process', + 'running_processes', + 'get_file', + 'execute', + 'upload_file', + ], + 'process.hash.sha256': ['fake sha256'], + 'host.hostname': ['Host-ffhve1li02'], + 'host.mac': ['15-42-cb-8d-d6-c8'], + 'elastic.agent.id': ['419413b4-cd07-41bf-9273-1c40a57d79b7'], + 'dll.hash.sha256': ['8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2'], + 'signal.rule.enabled': ['true'], + 'file.Ext.malware_classification.version': ['3.0.33'], + 'host.os.version': ['10.0'], + 'signal.rule.max_signals': [10000], + 'file.mtime': ['2023-11-07T17:53:34.919Z'], + 'kibana.alert.risk_score': [47], + 'signal.rule.updated_at': ['2023-10-27T16:33:43.125Z'], + 'Endpoint.policy.applied.id': ['00000000-0000-0000-0000-000000000000'], + 'kibana.alert.original_event.id': ['71471781-98f6-40ba-acc3-b38d5317b541'], + 'file.path.text': ['C:/fake_malware.exe'], + 'file.created': ['2023-11-07T17:53:34.919Z'], + 'signal.original_event.code': ['malicious_file'], + 'kibana.alert.original_event.module': ['endpoint'], + 'kibana.alert.rule.interval': ['5m'], + 'kibana.alert.rule.type': ['query'], + 'kibana.alert.rule.immutable': ['true'], + 'kibana.alert.rule.exceptions_list.list_id': ['endpoint_list'], + 'process.group_leader.entity_id': ['qkngtu1ty9'], + 'file.owner': ['SYSTEM'], + 'kibana.alert.rule.version': ['102'], + 'file.Ext.malware_classification.threshold': [0.66], + 'file.hash.md5': ['fake file md5'], + 'dll.Ext.malware_classification.score': [0], + 'file.Ext.malware_classification.identifier': ['endpointpe'], + 'process.entity_id': ['5hydsg0f85'], + 'host.ip': ['10.185.21.68', '10.198.36.199'], + 'agent.type': ['endpoint'], + 'process.executable.text': ['C:/malware.exe'], + 'signal.original_event.category': ['malware'], + 'Endpoint.policy.applied.name': ['Default'], + 'host.id': ['10f91578-370d-41b4-a806-fa80c591955f'], + 'process.Ext.code_signature.subject_name': ['bad signer'], + 'dll.Ext.malware_classification.identifier': ['Whitelisted'], + 'dll.Ext.mapped_address': [5362483200], + 'kibana.alert.rule.indices': ['logs-endpoint.alerts-*'], + 'host.os.Ext.variant': ['Windows Pro'], + 'signal.rule.updated_by': ['elastic'], + 'host.os.platform': ['Windows'], + 'process.session_leader.entity_id': ['qkngtu1ty9'], + 'kibana.alert.rule.severity': ['medium'], + 'kibana.version': ['8.12.0'], + 'event.id': ['71471781-98f6-40ba-acc3-b38d5317b541'], + 'process.entry_leader.pid': [510], + 'signal.ancestors.type': ['event'], + 'user.name.text': ['wxqb4pxvtg'], + 'kibana.alert.ancestors.id': ['UqsMqosB1rJhB-h4wsnG'], + 'process.name.text': ['malware writer'], + 'process.group_leader.name': ['fake leader'], + 'host.os.full': ['Windows 10'], + 'kibana.alert.original_event.code': ['malicious_file'], + 'kibana.alert.rule.description': [ + 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', + ], + 'kibana.alert.rule.producer': ['siem'], + 'kibana.alert.rule.to': ['now'], + 'kibana.alert.original_event.ingested': ['2023-11-07T13:50:44.000Z'], + 'signal.rule.id': ['97449b60-74e6-11ee-b0ed-29fb31c95fbe'], + 'signal.reason': [ + 'malware event with process malware writer, file fake_malware.exe, by wxqb4pxvtg on Host-ffhve1li02 created medium alert Endpoint Security.', + ], + 'signal.rule.risk_score': [47], + 'host.os.name': ['Windows'], + 'signal.status': ['open'], + 'kibana.alert.rule.severity_mapping.value': ['21', '47', '73', '99'], + 'signal.rule.tags': ['Data Source: Elastic Defend'], + 'kibana.alert.rule.uuid': ['97449b60-74e6-11ee-b0ed-29fb31c95fbe'], + 'kibana.alert.original_event.category': ['malware'], + 'process.name': ['malware writer'], + 'process.Ext.token.privileges.enabled': [false], + 'kibana.alert.ancestors.index': ['.ds-logs-endpoint.alerts-default-2023.10.27-000001'], + 'process.entry_leader.name.text': ['fake entry'], + 'dll.code_signature.trusted': [true], + 'process.Ext.code_signature.trusted': [false], + 'agent.version': ['8.12.0'], + 'kibana.alert.rule.risk_score_mapping.operator': ['equals'], + 'host.os.family': ['windows'], + 'kibana.alert.rule.from': ['now-10m'], + 'kibana.alert.rule.parameters': [ + { + description: + 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', + risk_score: 47, + severity: 'medium', + license: 'Elastic License v2', + rule_name_override: 'message', + timestamp_override: 'event.ingested', + author: ['Elastic'], + false_positives: [], + from: 'now-10m', + rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + max_signals: 10000, + risk_score_mapping: [ + { + field: 'event.risk_score', + operator: 'equals', + value: '', + }, + ], + severity_mapping: [ + { + field: 'event.severity', + operator: 'equals', + severity: 'low', + value: '21', + }, + { + field: 'event.severity', + operator: 'equals', + severity: 'medium', + value: '47', + }, + { + field: 'event.severity', + operator: 'equals', + severity: 'high', + value: '73', + }, + { + field: 'event.severity', + operator: 'equals', + severity: 'critical', + value: '99', + }, + ], + threat: [], + to: 'now', + references: [], + version: 102, + exceptions_list: [ + { + id: 'endpoint_list', + list_id: 'endpoint_list', + type: 'endpoint', + namespace_type: 'agnostic', + }, + ], + immutable: true, + related_integrations: [ + { + package: 'endpoint', + version: '^8.2.0', + }, + ], + required_fields: [ + { + name: 'event.kind', + type: 'keyword', + ecs: true, + }, + { + name: 'event.module', + type: 'keyword', + ecs: true, + }, + ], + setup: '', + type: 'query', + language: 'kuery', + index: ['logs-endpoint.alerts-*'], + query: 'event.kind:alert and event.module:(endpoint and not endgame)\n', + }, + ], + 'signal.original_event.kind': ['alert'], + 'file.Ext.quarantine_result': [true], + 'signal.depth': [1], + 'signal.rule.immutable': ['true'], + 'process.group_leader.pid': [317], + 'event.sequence': [23], + 'signal.rule.name': ['Endpoint Security'], + 'dll.hash.sha1': ['ca85243c0af6a6471bdaa560685c51eefd6dbc0d'], + 'event.module': ['endpoint'], + 'kibana.alert.rule.severity_mapping.operator': ['equals', 'equals', 'equals', 'equals'], + 'file.accessed': ['2023-11-07T17:53:34.919Z'], + 'process.Ext.token.type': ['tokenPrimary'], + 'kibana.alert.rule.license': ['Elastic License v2'], + 'kibana.alert.original_event.kind': ['alert'], + 'signal.rule.description': [ + 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', + ], + 'dll.Ext.mapped_size': [0], + 'kibana.alert.original_event.sequence': [23], + 'process.Ext.token.privileges.description': ['Replace a process level token'], + 'dll.path': ['C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe'], + 'process.Ext.user': ['SYSTEM'], + 'file.Ext.malware_classification.score': [1], + 'kibana.alert.rule.exceptions_list.namespace_type': ['agnostic'], + 'kibana.space_ids': ['default'], + 'kibana.alert.severity': ['medium'], + 'file.Ext.quarantine_message': ['fake quarantine message'], + 'signal.ancestors.depth': [0], + 'event.category': ['malware'], + 'process.parent.pid': [1], + 'kibana.alert.rule.tags': ['Data Source: Elastic Defend'], + 'kibana.alert.ancestors.depth': [0], + 'kibana.alert.rule.severity_mapping.severity': ['low', 'medium', 'high', 'critical'], + 'event.agent_id_status': ['auth_metadata_missing'], + 'kibana.alert.rule.risk_score_mapping.value': [''], + 'file.Ext.temp_file_path': ['C:/temp/fake_malware.exe'], + 'process.Ext.ancestry': ['yybc8cgr8a', 'xpr211xjvm'], + 'signal.original_event.sequence': [23], + 'Endpoint.state.isolation': [false], + 'host.architecture': ['sls014vbcb'], + 'kibana.alert.start': ['2023-11-07T13:54:29.175Z'], + 'event.code': ['malicious_file'], + 'kibana.alert.original_event.type': ['creation'], + 'agent.id': ['419413b4-cd07-41bf-9273-1c40a57d79b7'], + 'signal.original_event.module': ['endpoint'], + 'signal.rule.from': ['now-10m'], + 'kibana.alert.rule.exceptions_list.type': ['endpoint'], + 'process.Ext.token.domain': ['NT AUTHORITY'], + 'dll.Ext.malware_classification.version': ['3.0.0'], + 'kibana.alert.rule.enabled': ['true'], + 'kibana.alert.ancestors.type': ['event'], + 'process.session_leader.name.text': ['fake session'], + 'process.entry_leader.name': ['fake entry'], + 'dll.Ext.compile_time': [1534424710], + 'signal.ancestors.index': ['.ds-logs-endpoint.alerts-default-2023.10.27-000001'], + 'user.name': ['wxqb4pxvtg'], + 'signal.original_event.id': ['71471781-98f6-40ba-acc3-b38d5317b541'], + 'file.hash.sha256': ['fake file sha256'], + 'process.uptime': [0], + 'user.domain': ['lm02vqgxtl'], + 'process.Ext.token.integrity_level_name': ['system'], + 'signal.original_event.type': ['creation'], + 'kibana.alert.rule.max_signals': [10000], + 'signal.rule.author': ['Elastic'], + 'kibana.alert.rule.risk_score': [47], + 'file.name': ['fake_malware.exe'], + 'process.Ext.token.sid': ['S-1-5-18'], + 'signal.original_event.dataset': ['endpoint'], + 'kibana.alert.rule.consumer': ['siem'], + 'process.group_leader.name.text': ['fake leader'], + 'kibana.alert.rule.category': ['Custom Query Rule'], + 'event.action': ['rename'], + 'event.ingested': ['2023-11-07T13:50:44.000Z'], + '@timestamp': ['2023-11-07T13:54:29.164Z'], + 'kibana.alert.original_event.action': ['rename'], + 'kibana.alert.original_event.agent_id_status': ['auth_metadata_missing'], + 'Endpoint.status': ['enrolled'], + 'data_stream.dataset': ['endpoint.alerts'], + 'signal.rule.timestamp_override': ['event.ingested'], + 'kibana.alert.rule.execution.uuid': ['d01ed96c-59be-4d04-b14f-944f31f5be5f'], + 'kibana.alert.uuid': ['7a401ca5e5dac578d08ec0e929bf3c735446752f66c569cb0e910215f0a8b7e5'], + 'process.hash.sha1': ['fake sha1'], + 'signal.rule.license': ['Elastic License v2'], + 'kibana.alert.rule.rule_id': ['9a1a2dae-0b5f-4c3d-8305-a268d404c306'], + 'process.session_leader.pid': [617], + 'file.path': ['C:/fake_malware.exe'], + 'signal.rule.type': ['query'], + 'Endpoint.policy.applied.version': [3], + 'dll.hash.md5': ['1f2d082566b0fc5f2c238a5180db7451'], + 'signal.rule.rule_name_override': ['message'], + 'kibana.alert.rule.risk_score_mapping.field': ['event.risk_score'], + 'process.Ext.token.privileges.name': ['SeAssignPrimaryTokenPrivilege'], + 'process.pid': [2], + 'signal.rule.created_by': ['elastic'], + 'signal.rule.interval': ['5m'], + 'kibana.alert.rule.created_by': ['elastic'], + 'kibana.alert.rule.timestamp_override': ['event.ingested'], + 'process.parent.entity_id': ['yybc8cgr8a'], + 'kibana.alert.rule.name': ['Endpoint Security'], + 'host.name': ['Host-ffhve1li02'], + 'event.kind': ['signal'], + 'signal.rule.created_at': ['2023-10-27T16:33:43.125Z'], + 'kibana.alert.workflow_status': ['open'], + 'Endpoint.policy.applied.status': ['failure'], + 'dll.Ext.malware_classification.threshold': [0], + 'kibana.alert.reason': [ + 'malware event with process malware writer, file fake_malware.exe, by wxqb4pxvtg on Host-ffhve1li02 created medium alert Endpoint Security.', + ], + 'dll.pe.architecture': ['x64'], + 'data_stream.type': ['logs'], + 'process.Ext.token.user': ['SYSTEM'], + 'signal.ancestors.id': ['UqsMqosB1rJhB-h4wsnG'], + 'signal.original_time': ['2023-11-07T17:53:34.919Z'], + 'ecs.version': ['1.4.0'], + 'signal.rule.severity': ['medium'], + 'Endpoint.configuration.isolation': [false], + 'kibana.alert.depth': [1], + 'kibana.alert.rule.revision': [0], + 'process.start': ['2023-11-07T17:53:34.919Z'], + 'signal.rule.version': ['102'], + 'kibana.alert.status': ['active'], + 'kibana.alert.last_detected': ['2023-11-07T13:54:29.175Z'], + 'kibana.alert.rule.severity_mapping.field': [ + 'event.severity', + 'event.severity', + 'event.severity', + 'event.severity', + ], + 'kibana.alert.original_event.dataset': ['endpoint'], + 'file.hash.sha1': ['fake file sha1'], + 'kibana.alert.rule.rule_type_id': ['siem.queryRule'], + 'process.session_leader.name': ['fake session'], + 'signal.rule.rule_id': ['9a1a2dae-0b5f-4c3d-8305-a268d404c306'], + 'process.executable': ['C:/malware.exe'], + 'file.Ext.code_signature.trusted': [false], + 'process.entry_leader.start': ['1970-01-01T00:00:00.000Z'], + 'file.Ext.code_signature.subject_name': ['bad signer'], + 'kibana.alert.rule.updated_at': ['2023-10-27T16:33:43.125Z'], + 'data_stream.namespace': ['default'], + 'dll.code_signature.subject_name': ['Cybereason Inc'], + 'kibana.alert.rule.author': ['Elastic'], + 'file.size': [3456], + 'Endpoint.policy.applied.endpoint_policy_version': [1], + 'signal.original_event.action': ['rename'], + 'kibana.alert.rule.created_at': ['2023-10-27T16:33:43.125Z'], + 'signal.rule.to': ['now'], + 'event.type': ['creation'], + 'process.entry_leader.entity_id': ['qkngtu1ty9'], + 'process.Ext.token.integrity_level': [16384], + 'kibana.alert.rule.exceptions_list.id': ['endpoint_list'], + 'event.dataset': ['endpoint'], + 'kibana.alert.original_time': ['2023-11-07T17:53:34.919Z'], + }, + }, + { + _index: '.internal.alerts-security.alerts-default-000001', + _id: '3d040f57d83c40c8e1a9c2f1576ccd6e31e178135a6e98174fd40cd0924cc2a6', + _score: 1, + fields: { + 'host.os.full.text': ['Windows Server 2019 Datacenter 1809 (10.0.17763.4737)'], + 'kibana.alert.rule.updated_by': ['elastic'], + 'host.os.name.text': ['Windows'], + 'kibana.alert.rule.rule_name_override': ['message'], + 'host.hostname': ['siem-windows-endpoint'], + 'signal.original_event.created': ['2023-08-30T09:54:18.074Z'], + 'host.mac': ['42-01-0a-c8-00-1c'], + 'Events.process.pe.imphash': ['741776aaccfc5b71ff59832dcdcace0f'], + 'elastic.agent.id': ['0aa5458e-696b-40a6-98da-c3eafc66e2cb'], + 'Events.event.outcome': ['unknown', 'unknown'], + 'signal.rule.enabled': ['true'], + 'host.os.version': ['1809 (10.0.17763.4737)'], + 'signal.rule.max_signals': [10000], + 'kibana.alert.risk_score': [73], + 'signal.rule.updated_at': ['2023-08-30T09:33:26.498Z'], + 'Events.process.args': [ + 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', + '-NoProfile', + '-NonInteractive', + '-ExecutionPolicy', + 'Unrestricted', + '-EncodedCommand', + 'JgBjAGgAYwBwAC4AYwBvAG0AIAA2ADUAMAAwADEAIAA+ACAAJABuAHUAbABsAAoAaQBmACAAKAAkAFAAUwBWAGUAcgBzAGkAbwBuAFQAYQBiAGwAZQAuAFAAUwBWAGUAcgBzAGkAbwBuACAALQBsAHQAIABbAFYAZQByAHMAaQBvAG4AXQAiADMALgAwACIAKQAgAHsACgAnAHsAIgBmAGEAaQBsAGUAZAAiADoAdAByAHUAZQAsACIAbQBzAGcAIgA6ACIAQQBuAHMAaQBiAGwAZQAgAHIAZQBxAHUAaQByAGUAcwAgAFAAbwB3AGUAcgBTAGgAZQBsAGwAIAB2ADMALgAwACAAbwByACAAbgBlAHcAZQByACIAfQAnAAoAZQB4AGkAdAAgADEACgB9AAoAJABlAHgAZQBjAF8AdwByAGEAcABwAGUAcgBfAHMAdAByACAAPQAgACQAaQBuAHAAdQB0ACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcACgAkAHMAcABsAGkAdABfAHAAYQByAHQAcwAgAD0AIAAkAGUAeABlAGMAXwB3AHIAYQBwAHAAZQByAF8AcwB0AHIALgBTAHAAbABpAHQAKABAACgAIgBgADAAYAAwAGAAMABgADAAIgApACwAIAAyACwAIABbAFMAdAByAGkAbgBnAFMAcABsAGkAdABPAHAAdABpAG8AbgBzAF0AOgA6AFIAZQBtAG8AdgBlAEUAbQBwAHQAeQBFAG4AdAByAGkAZQBzACkACgBJAGYAIAAoAC0AbgBvAHQAIAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwAuAEwAZQBuAGcAdABoACAALQBlAHEAIAAyACkAIAB7ACAAdABoAHIAbwB3ACAAIgBpAG4AdgBhAGwAaQBkACAAcABhAHkAbABvAGEAZAAiACAAfQAKAFMAZQB0AC0AVgBhAHIAaQBhAGIAbABlACAALQBOAGEAbQBlACAAagBzAG8AbgBfAHIAYQB3ACAALQBWAGEAbAB1AGUAIAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwBbADEAXQAKACQAZQB4AGUAYwBfAHcAcgBhAHAAcABlAHIAIAA9ACAAWwBTAGMAcgBpAHAAdABCAGwAbwBjAGsAXQA6ADoAQwByAGUAYQB0AGUAKAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwBbADAAXQApAAoAJgAkAGUAeABlAGMAXwB3AHIAYQBwAHAAZQByAA==', + ], + 'Effective_process.pid': [8808], + 'kibana.alert.original_event.id': ['NCwF97poe8L69pfb+++++GFG'], + 'event.severity': [73], + 'Responses.action.action': ['kill_process'], + 'file.path.text': ['C:\\Windows\\System32\\Tasks\\MockRansomwareTask'], + 'Effective_process.executable': [ + 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', + ], + 'host.os.type': ['windows'], + 'Effective_process.name': ['powershell.exe'], + 'signal.original_event.code': ['behavior'], + 'kibana.alert.original_event.module': ['endpoint'], + 'kibana.alert.rule.interval': ['5m'], + 'Events.process.parent.code_signature.exists': [true], + 'kibana.alert.rule.type': ['query'], + 'kibana.alert.rule.immutable': ['true'], + 'Events.process.parent.args_count': [7], + 'kibana.alert.rule.exceptions_list.list_id': ['endpoint_list'], + 'threat.technique.subtechnique.name': ['Scheduled Task'], + 'Events.process.hash.md5': ['7353f60b1739074eb17c5f4dddefe239'], + 'kibana.alert.rule.version': ['102'], + 'Events.process.thread.Ext.call_stack_summary': [ + 'ntdll.dll|kernelbase.dll|schedsvc.dll|rpcrt4.dll|ntdll.dll|kernel32.dll|ntdll.dll', + ], + 'Events.process.code_signature.trusted': [true, true], + 'Events.process.Ext.token.security_attributes': ['TSA://ProcUnique'], + 'Events.process.parent.executable': [ + 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', + ], + 'Events.process.Ext.relative_file_name_modify_time': [35735739.3586987], + 'Events.host.mac': ['42-01-0a-c8-00-1c', '42-01-0a-c8-00-1c'], + 'signal.original_event.outcome': ['success'], + 'threat.framework': ['MITRE ATT&CK'], + 'process.entity_id': [ + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTE1NzItMTY5MzM4ODg5MS4xOTY0MjA4MDA=', + ], + 'host.ip': ['10.200.0.28', 'fe80::3219:dc81:cc1f:f4af', '127.0.0.1', '::1'], + 'agent.type': ['endpoint'], + 'process.executable.text': ['C:\\Windows\\System32\\svchost.exe'], + 'signal.original_event.category': ['malware', 'intrusion_detection'], + 'Events.user.id': [ + 'S-1-5-21-1629559480-2308347870-1638096131-1001', + 'S-1-5-21-1629559480-2308347870-1638096131-1001', + ], + 'Events.process.command_line': [ + '"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand JgBjAGgAYwBwAC4AYwBvAG0AIAA2ADUAMAAwADEAIAA+ACAAJABuAHUAbABsAAoAaQBmACAAKAAkAFAAUwBWAGUAcgBzAGkAbwBuAFQAYQBiAGwAZQAuAFAAUwBWAGUAcgBzAGkAbwBuACAALQBsAHQAIABbAFYAZQByAHMAaQBvAG4AXQAiADMALgAwACIAKQAgAHsACgAnAHsAIgBmAGEAaQBsAGUAZAAiADoAdAByAHUAZQAsACIAbQBzAGcAIgA6ACIAQQBuAHMAaQBiAGwAZQAgAHIAZQBxAHUAaQByAGUAcwAgAFAAbwB3AGUAcgBTAGgAZQBsAGwAIAB2ADMALgAwACAAbwByACAAbgBlAHcAZQByACIAfQAnAAoAZQB4AGkAdAAgADEACgB9AAoAJABlAHgAZQBjAF8AdwByAGEAcABwAGUAcgBfAHMAdAByACAAPQAgACQAaQBuAHAAdQB0ACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcACgAkAHMAcABsAGkAdABfAHAAYQByAHQAcwAgAD0AIAAkAGUAeABlAGMAXwB3AHIAYQBwAHAAZQByAF8AcwB0AHIALgBTAHAAbABpAHQAKABAACgAIgBgADAAYAAwAGAAMABgADAAIgApACwAIAAyACwAIABbAFMAdAByAGkAbgBnAFMAcABsAGkAdABPAHAAdABpAG8AbgBzAF0AOgA6AFIAZQBtAG8AdgBlAEUAbQBwAHQAeQBFAG4AdAByAGkAZQBzACkACgBJAGYAIAAoAC0AbgBvAHQAIAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwAuAEwAZQBuAGcAdABoACAALQBlAHEAIAAyACkAIAB7ACAAdABoAHIAbwB3ACAAIgBpAG4AdgBhAGwAaQBkACAAcABhAHkAbABvAGEAZAAiACAAfQAKAFMAZQB0AC0AVgBhAHIAaQBhAGIAbABlACAALQBOAGEAbQBlACAAagBzAG8AbgBfAHIAYQB3ACAALQBWAGEAbAB1AGUAIAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwBbADEAXQAKACQAZQB4AGUAYwBfAHcAcgBhAHAAcABlAHIAIAA9ACAAWwBTAGMAcgBpAHAAdABCAGwAbwBjAGsAXQA6ADoAQwByAGUAYQB0AGUAKAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwBbADAAXQApAAoAJgAkAGUAeABlAGMAXwB3AHIAYQBwAHAAZQByAA==', + ], + 'host.id': ['9b610e2b-5b2b-4a91-ab42-668d272ade50'], + 'process.Ext.code_signature.subject_name': ['Microsoft Windows Publisher'], + 'Responses.@timestamp': ['2023-08-30T09:54:18.0903678Z'], + 'Events.@timestamp': ['2023-08-30T09:54:14.4862516Z', '2023-08-30T09:54:18.0674986Z'], + 'Events.process.parent.code_signature.subject_name': ['Microsoft Windows'], + 'Events.user.name': ['elastic', 'elastic'], + 'kibana.alert.rule.indices': ['logs-endpoint.alerts-*'], + 'host.os.Ext.variant': ['Windows Server 2019 Datacenter'], + 'Events.event.action': ['start', 'creation'], + 'signal.rule.updated_by': ['elastic'], + 'host.os.platform': ['windows'], + 'kibana.alert.rule.severity': ['medium'], + 'Events.process.Ext.ancestry': [ + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTg3NTYtMTY5MzM4OTI1My44OTQ1MDI3MDA=', + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTg3MDAtMTY5MzM4OTI1My44NDY1NTcxMDA=', + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTg3NzItMTY5MzM4OTI1My42NDU0NDEwMDA=', + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTc1Ni0xNjkzMzg4ODg1LjQzNDM1MzEwMA==', + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTYxMi0xNjkzMzg4ODgyLjIxMzg0NjAw', + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTUwMC0xNjkzMzg4ODgxLjQxMTE3ODQwMA==', + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTYxMi0xNjkzMzg4ODgyLjIxMzg0NjAw', + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTUwMC0xNjkzMzg4ODgxLjQxMTE3ODQwMA==', + ], + 'Endpoint.policy.applied.artifacts.user.identifiers.sha256': [ + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + ], + 'Events.process.Ext.token.integrity_level_name': ['high'], + 'kibana.version': ['8.10.0-SNAPSHOT'], + 'event.id': ['NCwF97poe8L69pfb+++++GFG'], + 'signal.ancestors.type': ['event'], + 'user.name.text': ['elastic'], + 'Events.file.Ext.header_bytes': ['fffe3c003f0078006d006c0020007600'], + 'kibana.alert.ancestors.id': ['MWn3RYoBi3W_N62iAHoI'], + 'process.name.text': ['svchost.exe'], + 'Events.process.hash.sha1': ['6cbce4a295c163791b60fc23d285e6d84f28ee4c'], + 'host.os.full': ['Windows Server 2019 Datacenter 1809 (10.0.17763.4737)'], + 'kibana.alert.original_event.code': ['behavior'], + 'Endpoint.policy.applied.artifacts.global.identifiers.name': [ + 'diagnostic-endpointpe-v4-blocklist', + 'diagnostic-endpointpe-v4-exceptionlist', + 'diagnostic-endpointpe-v4-model', + 'diagnostic-malware-signature-v1-windows', + 'diagnostic-ransomware-v1-windows', + 'diagnostic-rules-windows-v1', + 'endpointpe-v4-blocklist', + 'endpointpe-v4-exceptionlist', + 'endpointpe-v4-model', + 'global-configuration-v1', + 'global-eventfilterlist-windows-v1', + 'global-exceptionlist-windows', + 'global-trustlist-windows-v1', + 'production-malware-signature-v1-windows', + 'production-ransomware-v1-windows', + 'production-rules-windows-v1', + ], + 'kibana.alert.rule.description': [ + 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', + ], + 'kibana.alert.rule.producer': ['siem'], + 'kibana.alert.rule.to': ['now'], + 'Endpoint.policy.applied.artifacts.user.version': ['1.0.0'], + 'kibana.alert.original_event.ingested': ['2023-08-30T10:22:09.000Z'], + 'signal.rule.id': ['44a7f830-4718-11ee-a876-8955b5f07a55'], + 'rule.ruleset': ['production'], + 'signal.reason': [ + 'malware, intrusion_detection event with process svchost.exe, file MockRansomwareTask, by elastic on siem-windows-endpoint created high alert Malicious Behavior Prevention Alert: Scheduled Task Creation by an Unusual Process.', + ], + 'signal.rule.risk_score': [73], + 'host.os.name': ['Windows'], + 'Responses.action.field': ['process.entity_id'], + 'Events.file.Ext.monotonic_id': [466], + 'signal.status': ['open'], + 'Events.host.os.full': [ + 'Windows Server 2019 Datacenter 1809 (10.0.17763.4737)', + 'Windows Server 2019 Datacenter 1809 (10.0.17763.4737)', + ], + 'kibana.alert.rule.severity_mapping.value': ['21', '47', '73', '99'], + 'signal.rule.tags': ['Data Source: Elastic Defend'], + 'rule.name': ['Scheduled Task Creation by an Unusual Process'], + 'kibana.alert.rule.uuid': ['44a7f830-4718-11ee-a876-8955b5f07a55'], + 'Events.process.executable': [ + 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', + 'C:\\Windows\\System32\\svchost.exe', + ], + 'kibana.alert.original_event.category': ['malware', 'intrusion_detection'], + 'signal.original_event.risk_score': [73], + 'Events.host.os.name': ['Windows', 'Windows'], + 'Responses.process.entity_id': [ + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTg4MDgtMTY5MzM4OTI1NC40ODYyNTE2MDA=', + ], + 'rule.description': [ + 'Identifies the creation of a scheduled task by an unusual process such as script interpreters or recently dropped unsigned executables. This behavior is consistent with an adversary attempting to establish persistence.', + ], + 'threat.technique.id': ['T1053'], + 'Events.process.args_count': [7], + 'Events.process.name': ['powershell.exe', 'svchost.exe'], + 'process.name': ['svchost.exe'], + 'Events.process.Ext.session_info.logon_type': ['Network'], + 'Events.process.Ext.code_signature.status': ['trusted', 'trusted'], + 'Events.process.code_signature.status': ['trusted', 'trusted'], + 'kibana.alert.ancestors.index': ['.ds-logs-endpoint.alerts-default-2023.08.30-000001'], + 'process.Ext.code_signature.trusted': [true], + 'agent.version': ['8.10.0-SNAPSHOT'], + 'signal.original_event.severity': [73], + 'Effective_process.entity_id': [ + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTg4MDgtMTY5MzM4OTI1NC40ODYyNTE2MDA=', + ], + 'kibana.alert.rule.risk_score_mapping.operator': ['equals'], + 'host.os.family': ['windows'], + 'kibana.alert.rule.from': ['now-10m'], + 'kibana.alert.rule.parameters': [ + { + description: + 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', + risk_score: 47, + severity: 'medium', + license: 'Elastic License v2', + rule_name_override: 'message', + timestamp_override: 'event.ingested', + investigation_fields: [], + author: ['Elastic'], + false_positives: [], + from: 'now-10m', + rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + max_signals: 10000, + risk_score_mapping: [ + { + field: 'event.risk_score', + operator: 'equals', + value: '', + }, + ], + severity_mapping: [ + { + field: 'event.severity', + operator: 'equals', + severity: 'low', + value: '21', + }, + { + field: 'event.severity', + operator: 'equals', + severity: 'medium', + value: '47', + }, + { + field: 'event.severity', + operator: 'equals', + severity: 'high', + value: '73', + }, + { + field: 'event.severity', + operator: 'equals', + severity: 'critical', + value: '99', + }, + ], + threat: [], + to: 'now', + references: [], + version: 102, + exceptions_list: [ + { + id: 'endpoint_list', + list_id: 'endpoint_list', + namespace_type: 'agnostic', + type: 'endpoint', + }, + ], + immutable: true, + related_integrations: [ + { + package: 'endpoint', + version: '^8.2.0', + }, + ], + required_fields: [ + { + ecs: true, + name: 'event.kind', + type: 'keyword', + }, + { + ecs: true, + name: 'event.module', + type: 'keyword', + }, + ], + setup: '', + type: 'query', + language: 'kuery', + index: ['logs-endpoint.alerts-*'], + query: 'event.kind:alert and event.module:(endpoint and not endgame)\n', + }, + ], + 'signal.original_event.kind': ['alert'], + 'threat.technique.name': ['Scheduled Task/Job'], + 'Responses.message': ['Success'], + 'Events.event.type': ['start', 'creation'], + 'Events.event.created': ['2023-08-30T09:54:14.4862516Z', '2023-08-30T09:54:18.0674986Z'], + 'signal.depth': [1], + 'Events.process.parent.code_signature.status': ['trusted'], + 'Events.file.name': ['MockRansomwareTask'], + 'signal.rule.immutable': ['true'], + 'event.sequence': [5006], + 'signal.rule.name': [ + 'Malicious Behavior Prevention Alert: Scheduled Task Creation by an Unusual Process', + ], + 'event.module': ['endpoint'], + 'kibana.alert.rule.severity_mapping.operator': ['equals', 'equals', 'equals', 'equals'], + 'host.os.kernel': ['1809 (10.0.17763.4737)'], + 'kibana.alert.rule.license': ['Elastic License v2'], + 'kibana.alert.original_event.kind': ['alert'], + 'Events.Effective_process.pid': [8808], + 'file.Ext.entropy': [3.442708269901192], + 'signal.rule.description': [ + 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', + ], + 'Events.process.parent.Ext.code_signature.subject_name': ['Microsoft Windows'], + message: [ + 'Malicious Behavior Prevention Alert: Scheduled Task Creation by an Unusual Process', + ], + 'Responses.process.name': ['powershell.exe'], + 'rule.version': ['1.0.23'], + 'Events.process.parent.Ext.code_signature.trusted': [true], + 'kibana.alert.original_event.outcome': ['success'], + 'kibana.alert.original_event.sequence': [5006], + 'threat.technique.subtechnique.id': ['T1053.005'], + 'Events.process.parent.thread.Ext.call_stack.callsite_leading_bytes': [ + '2428f6c1017404488b49ffe82fe8685f4889442430498bd5448b44245c4c8b4c2448488b6c244048896c2420488b6c243848896c2428488d4b08488b09ff5318', + ], + 'kibana.alert.rule.exceptions_list.namespace_type': ['agnostic'], + 'threat.technique.reference': ['https://attack.mitre.org/techniques/T1053/'], + 'kibana.space_ids': ['default'], + 'kibana.alert.severity': ['high'], + 'rule.id': ['cb5fdbe3-84fa-4277-a967-1ffc0e8d3d25'], + 'Responses.result': [0], + 'signal.ancestors.depth': [0], + 'event.category': ['malware', 'intrusion_detection'], + 'Endpoint.policy.applied.artifacts.global.identifiers.sha256': [ + '17d8695f22d3817c426a0e08a477b88ecdb6088bc253dfbccc760224600afcfd', + '360d54813b22a0cb43fd85a04c296690e8daae76c392c8290950d360bbe2f036', + '64f0de2812eb4f97bb97ac7e6f156e85e1a92a94da16a11c09e3e34fef8ea890', + 'b148e9dc65738cdb3f1efd9eccb72739e0ea241db77a706f31088bbb95468e2e', + '0e3b9a2fc1bd1f4428c445a98ab8890a79ab0f385f51465933b47ec850b93d85', + '0ea4938e578f8af2cfaec7e4809a49c99ef787edb4228954d809900288e0a560', + '65cb7056d27f3ad4ae52c5f1160528f9424bea5ee2246cd4d9de470cdf265af1', + 'b450c0b140d9bb881ca3b0918454e39426a7fa50da2e094233ed2e5f9cf086e6', + '7a9858f040c2965b4f3f31c3fcf19eedc938a5b75880a94f86f9627942dd1f02', + 'ac9ea7b6be0c281030a05cda450eab04a80fe323cf189b11b1c03cdc827ae6fa', + 'e561fff00d3c73367571cfb70694c6e38bedbc6269f4f7a61f8e79f797c32f1c', + 'e04703ba6a2a0f8234f5e0e9bf44f2354e001498332f0d6050a7e9f3fdd818d6', + '35799e77e8b81397d2a7f6c808a68aff6a79828a82dcc3f23fb36b1f091c8639', + '2777862e16ea1f8d5f6fac712e585e1d277b7d0e10101cd841c010cde8bfb1b2', + 'b35d822a94e6e9129c9c736474bac0e95ebde2b11bc33d0c6e0311cd33152218', + '3cc333affef9d6f2ca6ad62573120ec463f2e81c863b8da88080e59096f64b43', + ], + 'rule.reference': [ + 'https://docs.microsoft.com/en-us/windows/win32/taskschd/daily-trigger-example--xml-', + ], + 'Events.host.ip': [ + '10.200.0.28', + 'fe80::3219:dc81:cc1f:f4af', + '127.0.0.1', + '::1', + '10.200.0.28', + 'fe80::3219:dc81:cc1f:f4af', + '127.0.0.1', + '::1', + ], + 'process.parent.pid': [612], + 'kibana.alert.original_event.risk_score': [73], + 'kibana.alert.rule.tags': ['Data Source: Elastic Defend'], + 'process.code_signature.exists': [true], + 'Events.process.Ext.session_info.authentication_package': ['NTLM'], + 'Events.process.Ext.code_signature.trusted': [true, true], + 'kibana.alert.ancestors.depth': [0], + 'threat.technique.name.text': ['Scheduled Task/Job'], + 'Events.host.id': [ + '9b610e2b-5b2b-4a91-ab42-668d272ade50', + '9b610e2b-5b2b-4a91-ab42-668d272ade50', + ], + 'process.thread.Ext.call_stack.symbol_info': [ + 'C:\\Windows\\System32\\ntdll.dll!NtCreateFile+0x14', + 'C:\\Windows\\System32\\KernelBase.dll!CreateFileW+0x643', + 'C:\\Windows\\System32\\KernelBase.dll!CreateFileW+0x66', + 'C:\\Windows\\System32\\schedsvc.dll!ServiceMain+0xa75a', + 'C:\\Windows\\System32\\schedsvc.dll+0x12f08', + 'C:\\Windows\\System32\\schedsvc.dll+0x12de4', + 'C:\\Windows\\System32\\schedsvc.dll+0x12ce1', + 'C:\\Windows\\System32\\schedsvc.dll+0x2aec8', + 'C:\\Windows\\System32\\schedsvc.dll+0x2ce8b', + 'C:\\Windows\\System32\\rpcrt4.dll!NdrNsGetBuffer+0x2463', + 'C:\\Windows\\System32\\rpcrt4.dll!NdrClientCall3+0x263a', + 'C:\\Windows\\System32\\rpcrt4.dll!NdrServerCallAll+0x40', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcExceptionFilter+0x38', + 'C:\\Windows\\System32\\rpcrt4.dll!RpcServerInqBindings+0x9aa0', + 'C:\\Windows\\System32\\rpcrt4.dll!RpcServerInqBindings+0x944b', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcBCacheAllocate+0x545f', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcBCacheAllocate+0x48ba', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcBCacheAllocate+0x3e81', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcBCacheAllocate+0x38f2', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcBCacheAllocate+0x1e5', + 'C:\\Windows\\System32\\ntdll.dll!RtlpTimeToTimeFields+0x5a0', + 'C:\\Windows\\System32\\ntdll.dll!RtlAcquireSRWLockExclusive+0x6f8', + 'C:\\Windows\\System32\\kernel32.dll!BaseThreadInitThunk+0x14', + 'C:\\Windows\\System32\\ntdll.dll!RtlUserThreadStart+0x21', + ], + 'Events.process.parent.args': [ + 'PowerShell', + '-NoProfile', + '-NonInteractive', + '-ExecutionPolicy', + 'Unrestricted', + '-EncodedCommand', + 'UABvAHcAZQByAFMAaABlAGwAbAAgAC0ATgBvAFAAcgBvAGYAaQBsAGUAIAAtAE4AbwBuAEkAbgB0AGUAcgBhAGMAdABpAHYAZQAgAC0ARQB4AGUAYwB1AHQAaQBvAG4AUABvAGwAaQBjAHkAIABVAG4AcgBlAHMAdAByAGkAYwB0AGUAZAAgAC0ARQBuAGMAbwBkAGUAZABDAG8AbQBtAGEAbgBkACAASgBnAEIAagBBAEcAZwBBAFkAdwBCAHcAQQBDADQAQQBZAHcAQgB2AEEARwAwAEEASQBBAEEAMgBBAEQAVQBBAE0AQQBBAHcAQQBEAEUAQQBJAEEAQQArAEEAQwBBAEEASgBBAEIAdQBBAEgAVQBBAGIAQQBCAHMAQQBBAG8AQQBhAFEAQgBtAEEAQwBBAEEASwBBAEEAawBBAEYAQQBBAFUAdwBCAFcAQQBHAFUAQQBjAGcAQgB6AEEARwBrAEEAYgB3AEIAdQBBAEYAUQBBAFkAUQBCAGkAQQBHAHcAQQBaAFEAQQB1AEEARgBBAEEAVQB3AEIAVwBBAEcAVQBBAGMAZwBCAHoAQQBHAGsAQQBiAHcAQgB1AEEAQwBBAEEATABRAEIAcwBBAEgAUQBBAEkAQQBCAGIAQQBGAFkAQQBaAFEAQgB5AEEASABNAEEAYQBRAEIAdgBBAEcANABBAFgAUQBBAGkAQQBEAE0AQQBMAGcAQQB3AEEAQwBJAEEASwBRAEEAZwBBAEgAcwBBAEMAZwBBAG4AQQBIAHMAQQBJAGcAQgBtAEEARwBFAEEAYQBRAEIAcwBBAEcAVQBBAFoAQQBBAGkAQQBEAG8AQQBkAEEAQgB5AEEASABVAEEAWgBRAEEAcwBBAEMASQBBAGIAUQBCAHoAQQBHAGMAQQBJAGcAQQA2AEEAQwBJAEEAUQBRAEIAdQBBAEgATQBBAGEAUQBCAGkAQQBHAHcAQQBaAFEAQQBnAEEASABJAEEAWgBRAEIAeABBAEgAVQBBAGEAUQBCAHkAQQBHAFUAQQBjAHcAQQBnAEEARgBBAEEAYgB3AEIAMwBBAEcAVQBBAGMAZwBCAFQAQQBHAGcAQQBaAFEAQgBzAEEARwB3AEEASQBBAEIAMgBBAEQATQBBAEwAZwBBAHcAQQBDAEEAQQBiAHcAQgB5AEEAQwBBAEEAYgBnAEIAbABBAEgAYwBBAFoAUQBCAHkAQQBDAEkAQQBmAFEAQQBuAEEAQQBvAEEAWgBRAEIANABBAEcAawBBAGQAQQBBAGcAQQBEAEUAQQBDAGcAQgA5AEEAQQBvAEEASgBBAEIAbABBAEgAZwBBAFoAUQBCAGoAQQBGADgAQQBkAHcAQgB5AEEARwBFAEEAYwBBAEIAdwBBAEcAVQBBAGMAZwBCAGYAQQBIAE0AQQBkAEEAQgB5AEEAQwBBAEEAUABRAEEAZwBBAEMAUQBBAGEAUQBCAHUAQQBIAEEAQQBkAFEAQgAwAEEAQwBBAEEAZgBBAEEAZwBBAEUAOABBAGQAUQBCADAAQQBDADAAQQBVAHcAQgAwAEEASABJAEEAYQBRAEIAdQBBAEcAYwBBAEMAZwBBAGsAQQBIAE0AQQBjAEEAQgBzAEEARwBrAEEAZABBAEIAZgBBAEgAQQBBAFkAUQBCAHkAQQBIAFEAQQBjAHcAQQBnAEEARAAwAEEASQBBAEEAawBBAEcAVQBBAGUAQQBCAGwAQQBHAE0AQQBYAHcAQgAzAEEASABJAEEAWQBRAEIAdwBBAEgAQQBBAFoAUQBCAHkAQQBGADgAQQBjAHcAQgAwAEEASABJAEEATABnAEIAVABBAEgAQQBBAGIAQQBCAHAAQQBIAFEAQQBLAEEAQgBBAEEAQwBnAEEASQBnAEIAZwBBAEQAQQBBAFkAQQBBAHcAQQBHAEEAQQBNAEEAQgBnAEEARABBAEEASQBnAEEAcABBAEMAdwBBAEkAQQBBAHkAQQBDAHcAQQBJAEEAQgBiAEEARgBNAEEAZABBAEIAeQBBAEcAawBBAGIAZwBCAG4AQQBGAE0AQQBjAEEAQgBzAEEARwBrAEEAZABBAEIAUABBAEgAQQBBAGQAQQBCAHAAQQBHADgAQQBiAGcAQgB6AEEARgAwAEEATwBnAEEANgBBAEYASQBBAFoAUQBCAHQAQQBHADgAQQBkAGcAQgBsAEEARQBVAEEAYgBRAEIAdwBBAEgAUQBBAGUAUQBCAEYAQQBHADQAQQBkAEEAQgB5AEEARwBrAEEAWgBRAEIAegBBAEMAawBBAEMAZwBCAEoAQQBHAFkAQQBJAEEAQQBvAEEAQwAwAEEAYgBnAEIAdgBBAEgAUQBBAEkAQQBBAGsAQQBIAE0AQQBjAEEAQgBzAEEARwBrAEEAZABBAEIAZgBBAEgAQQBBAFkAUQBCAHkAQQBIAFEAQQBjAHcAQQB1AEEARQB3AEEAWgBRAEIAdQBBAEcAYwBBAGQAQQBCAG8AQQBDAEEAQQBMAFEAQgBsAEEASABFAEEASQBBAEEAeQBBAEMAawBBAEkAQQBCADcAQQBDAEEAQQBkAEEAQgBvAEEASABJAEEAYgB3AEIAMwBBAEMAQQBBAEkAZwBCAHAAQQBHADQAQQBkAGcAQgBoAEEARwB3AEEAYQBRAEIAawBBAEMAQQBBAGMAQQBCAGgAQQBIAGsAQQBiAEEAQgB2AEEARwBFAEEAWgBBAEEAaQBBAEMAQQBBAGYAUQBBAEsAQQBGAE0AQQBaAFEAQgAwAEEAQwAwAEEAVgBnAEIAaABBAEgASQBBAGEAUQBCAGgAQQBHAEkAQQBiAEEAQgBsAEEAQwBBAEEATABRAEIATwBBAEcARQBBAGIAUQBCAGwAQQBDAEEAQQBhAGcAQgB6AEEARwA4AEEAYgBnAEIAZgBBAEgASQBBAFkAUQBCADMAQQBDAEEAQQBMAFEAQgBXAEEARwBFAEEAYgBBAEIAMQBBAEcAVQBBAEkAQQBBAGsAQQBIAE0AQQBjAEEAQgBzAEEARwBrAEEAZABBAEIAZgBBAEgAQQBBAFkAUQBCAHkAQQBIAFEAQQBjAHcAQgBiAEEARABFAEEAWABRAEEASwBBAEMAUQBBAFoAUQBCADQAQQBHAFUAQQBZAHcAQgBmAEEASABjAEEAYwBnAEIAaABBAEgAQQBBAGMAQQBCAGwAQQBIAEkAQQBJAEEAQQA5AEEAQwBBAEEAVwB3AEIAVABBAEcATQBBAGMAZwBCAHAAQQBIAEEAQQBkAEEAQgBDAEEARwB3AEEAYgB3AEIAagBBAEcAcwBBAFgAUQBBADYAQQBEAG8AQQBRAHcAQgB5AEEARwBVAEEAWQBRAEIAMABBAEcAVQBBAEsAQQBBAGsAQQBIAE0AQQBjAEEAQgBzAEEARwBrAEEAZABBAEIAZgBBAEgAQQBBAFkAUQBCAHkAQQBIAFEAQQBjAHcAQgBiAEEARABBAEEAWABRAEEAcABBAEEAbwBBAEoAZwBBAGsAQQBHAFUAQQBlAEEAQgBsAEEARwBNAEEAWAB3AEIAMwBBAEgASQBBAFkAUQBCAHcAQQBIAEEAQQBaAFEAQgB5AEEAQQA9AD0A', + ], + 'kibana.alert.rule.severity_mapping.severity': ['low', 'medium', 'high', 'critical'], + 'agent.build.original': [ + 'version: 8.10.0-SNAPSHOT, compiled: Mon Aug 28 01:00:00 2023, branch: 8.10, commit: ff8431347e187a8f81b7d1ce375f1f910c216f00', + ], + 'Events.process.parent.entity_id': [ + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTg3NTYtMTY5MzM4OTI1My44OTQ1MDI3MDA=', + ], + 'event.agent_id_status': ['verified'], + 'Events.process.parent.command_line': [ + 'PowerShell -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand UABvAHcAZQByAFMAaABlAGwAbAAgAC0ATgBvAFAAcgBvAGYAaQBsAGUAIAAtAE4AbwBuAEkAbgB0AGUAcgBhAGMAdABpAHYAZQAgAC0ARQB4AGUAYwB1AHQAaQBvAG4AUABvAGwAaQBjAHkAIABVAG4AcgBlAHMAdAByAGkAYwB0AGUAZAAgAC0ARQBuAGMAbwBkAGUAZABDAG8AbQBtAGEAbgBkACAASgBnAEIAagBBAEcAZwBBAFkAdwBCAHcAQQBDADQAQQBZAHcAQgB2AEEARwAwAEEASQBBAEEAMgBBAEQAVQBBAE0AQQBBAHcAQQBEAEUAQQBJAEEAQQArAEEAQwBBAEEASgBBAEIAdQBBAEgAVQBBAGIAQQBCAHMAQQBBAG8AQQBhAFEAQgBtAEEAQwBBAEEASwBBAEEAawBBAEYAQQBBAFUAdwBCAFcAQQBHAFUAQQBjAGcAQgB6AEEARwBrAEEAYgB3AEIAdQBBAEYAUQBBAFkAUQBCAGkAQQBHAHcAQQBaAFEAQQB1AEEARgBBAEEAVQB3AEIAVwBBAEcAVQBBAGMAZwBCAHoAQQBHAGsAQQBiAHcAQgB1AEEAQwBBAEEATABRAEIAcwBBAEgAUQBBAEkAQQBCAGIAQQBGAFkAQQBaAFEAQgB5AEEASABNAEEAYQBRAEIAdgBBAEcANABBAFgAUQBBAGkAQQBEAE0AQQBMAGcAQQB3AEEAQwBJAEEASwBRAEEAZwBBAEgAcwBBAEMAZwBBAG4AQQBIAHMAQQBJAGcAQgBtAEEARwBFAEEAYQBRAEIAcwBBAEcAVQBBAFoAQQBBAGkAQQBEAG8AQQBkAEEAQgB5AEEASABVAEEAWgBRAEEAcwBBAEMASQBBAGIAUQBCAHoAQQBHAGMAQQBJAGcAQQA2AEEAQwBJAEEAUQBRAEIAdQBBAEgATQBBAGEAUQBCAGkAQQBHAHcAQQBaAFEAQQBnAEEASABJAEEAWgBRAEIAeABBAEgAVQBBAGEAUQBCAHkAQQBHAFUAQQBjAHcAQQBnAEEARgBBAEEAYgB3AEIAMwBBAEcAVQBBAGMAZwBCAFQAQQBHAGcAQQBaAFEAQgBzAEEARwB3AEEASQBBAEIAMgBBAEQATQBBAEwAZwBBAHcAQQBDAEEAQQBiAHcAQgB5AEEAQwBBAEEAYgBnAEIAbABBAEgAYwBBAFoAUQBCAHkAQQBDAEkAQQBmAFEAQQBuAEEAQQBvAEEAWgBRAEIANABBAEcAawBBAGQAQQBBAGcAQQBEAEUAQQBDAGcAQgA5AEEAQQBvAEEASgBBAEIAbABBAEgAZwBBAFoAUQBCAGoAQQBGADgAQQBkAHcAQgB5AEEARwBFAEEAYwBBAEIAdwBBAEcAVQBBAGMAZwBCAGYAQQBIAE0AQQBkAEEAQgB5AEEAQwBBAEEAUABRAEEAZwBBAEMAUQBBAGEAUQBCAHUAQQBIAEEAQQBkAFEAQgAwAEEAQwBBAEEAZgBBAEEAZwBBAEUAOABBAGQAUQBCADAAQQBDADAAQQBVAHcAQgAwAEEASABJAEEAYQBRAEIAdQBBAEcAYwBBAEMAZwBBAGsAQQBIAE0AQQBjAEEAQgBzAEEARwBrAEEAZABBAEIAZgBBAEgAQQBBAFkAUQBCAHkAQQBIAFEAQQBjAHcAQQBnAEEARAAwAEEASQBBAEEAawBBAEcAVQBBAGUAQQBCAGwAQQBHAE0AQQBYAHcAQgAzAEEASABJAEEAWQBRAEIAdwBBAEgAQQBBAFoAUQBCAHkAQQBGADgAQQBjAHcAQgAwAEEASABJAEEATABnAEIAVABBAEgAQQBBAGIAQQBCAHAAQQBIAFEAQQBLAEEAQgBBAEEAQwBnAEEASQBnAEIAZwBBAEQAQQBBAFkAQQBBAHcAQQBHAEEAQQBNAEEAQgBnAEEARABBAEEASQBnAEEAcABBAEMAdwBBAEkAQQBBAHkAQQBDAHcAQQBJAEEAQgBiAEEARgBNAEEAZABBAEIAeQBBAEcAawBBAGIAZwBCAG4AQQBGAE0AQQBjAEEAQgBzAEEARwBrAEEAZABBAEIAUABBAEgAQQBBAGQAQQBCAHAAQQBHADgAQQBiAGcAQgB6AEEARgAwAEEATwBnAEEANgBBAEYASQBBAFoAUQBCAHQAQQBHADgAQQBkAGcAQgBsAEEARQBVAEEAYgBRAEIAdwBBAEgAUQBBAGUAUQBCAEYAQQBHADQAQQBkAEEAQgB5AEEARwBrAEEAWgBRAEIAegBBAEMAawBBAEMAZwBCAEoAQQBHAFkAQQBJAEEAQQBvAEEAQwAwAEEAYgBnAEIAdgBBAEgAUQBBAEkAQQBBAGsAQQBIAE0AQQBjAEEAQgBzAEEARwBrAEEAZABBAEIAZgBBAEgAQQBBAFkAUQBCAHkAQQBIAFEAQQBjAHcAQQB1AEEARQB3AEEAWgBRAEIAdQBBAEcAYwBBAGQAQQBCAG8AQQBDAEEAQQBMAFEAQgBsAEEASABFAEEASQBBAEEAeQBBAEMAawBBAEkAQQBCADcAQQBDAEEAQQBkAEEAQgBvAEEASABJAEEAYgB3AEIAMwBBAEMAQQBBAEkAZwBCAHAAQQBHADQAQQBkAGcAQgBoAEEARwB3AEEAYQBRAEIAawBBAEMAQQBBAGMAQQBCAGgAQQBIAGsAQQBiAEEAQgB2AEEARwBFAEEAWgBBAEEAaQBBAEMAQQBBAGYAUQBBAEsAQQBGAE0AQQBaAFEAQgAwAEEAQwAwAEEAVgBnAEIAaABBAEgASQBBAGEAUQBCAGgAQQBHAEkAQQBiAEEAQgBsAEEAQwBBAEEATABRAEIATwBBAEcARQBBAGIAUQBCAGwAQQBDAEEAQQBhAGcAQgB6AEEARwA4AEEAYgBnAEIAZgBBAEgASQBBAFkAUQBCADMAQQBDAEEAQQBMAFEAQgBXAEEARwBFAEEAYgBBAEIAMQBBAEcAVQBBAEkAQQBBAGsAQQBIAE0AQQBjAEEAQgBzAEEARwBrAEEAZABBAEIAZgBBAEgAQQBBAFkAUQBCAHkAQQBIAFEAQQBjAHcAQgBiAEEARABFAEEAWABRAEEASwBBAEMAUQBBAFoAUQBCADQAQQBHAFUAQQBZAHcAQgBmAEEASABjAEEAYwBnAEIAaABBAEgAQQBBAGMAQQBCAGwAQQBIAEkAQQBJAEEAQQA5AEEAQwBBAEEAVwB3AEIAVABBAEcATQBBAGMAZwBCAHAAQQBIAEEAQQBkAEEAQgBDAEEARwB3AEEAYgB3AEIAagBBAEcAcwBBAFgAUQBBADYAQQBEAG8AQQBRAHcAQgB5AEEARwBVAEEAWQBRAEIAMABBAEcAVQBBAEsAQQBBAGsAQQBIAE0AQQBjAEEAQgBzAEEARwBrAEEAZABBAEIAZgBBAEgAQQBBAFkAUQBCAHkAQQBIAFEAQQBjAHcAQgBiAEEARABBAEEAWABRAEEAcABBAEEAbwBBAEoAZwBBAGsAQQBHAFUAQQBlAEEAQgBsAEEARwBNAEEAWAB3AEIAMwBBAEgASQBBAFkAUQBCAHcAQQBIAEEAQQBaAFEAQgB5AEEAQQA9AD0A', + ], + 'Events.process.thread.id': [8216], + 'Events.process.parent.thread.Ext.call_stack_summary': [ + 'ntdll.dll|kernelbase.dll|kernel32.dll|system.ni.dll|system.management.automation.ni.dll|Unbacked', + ], + 'event.outcome': ['success'], + 'Events.event.kind': ['event', 'event'], + 'kibana.alert.rule.risk_score_mapping.value': [''], + 'user.id': ['S-1-5-21-1629559480-2308347870-1638096131-1001'], + 'process.Ext.ancestry': [ + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTYxMi0xNjkzMzg4ODgyLjIxMzg0NjAw', + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTUwMC0xNjkzMzg4ODgxLjQxMTE3ODQwMA==', + ], + 'signal.original_event.sequence': [5006], + 'event.risk_score': [73], + 'Events.host.hostname': ['siem-windows-endpoint', 'siem-windows-endpoint'], + 'threat.technique.subtechnique.reference': ['https://attack.mitre.org/techniques/T1053/005/'], + 'host.architecture': ['x86_64'], + 'kibana.alert.start': ['2023-08-30T10:23:54.793Z'], + 'process.Ext.code_signature.status': ['trusted'], + 'event.code': ['behavior'], + 'kibana.alert.original_event.type': ['info', 'allowed'], + 'agent.id': ['0aa5458e-696b-40a6-98da-c3eafc66e2cb'], + 'signal.original_event.module': ['endpoint'], + 'signal.rule.from': ['now-10m'], + 'Events.file.Ext.entropy': [3.442708269901192], + 'Events.file.size': [3266], + 'kibana.alert.rule.exceptions_list.type': ['endpoint'], + 'kibana.alert.rule.enabled': ['true'], + 'Events.process.Ext.authentication_id': ['0x147af0'], + 'kibana.alert.ancestors.type': ['event'], + 'Events.host.os.type': ['windows', 'windows'], + 'file.Ext.windows.zone_identifier': [-1], + 'Events.process.code_signature.subject_name': [ + 'Microsoft Windows', + 'Microsoft Windows Publisher', + ], + 'signal.ancestors.index': ['.ds-logs-endpoint.alerts-default-2023.08.30-000001'], + 'user.name': ['elastic'], + 'Events.process.Ext.code_signature.subject_name': [ + 'Microsoft Windows', + 'Microsoft Windows Publisher', + ], + 'Endpoint.policy.applied.artifacts.global.version': ['1.0.697'], + 'Events.process.Ext.session_info.id': [0], + 'Events.process.parent.Ext.code_signature.exists': [true], + 'Events.process.parent.thread.Ext.call_stack.protection': ['RWX'], + 'Events.host.os.Ext.variant': [ + 'Windows Server 2019 Datacenter', + 'Windows Server 2019 Datacenter', + ], + 'signal.original_event.id': ['NCwF97poe8L69pfb+++++GFG'], + 'Events.event.category': ['process', 'file'], + 'user.domain': ['SIEM-WINDOWS-EN'], + 'signal.original_event.type': ['info', 'allowed'], + 'kibana.alert.rule.max_signals': [10000], + 'Events.Effective_process.executable': [ + 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', + ], + 'signal.rule.author': ['Elastic'], + 'Events.process.Ext.relative_file_creation_time': [156393600.0314843], + 'Events.file.path': ['C:\\Windows\\System32\\Tasks\\MockRansomwareTask'], + 'kibana.alert.rule.risk_score': [47], + 'file.name': ['MockRansomwareTask'], + 'Events.file.Ext.windows.zone_identifier': [-1], + 'process.code_signature.status': ['trusted'], + 'signal.original_event.dataset': ['endpoint.alerts'], + 'Events.process.parent.pid': [8756, 612], + 'Events.process.Ext.token.elevation_level': ['default'], + 'kibana.alert.rule.consumer': ['siem'], + 'kibana.alert.rule.category': ['Custom Query Rule'], + 'event.action': ['rule_detection'], + 'event.ingested': ['2023-08-30T10:22:09.000Z'], + '@timestamp': ['2023-08-30T10:23:54.731Z'], + 'kibana.alert.original_event.action': ['rule_detection'], + 'kibana.alert.original_event.agent_id_status': ['verified'], + 'data_stream.dataset': ['endpoint.alerts'], + 'signal.rule.timestamp_override': ['event.ingested'], + 'kibana.alert.rule.execution.uuid': ['c1aca77b-1341-4569-ab92-fffcf598a98d'], + 'kibana.alert.uuid': ['3d040f57d83c40c8e1a9c2f1576ccd6e31e178135a6e98174fd40cd0924cc2a6'], + 'Endpoint.policy.applied.artifacts.user.identifiers.name': [ + 'endpoint-blocklist-windows-v1', + 'endpoint-eventfilterlist-windows-v1', + 'endpoint-exceptionlist-windows-v1', + 'endpoint-hostisolationexceptionlist-windows-v1', + 'endpoint-trustlist-windows-v1', + ], + 'signal.rule.license': ['Elastic License v2'], + 'kibana.alert.rule.rule_id': ['9a1a2dae-0b5f-4c3d-8305-a268d404c306'], + 'file.path': ['C:\\Windows\\System32\\Tasks\\MockRansomwareTask'], + 'signal.rule.type': ['query'], + 'signal.rule.rule_name_override': ['message'], + 'Events.process.Ext.code_signature.exists': [true, true], + 'Events.process.parent.thread.Ext.call_stack.callsite_trailing_bytes': [ + '834648fab8010000004883c4685b5d5e5f415c415d415e415fc3e8205b9f5fcc0000001910090010c20c300b500a60097008c006d004e002f000004000000000', + ], + 'kibana.alert.url': [ + 'https://kibana.siem.estc.dev/app/security/alerts/redirect/3d040f57d83c40c8e1a9c2f1576ccd6e31e178135a6e98174fd40cd0924cc2a6?index=.alerts-security.alerts-default×tamp=2023-08-30T10:23:54.731Z', + ], + 'kibana.alert.rule.risk_score_mapping.field': ['event.risk_score'], + 'Events._label': ['process_execution', 'scheduled_task_creation'], + 'process.pid': [1572], + 'signal.rule.created_by': ['elastic'], + 'signal.rule.interval': ['5m'], + 'kibana.alert.rule.created_by': ['elastic'], + 'Events.process.parent.thread.Ext.call_stack.symbol_info': [ + 'C:\\Windows\\System32\\ntdll.dll!ZwCreateUserProcess+0x14', + 'C:\\Windows\\System32\\KernelBase.dll!CreateProcessInternalW+0x1f12', + 'C:\\Windows\\System32\\KernelBase.dll!CreateProcessW+0x66', + 'C:\\Windows\\System32\\kernel32.dll!CreateProcessW+0x53', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System\\98a55333af123511d40829217789091a\\System.ni.dll+0x384036', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System\\98a55333af123511d40829217789091a\\System.ni.dll+0x2c4849', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System\\98a55333af123511d40829217789091a\\System.ni.dll+0x2c41b9', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Manaa57fc8cc#\\1626b84d4e3d35507a575b9e5c45c967\\System.Management.Automation.ni.dll+0x1159eb9', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Manaa57fc8cc#\\1626b84d4e3d35507a575b9e5c45c967\\System.Management.Automation.ni.dll+0x10b12da', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Manaa57fc8cc#\\1626b84d4e3d35507a575b9e5c45c967\\System.Management.Automation.ni.dll+0x113b9bd', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Manaa57fc8cc#\\1626b84d4e3d35507a575b9e5c45c967\\System.Management.Automation.ni.dll+0x113b67b', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Manaa57fc8cc#\\1626b84d4e3d35507a575b9e5c45c967\\System.Management.Automation.ni.dll+0x123e90f', + 'Unbacked+0x3401', + ], + 'kibana.alert.rule.timestamp_override': ['event.ingested'], + 'Events.process.entity_id': [ + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTg4MDgtMTY5MzM4OTI1NC40ODYyNTE2MDA=', + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTE1NzItMTY5MzM4ODg5MS4xOTY0MjA4MDA=', + ], + 'process.code_signature.subject_name': ['Microsoft Windows Publisher'], + 'kibana.alert.rule.name': [ + 'Malicious Behavior Prevention Alert: Scheduled Task Creation by an Unusual Process', + ], + 'host.name': ['siem-windows-endpoint'], + 'Events.process.parent.name': ['powershell.exe'], + 'event.kind': ['signal'], + 'process.code_signature.trusted': [true], + 'signal.rule.created_at': ['2023-08-30T09:33:26.498Z'], + 'Events.process.parent.Ext.code_signature.status': ['trusted'], + 'Events.process.parent.thread.Ext.call_stack_contains_unbacked': [true], + 'kibana.alert.workflow_status': ['open'], + 'Events.host.name': ['siem-windows-endpoint', 'siem-windows-endpoint'], + 'kibana.alert.original_event.created': ['2023-08-30T09:54:18.074Z'], + 'threat.tactic.id': ['TA0003'], + 'Events.host.os.platform': ['windows', 'windows'], + 'Events.host.architecture': ['x86_64', 'x86_64'], + 'Events.host.os.kernel': ['1809 (10.0.17763.4737)', '1809 (10.0.17763.4737)'], + 'threat.tactic.name': ['Persistence'], + 'threat.technique.subtechnique.name.text': ['Scheduled Task'], + 'kibana.alert.reason': [ + 'malware, intrusion_detection event with process svchost.exe, file MockRansomwareTask, by elastic on siem-windows-endpoint created high alert Malicious Behavior Prevention Alert: Scheduled Task Creation by an Unusual Process.', + ], + 'data_stream.type': ['logs'], + 'signal.ancestors.id': ['MWn3RYoBi3W_N62iAHoI'], + 'signal.original_time': ['2023-08-30T09:54:18.074Z'], + 'file.Ext.header_bytes': ['fffe3c003f0078006d006c0020007600'], + 'Events.Effective_process.name': ['powershell.exe'], + 'Responses.process.pid': [8808], + 'ecs.version': ['1.11.0'], + 'signal.rule.severity': ['high'], + 'event.created': ['2023-08-30T09:54:18.074Z'], + 'Responses.action.state': [0], + 'Events.Effective_process.entity_id': [ + 'MGFhNTQ1OGUtNjk2Yi00MGE2LTk4ZGEtYzNlYWZjNjZlMmNiLTg4MDgtMTY5MzM4OTI1NC40ODYyNTE2MDA=', + ], + 'kibana.alert.depth': [1], + 'process.thread.id': [8216], + 'process.thread.Ext.call_stack_summary': [ + 'ntdll.dll|kernelbase.dll|schedsvc.dll|rpcrt4.dll|ntdll.dll|kernel32.dll|ntdll.dll', + ], + 'Events.process.thread.Ext.call_stack.symbol_info': [ + 'C:\\Windows\\System32\\ntdll.dll!NtCreateFile+0x14', + 'C:\\Windows\\System32\\KernelBase.dll!CreateFileW+0x643', + 'C:\\Windows\\System32\\KernelBase.dll!CreateFileW+0x66', + 'C:\\Windows\\System32\\schedsvc.dll!ServiceMain+0xa75a', + 'C:\\Windows\\System32\\schedsvc.dll+0x12f08', + 'C:\\Windows\\System32\\schedsvc.dll+0x12de4', + 'C:\\Windows\\System32\\schedsvc.dll+0x12ce1', + 'C:\\Windows\\System32\\schedsvc.dll+0x2aec8', + 'C:\\Windows\\System32\\schedsvc.dll+0x2ce8b', + 'C:\\Windows\\System32\\rpcrt4.dll!NdrNsGetBuffer+0x2463', + 'C:\\Windows\\System32\\rpcrt4.dll!NdrClientCall3+0x263a', + 'C:\\Windows\\System32\\rpcrt4.dll!NdrServerCallAll+0x40', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcExceptionFilter+0x38', + 'C:\\Windows\\System32\\rpcrt4.dll!RpcServerInqBindings+0x9aa0', + 'C:\\Windows\\System32\\rpcrt4.dll!RpcServerInqBindings+0x944b', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcBCacheAllocate+0x545f', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcBCacheAllocate+0x48ba', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcBCacheAllocate+0x3e81', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcBCacheAllocate+0x38f2', + 'C:\\Windows\\System32\\rpcrt4.dll!I_RpcBCacheAllocate+0x1e5', + 'C:\\Windows\\System32\\ntdll.dll!RtlpTimeToTimeFields+0x5a0', + 'C:\\Windows\\System32\\ntdll.dll!RtlAcquireSRWLockExclusive+0x6f8', + 'C:\\Windows\\System32\\kernel32.dll!BaseThreadInitThunk+0x14', + 'C:\\Windows\\System32\\ntdll.dll!RtlUserThreadStart+0x21', + ], + 'kibana.alert.rule.revision': [0], + 'Events.message': ['Endpoint process event', 'Endpoint file event'], + 'signal.rule.version': ['102'], + 'Events.process.parent.code_signature.trusted': [true], + 'file.Ext.monotonic_id': [466], + 'kibana.alert.status': ['active'], + 'kibana.alert.last_detected': ['2023-08-30T10:23:54.793Z'], + 'Events.host.os.family': ['windows', 'windows'], + 'threat.tactic.reference': ['https://attack.mitre.org/tactics/TA0003/'], + 'Events.user.domain': ['SIEM-WINDOWS-EN', 'SIEM-WINDOWS-EN'], + 'kibana.alert.rule.severity_mapping.field': [ + 'event.severity', + 'event.severity', + 'event.severity', + 'event.severity', + ], + 'Events.process.pe.original_file_name': ['PowerShell.EXE'], + 'kibana.alert.original_event.dataset': ['endpoint.alerts'], + 'Events._state': [0, 1], + 'kibana.alert.rule.rule_type_id': ['siem.queryRule'], + 'Events.process.Ext.session_info.user_flags': [ + 'LOGON_EXTRA_SIDS', + 'LOGON_NTLMV2_ENABLED', + 'LOGON_NTLM_V2', + ], + 'signal.rule.rule_id': ['9a1a2dae-0b5f-4c3d-8305-a268d404c306'], + 'Events.process.Ext.session_info.relative_logon_time': [0.9732163], + 'process.executable': ['C:\\Windows\\System32\\svchost.exe'], + 'kibana.alert.original_event.severity': [73], + 'Events.host.os.version': ['1809 (10.0.17763.4737)', '1809 (10.0.17763.4737)'], + 'kibana.alert.rule.updated_at': ['2023-08-30T09:33:26.498Z'], + 'Events.event.id': ['NCwF97poe8L69pfb+++++FWI', 'NCwF97poe8L69pfb+++++GFE'], + 'data_stream.namespace': ['default'], + 'kibana.alert.rule.author': ['Elastic'], + 'file.size': [3266], + 'process.Ext.code_signature.exists': [true], + 'Events.process.pid': [8808, 1572], + 'signal.original_event.action': ['rule_detection'], + 'kibana.alert.rule.created_at': ['2023-08-30T09:33:26.498Z'], + 'signal.rule.to': ['now'], + 'Events.process.Ext.mitigation_policies': ['CF Guard'], + 'Events.process.working_directory': ['C:\\Users\\elastic\\'], + 'event.type': ['info', 'allowed'], + 'Events.process.hash.sha256': [ + 'de96a6e69944335375dc1ac238336066889d9ffc7d73628ef4fe1b1b160ab32c', + ], + 'Events.process.code_signature.exists': [true, true], + 'kibana.alert.rule.exceptions_list.id': ['endpoint_list'], + 'event.dataset': ['endpoint.alerts'], + 'kibana.alert.original_time': ['2023-08-30T09:54:18.074Z'], + }, + }, + { + _index: '.internal.alerts-security.alerts-default-000003', + _id: 'd53623e8fd0e343b4da7bbe856760e1f40a94b81ab1c2c2386409615757fccc4', + _score: 1, + fields: { + 'process.hash.md5': ['7353f60b1739074eb17c5f4dddefe239'], + 'host.os.full.text': ['Windows Server 2019 Datacenter 1809 (10.0.17763.4737)'], + 'kibana.alert.rule.updated_by': ['elastic'], + 'process.Ext.dll.Ext.mapped_size': [ + 458752, 2027520, 733184, 2740224, 647168, 802816, 114688, 655360, 1671168, 131072, 167936, + 1024000, 3321856, 1728512, 1171456, 532480, 684032, 651264, 1400832, 409600, 696320, 335872, + 69632, 40960, 11747328, 90112, 774144, 32768, 23453696, 13049856, 10964992, 688128, 110592, + 208896, 155648, 49152, 34283520, 688128, 21987328, 303104, 684032, 7630848, 143360, 380928, + 94208, 167936, 155648, 2113536, 73728, 389120, 507904, 655360, 1466368, 1466368, 9093120, + 49152, 118784, 290816, 2203648, 802816, 237568, 1929216, 323584, 2797568, 155648, 57344, + 331776, 139264, 9932800, 3588096, 446464, 49152, 1257472, 1372160, 401408, 897024, 323584, + 49152, 192512, 1253376, 13643776, 184320, 2314240, 249856, 811008, 32768, 90112, 114688, + 45056, + ], + 'host.os.name.text': ['Windows'], + 'kibana.alert.rule.rule_name_override': ['message'], + 'Ransomware.score': [30], + 'process.hash.sha256': ['de96a6e69944335375dc1ac238336066889d9ffc7d73628ef4fe1b1b160ab32c'], + 'host.hostname': ['siem-windows-endpoint'], + 'signal.original_event.created': ['2023-11-07T18:22:22.815Z'], + 'host.mac': ['42-01-0a-c8-00-1c'], + 'elastic.agent.id': ['9afa5fb9-7e83-4381-8cf3-f81f9259806c'], + 'signal.rule.enabled': ['true'], + 'host.os.version': ['1809 (10.0.17763.4737)'], + 'signal.rule.max_signals': [10000], + 'kibana.alert.risk_score': [73], + 'signal.rule.updated_at': ['2023-08-30T09:33:26.498Z'], + 'kibana.alert.original_event.id': ['NEze/ycl6FBijgcr+++1Vj+W'], + 'Ransomware.files.data': [ + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + '4C50BFD2DA6EF429A35DDE0C36567700', + ], + 'event.severity': [73], + 'host.os.type': ['windows'], + 'process.Ext.architecture': ['x86_64'], + 'signal.original_event.code': ['ransomware'], + 'kibana.alert.original_event.module': ['endpoint'], + 'kibana.alert.rule.interval': ['5m'], + 'kibana.alert.rule.type': ['query'], + 'process.Ext.dll.Ext.code_signature.subject_name': [ + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Windows', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Corporation', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + ], + 'kibana.alert.rule.immutable': ['true'], + 'kibana.alert.rule.exceptions_list.list_id': ['endpoint_list'], + 'kibana.alert.rule.version': ['102'], + 'process.command_line.text': [ + '"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" -ExecutionPolicy Bypass -NonInteractive -File C:\\Tools\\alerting\\mock_ransomware.ps1', + ], + 'signal.original_event.outcome': ['success'], + 'process.entity_id': [ + 'OWFmYTVmYjktN2U4My00MzgxLThjZjMtZjgxZjkyNTk4MDZjLTE1MDQtMTY5OTM4MTMxOS4xNDg0OTE1MDA=', + ], + 'process.parent.code_signature.status': ['trusted'], + 'host.ip': ['10.200.0.28', 'fe80::3219:dc81:cc1f:f4af', '127.0.0.1', '::1'], + 'agent.type': ['endpoint'], + 'process.executable.text': ['C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe'], + 'signal.original_event.category': ['malware', 'intrusion_detection', 'process', 'file'], + 'host.id': ['9b610e2b-5b2b-4a91-ab42-668d272ade50'], + 'process.parent.hash.sha256': [ + '2b105fb153b1bcd619b95028612b3a93c60b953eef6837d3bb0099e4207aaf6b', + ], + 'process.Ext.code_signature.subject_name': ['Microsoft Windows'], + 'Ransomware.files.path': [ + 'c:\\qatests\\ransomfiles_343912287\\1002960647_siem-windows-endpoint_sample.doc', + 'c:\\qatests\\ransomfiles_343912287\\1002960647_siem-windows-endpoint_sample.docx', + 'c:\\qatests\\ransomfiles_343912287\\1002960647_siem-windows-endpoint_sample.gif', + 'c:\\qatests\\ransomfiles_343912287\\1002960647_siem-windows-endpoint_sample.jpg', + 'c:\\qatests\\ransomfiles_343912287\\1002960647_siem-windows-endpoint_sample.pdf', + 'c:\\qatests\\ransomfiles_343912287\\1047785655_siem-windows-endpoint_sample.doc', + 'c:\\qatests\\ransomfiles_343912287\\1047785655_siem-windows-endpoint_sample.docx', + 'c:\\qatests\\ransomfiles_343912287\\1047785655_siem-windows-endpoint_sample.gif', + 'c:\\qatests\\ransomfiles_343912287\\1047785655_siem-windows-endpoint_sample.jpg', + 'c:\\qatests\\ransomfiles_343912287\\1047785655_siem-windows-endpoint_sample.pdf', + 'c:\\qatests\\ransomfiles_343912287\\1160308466_siem-windows-endpoint_sample.doc', + 'c:\\qatests\\ransomfiles_343912287\\1160308466_siem-windows-endpoint_sample.docx', + 'c:\\qatests\\ransomfiles_343912287\\1160308466_siem-windows-endpoint_sample.gif', + 'c:\\qatests\\ransomfiles_343912287\\1160308466_siem-windows-endpoint_sample.jpg', + 'c:\\qatests\\ransomfiles_343912287\\1160308466_siem-windows-endpoint_sample.pdf', + 'c:\\qatests\\ransomfiles_343912287\\1242872302_siem-windows-endpoint_sample.doc', + 'c:\\qatests\\ransomfiles_343912287\\1242872302_siem-windows-endpoint_sample.docx', + 'c:\\qatests\\ransomfiles_343912287\\1242872302_siem-windows-endpoint_sample.gif', + 'c:\\qatests\\ransomfiles_343912287\\1242872302_siem-windows-endpoint_sample.jpg', + 'c:\\qatests\\ransomfiles_343912287\\1242872302_siem-windows-endpoint_sample.pdf', + 'c:\\qatests\\ransomfiles_343912287\\1295912135_siem-windows-endpoint_sample.doc', + 'c:\\qatests\\ransomfiles_343912287\\1295912135_siem-windows-endpoint_sample.docx', + 'c:\\qatests\\ransomfiles_343912287\\1295912135_siem-windows-endpoint_sample.gif', + 'c:\\qatests\\ransomfiles_343912287\\1295912135_siem-windows-endpoint_sample.jpg', + ], + 'Ransomware.files.entropy': [ + 1.952240380956299, 1.952240380956299, 1.952240380956299, 1.952240380956299, + 1.952240380956299, 1.952240380956299, 1.952240380956299, 1.952240380956299, + 1.952240380956299, 1.952240380956299, 1.952240380956299, 1.952240380956299, + 1.952240380956299, 1.952240380956299, 1.952240380956299, 1.952240380956299, + 1.952240380956299, 1.952240380956299, 1.952240380956299, 1.952240380956299, + 1.952240380956299, 1.952240380956299, 1.952240380956299, 1.952240380956299, + ], + 'process.Ext.dll.name': [ + 'powershell.exe', + 'ntdll.dll', + 'KERNEL32.DLL', + 'KERNELBASE.dll', + 'msvcrt.dll', + 'OLEAUT32.dll', + 'ATL.DLL', + 'msvcp_win.dll', + 'USER32.dll', + 'win32u.dll', + 'GDI32.dll', + 'ucrtbase.dll', + 'combase.dll', + 'gdi32full.dll', + 'RPCRT4.dll', + 'bcryptPrimitives.dll', + 'ADVAPI32.dll', + 'sechost.dll', + 'OLE32.dll', + 'mscoree.dll', + 'mscoreei.dll', + 'SHLWAPI.dll', + 'kernel.appcore.dll', + 'VERSION.dll', + 'clr.dll', + 'VCRUNTIME140_CLR0400.dll', + 'ucrtbase_clr0400.dll', + 'psapi.dll', + 'mscorlib.ni.dll', + 'System.ni.dll', + 'System.Core.ni.dll', + 'Microsoft.PowerShell.ConsoleHost.ni.dll', + 'CRYPTSP.dll', + 'rsaenh.dll', + 'bcrypt.dll', + 'CRYPTBASE.dll', + 'System.Management.Automation.ni.dll', + 'clbcatq.dll', + 'shell32.dll', + 'cfgmgr32.dll', + 'shcore.dll', + 'windows.storage.dll', + 'profapi.dll', + 'powrprof.dll', + 'amsi.dll', + 'USERENV.dll', + 'wldp.dll', + 'CRYPT32.dll', + 'MSASN1.dll', + 'WINTRUST.dll', + 'MpOav.dll', + 'Microsoft.Management.Infrastructure.ni.dll', + 'System.Management.ni.dll', + 'System.DirectoryServices.ni.dll', + 'System.Xml.ni.dll', + 'MSISIP.DLL', + 'wshext.dll', + 'AppxSip.dll', + 'OpcServices.DLL', + 'tdh.dll', + 'XmlLite.dll', + 'urlmon.dll', + 'mintdh.dll', + 'iertutil.dll', + 'srvcli.dll', + 'netutils.dll', + 'System.Numerics.ni.dll', + 'gpapi.dll', + 'System.Data.ni.dll', + 'System.Data.dll', + 'WS2_32.dll', + 'pwrshsip.dll', + 'System.Configuration.ni.dll', + 'clrjit.dll', + 'Microsoft.PowerShell.Security.ni.dll', + 'System.Transactions.ni.dll', + 'System.Transactions.dll', + 'secur32.dll', + 'SSPICLI.DLL', + 'MPCLIENT.DLL', + 'Microsoft.PowerShell.Commands.Utility.ni.dll', + 'System.Configuration.Install.ni.dll', + 'Microsoft.PowerShell.Commands.Management.ni.dll', + 'iphlpapi.dll', + 'DNSAPI.dll', + 'NSI.dll', + 'dhcpcsvc6.DLL', + 'dhcpcsvc.DLL', + 'WINNSI.DLL', + ], + 'kibana.alert.rule.indices': ['logs-endpoint.alerts-*'], + 'host.os.Ext.variant': ['Windows Server 2019 Datacenter'], + 'signal.rule.updated_by': ['elastic'], + 'host.os.platform': ['windows'], + 'kibana.alert.rule.severity': ['medium'], + 'Endpoint.policy.applied.artifacts.user.identifiers.sha256': [ + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + 'b0e34b01c47f05134e43e662ccf1398ff0c3517d0ccf23ad47b54eead1e761b3', + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + 'b61f5e4a907f35a053547cdc4f1b23b524c63e5ecae31576b5422468224ea0b4', + ], + 'kibana.version': ['8.11.0-SNAPSHOT'], + 'event.id': ['NEze/ycl6FBijgcr+++1Vj+W'], + 'signal.ancestors.type': ['event'], + 'user.name.text': ['SYSTEM'], + 'kibana.alert.ancestors.id': ['cAAFq4sBrCLniDtDslEg'], + 'process.name.text': ['powershell.exe'], + 'host.os.full': ['Windows Server 2019 Datacenter 1809 (10.0.17763.4737)'], + 'process.parent.Ext.code_signature.trusted': [true], + 'kibana.alert.original_event.code': ['ransomware'], + 'Endpoint.policy.applied.artifacts.global.identifiers.name': [ + 'diagnostic-configuration-v1', + 'diagnostic-endpointpe-v4-blocklist', + 'diagnostic-endpointpe-v4-exceptionlist', + 'diagnostic-endpointpe-v4-model', + 'diagnostic-malware-signature-v1-windows', + 'diagnostic-ransomware-v1-windows', + 'diagnostic-rules-windows-v1', + 'endpointpe-v4-blocklist', + 'endpointpe-v4-exceptionlist', + 'endpointpe-v4-model', + 'global-configuration-v1', + 'global-eventfilterlist-windows-v1', + 'global-exceptionlist-windows', + 'global-trustlist-windows-v1', + 'production-malware-signature-v1-windows', + 'production-ransomware-v1-windows', + 'production-rules-windows-v1', + ], + 'kibana.alert.rule.description': [ + 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', + ], + 'kibana.alert.rule.producer': ['siem'], + 'kibana.alert.rule.to': ['now'], + 'Endpoint.policy.applied.artifacts.user.version': ['1.0.7'], + 'kibana.alert.original_event.ingested': ['2023-11-07T18:22:39.000Z'], + 'signal.rule.id': ['44a7f830-4718-11ee-a876-8955b5f07a55'], + 'rule.ruleset': ['production'], + 'signal.reason': [ + 'malware, intrusion_detection, process, file event with process powershell.exe, parent process svchost.exe, by SYSTEM on siem-windows-endpoint created high alert Ransomware Prevention Alert.', + ], + 'signal.rule.risk_score': [73], + 'user.risk.calculated_score_norm': [72.21453], + 'host.os.name': ['Windows'], + 'process.parent.Ext.code_signature.exists': [true], + 'signal.status': ['open'], + 'kibana.alert.rule.severity_mapping.value': ['21', '47', '73', '99'], + 'signal.rule.tags': ['Data Source: Elastic Defend'], + 'kibana.alert.rule.uuid': ['44a7f830-4718-11ee-a876-8955b5f07a55'], + 'kibana.alert.original_event.category': ['malware', 'intrusion_detection', 'process', 'file'], + 'signal.original_event.risk_score': [73], + 'process.name': ['powershell.exe'], + 'Ransomware.files.score': [ + 0, 0, 0, 0, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5, 1.5, + ], + 'process.parent.executable.text': ['C:\\Windows\\System32\\svchost.exe'], + 'kibana.alert.ancestors.index': ['.ds-logs-endpoint.alerts-default-2023.10.29-000003'], + 'process.Ext.code_signature.trusted': [true], + 'agent.version': ['8.10.3-SNAPSHOT'], + 'signal.original_event.severity': [73], + 'kibana.alert.rule.risk_score_mapping.operator': ['equals'], + 'host.os.family': ['windows'], + 'kibana.alert.rule.from': ['now-10m'], + 'kibana.alert.rule.parameters': [ + { + description: + 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', + risk_score: 47, + severity: 'medium', + license: 'Elastic License v2', + rule_name_override: 'message', + timestamp_override: 'event.ingested', + author: ['Elastic'], + false_positives: [], + from: 'now-10m', + rule_id: '9a1a2dae-0b5f-4c3d-8305-a268d404c306', + max_signals: 10000, + risk_score_mapping: [ + { + field: 'event.risk_score', + operator: 'equals', + value: '', + }, + ], + severity_mapping: [ + { + field: 'event.severity', + operator: 'equals', + severity: 'low', + value: '21', + }, + { + field: 'event.severity', + operator: 'equals', + severity: 'medium', + value: '47', + }, + { + field: 'event.severity', + operator: 'equals', + severity: 'high', + value: '73', + }, + { + field: 'event.severity', + operator: 'equals', + severity: 'critical', + value: '99', + }, + ], + threat: [], + to: 'now', + references: [], + version: 102, + exceptions_list: [ + { + id: 'endpoint_list', + list_id: 'endpoint_list', + namespace_type: 'agnostic', + type: 'endpoint', + }, + ], + immutable: true, + related_integrations: [ + { + package: 'endpoint', + version: '^8.2.0', + }, + ], + required_fields: [ + { + ecs: true, + name: 'event.kind', + type: 'keyword', + }, + { + ecs: true, + name: 'event.module', + type: 'keyword', + }, + ], + setup: '', + type: 'query', + language: 'kuery', + index: ['logs-endpoint.alerts-*'], + query: 'event.kind:alert and event.module:(endpoint and not endgame)\n', + }, + ], + 'signal.original_event.kind': ['alert'], + 'signal.depth': [1], + 'signal.rule.immutable': ['true'], + 'process.parent.name.text': ['svchost.exe'], + 'event.sequence': [19319894], + 'signal.rule.name': ['Ransomware Prevention Alert'], + 'event.module': ['endpoint'], + 'kibana.alert.rule.severity_mapping.operator': ['equals', 'equals', 'equals', 'equals'], + 'host.os.kernel': ['1809 (10.0.17763.4737)'], + 'process.parent.Ext.user': ['SYSTEM'], + 'process.Ext.dll.code_signature.subject_name': [ + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Corporation', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Windows', + 'Microsoft Corporation', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Corporation', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Corporation', + 'Microsoft Corporation', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + 'Microsoft Windows', + ], + 'kibana.alert.rule.license': ['Elastic License v2'], + 'kibana.alert.original_event.kind': ['alert'], + 'process.parent.command_line.text': [ + 'C:\\Windows\\system32\\svchost.exe -k netsvcs -p -s Schedule', + ], + 'Ransomware.feature': ['behavior'], + 'signal.rule.description': [ + 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', + ], + 'process.Ext.token.elevation_type': ['default'], + 'process.args': [ + 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', + '-ExecutionPolicy', + 'Bypass', + '-NonInteractive', + '-File', + 'C:\\Tools\\alerting\\mock_ransomware.ps1', + ], + 'process.parent.uptime': [5990501], + 'process.Ext.dll.path': [ + 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', + 'C:\\Windows\\SYSTEM32\\ntdll.dll', + 'C:\\Windows\\System32\\KERNEL32.DLL', + 'C:\\Windows\\System32\\KERNELBASE.dll', + 'C:\\Windows\\System32\\msvcrt.dll', + 'C:\\Windows\\System32\\OLEAUT32.dll', + 'C:\\Windows\\SYSTEM32\\ATL.DLL', + 'C:\\Windows\\System32\\msvcp_win.dll', + 'C:\\Windows\\System32\\USER32.dll', + 'C:\\Windows\\System32\\win32u.dll', + 'C:\\Windows\\System32\\GDI32.dll', + 'C:\\Windows\\System32\\ucrtbase.dll', + 'C:\\Windows\\System32\\combase.dll', + 'C:\\Windows\\System32\\gdi32full.dll', + 'C:\\Windows\\System32\\RPCRT4.dll', + 'C:\\Windows\\System32\\bcryptPrimitives.dll', + 'C:\\Windows\\System32\\ADVAPI32.dll', + 'C:\\Windows\\System32\\sechost.dll', + 'C:\\Windows\\System32\\OLE32.dll', + 'C:\\Windows\\SYSTEM32\\mscoree.dll', + 'C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\mscoreei.dll', + 'C:\\Windows\\System32\\SHLWAPI.dll', + 'C:\\Windows\\System32\\kernel.appcore.dll', + 'C:\\Windows\\SYSTEM32\\VERSION.dll', + 'C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\clr.dll', + 'C:\\Windows\\SYSTEM32\\VCRUNTIME140_CLR0400.dll', + 'C:\\Windows\\SYSTEM32\\ucrtbase_clr0400.dll', + 'C:\\Windows\\System32\\psapi.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\mscorlib\\4bc5e5252873c08797895d5b6fe6ddfd\\mscorlib.ni.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System\\98a55333af123511d40829217789091a\\System.ni.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Core\\28a91fc0413c5c5e8a3ae2eeba02e55f\\System.Core.ni.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\Microsoft.Pb378ec07#\\277f80b6dad2927932f711744560076d\\Microsoft.PowerShell.ConsoleHost.ni.dll', + 'C:\\Windows\\System32\\CRYPTSP.dll', + 'C:\\Windows\\system32\\rsaenh.dll', + 'C:\\Windows\\System32\\bcrypt.dll', + 'C:\\Windows\\SYSTEM32\\CRYPTBASE.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Manaa57fc8cc#\\1626b84d4e3d35507a575b9e5c45c967\\System.Management.Automation.ni.dll', + 'C:\\Windows\\System32\\clbcatq.dll', + 'C:\\Windows\\System32\\shell32.dll', + 'C:\\Windows\\System32\\cfgmgr32.dll', + 'C:\\Windows\\System32\\shcore.dll', + 'C:\\Windows\\System32\\windows.storage.dll', + 'C:\\Windows\\System32\\profapi.dll', + 'C:\\Windows\\System32\\powrprof.dll', + 'C:\\Windows\\SYSTEM32\\amsi.dll', + 'C:\\Windows\\SYSTEM32\\USERENV.dll', + 'C:\\Windows\\SYSTEM32\\wldp.dll', + 'C:\\Windows\\System32\\CRYPT32.dll', + 'C:\\Windows\\System32\\MSASN1.dll', + 'C:\\Windows\\System32\\WINTRUST.dll', + 'C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\4.18.23100.2009-0\\MpOav.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\Microsoft.Mf49f6405#\\6e7f7fc9cfebd148f1725a40bf43904d\\Microsoft.Management.Infrastructure.ni.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Management\\a138c7caf02ae4ab2d2f415dcfee7712\\System.Management.ni.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Dired13b18a9#\\bf686c6ebc51b987b3bb2e0021a0981f\\System.DirectoryServices.ni.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Xml\\8552125c25481eff4f470d3a02ed681d\\System.Xml.ni.dll', + 'C:\\Windows\\System32\\MSISIP.DLL', + 'C:\\Windows\\System32\\wshext.dll', + 'C:\\Windows\\System32\\AppxSip.dll', + 'C:\\Windows\\SYSTEM32\\OpcServices.DLL', + 'C:\\Windows\\SYSTEM32\\tdh.dll', + 'C:\\Windows\\SYSTEM32\\XmlLite.dll', + 'C:\\Windows\\SYSTEM32\\urlmon.dll', + 'C:\\Windows\\SYSTEM32\\mintdh.dll', + 'C:\\Windows\\SYSTEM32\\iertutil.dll', + 'C:\\Windows\\SYSTEM32\\srvcli.dll', + 'C:\\Windows\\SYSTEM32\\netutils.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Numerics\\231b6b3f9d9dd6d045c8e0c4d3e9a41a\\System.Numerics.ni.dll', + 'C:\\Windows\\SYSTEM32\\gpapi.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Data\\b0f6caebd2d7deb8701436e2f6189928\\System.Data.ni.dll', + 'C:\\Windows\\Microsoft.Net\\assembly\\GAC_64\\System.Data\\v4.0_4.0.0.0__b77a5c561934e089\\System.Data.dll', + 'C:\\Windows\\System32\\WS2_32.dll', + 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\pwrshsip.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Configuration\\5fcb3cceec8047f65a893687ea45807a\\System.Configuration.ni.dll', + 'C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\clrjit.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\Microsoft.P6f792626#\\1ae33e5b7b0ed0f9162b9c8877aea85d\\Microsoft.PowerShell.Security.ni.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Transactions\\dca546170c3feac83bf7208be1c114ac\\System.Transactions.ni.dll', + 'C:\\Windows\\Microsoft.Net\\assembly\\GAC_64\\System.Transactions\\v4.0_4.0.0.0__b77a5c561934e089\\System.Transactions.dll', + 'C:\\Windows\\SYSTEM32\\secur32.dll', + 'C:\\Windows\\SYSTEM32\\SSPICLI.DLL', + 'C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\4.18.23100.2009-0\\MPCLIENT.DLL', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\Microsoft.P521220ea#\\48ed92918fa397725c9e67698aa551b9\\Microsoft.PowerShell.Commands.Utility.ni.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\System.Confe64a9051#\\1b9fcf120b13cc063f8d3f8e52f1ba8a\\System.Configuration.Install.ni.dll', + 'C:\\Windows\\assembly\\NativeImages_v4.0.30319_64\\Microsoft.Pae3498d9#\\ee0242889d34fc0a39cda5c3a454483a\\Microsoft.PowerShell.Commands.Management.ni.dll', + 'C:\\Windows\\SYSTEM32\\iphlpapi.dll', + 'C:\\Windows\\SYSTEM32\\DNSAPI.dll', + 'C:\\Windows\\System32\\NSI.dll', + 'C:\\Windows\\SYSTEM32\\dhcpcsvc6.DLL', + 'C:\\Windows\\SYSTEM32\\dhcpcsvc.DLL', + 'C:\\Windows\\SYSTEM32\\WINNSI.DLL', + ], + message: ['Ransomware Prevention Alert'], + 'process.parent.hash.sha1': ['582cfae3826871dbfbadd179fb80a693694387fd'], + 'kibana.alert.original_event.outcome': ['success'], + 'kibana.alert.original_event.sequence': [19319894], + 'process.Ext.user': ['SYSTEM'], + 'kibana.alert.rule.exceptions_list.namespace_type': ['agnostic'], + 'kibana.space_ids': ['default'], + 'kibana.alert.severity': ['high'], + 'process.Ext.dll.code_signature.status': [ + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + ], + 'signal.ancestors.depth': [0], + 'event.category': ['malware', 'intrusion_detection', 'process', 'file'], + 'host.risk.calculated_score_norm': [72.258484], + 'Endpoint.policy.applied.artifacts.global.identifiers.sha256': [ + '2be4541e338528477b119c2ec50e7abdb638b093591e95c17e1db4132621b39e', + '17d8695f22d3817c426a0e08a477b88ecdb6088bc253dfbccc760224600afcfd', + 'e899eb51199bd145c2f9af25429aebee73790fe33d2f6ceada8d2659554887ba', + 'c01842ec8a5f29b3780162b8251da3caa913b1c493877a4ce9a77bce9464ce21', + '563a9106d2d895302935f8a6545961062c083214a3e5b66aadad1b0145bdba64', + 'cb611e8d2bdb3a9e87e34fc395f3e5b420ed41c1bd6624cb400e1869dd965f75', + '7129b458a4d87d63588605f577145fbf808a8f936e49fecfa2c057d16f0c9f60', + 'f864be0d57a9b43915bc20521c9168cad6984aeca5e3b08a755ea1b9559384d7', + '3313389ef04d17bbd995b5394b1e25555d76db295a59b69dc8b289ee3d4a022f', + '1faaa8f819d6b224fd9ffd48fc8fdf0891fb8ec720e9f108439dc616db53dd10', + 'c270b23fefad7d85c77ef604b7db3e3a8ef1853ba4abfb9a08b51cdfc8665d08', + '6815da3fe249428c5bc6f78eae18878affb173619d45ea1dbb540a0625b32121', + 'e42945d9b870c93a827dd6157765d96620943d494b98ea8935a6f66473d270ac', + 'bb457a407544d2e8156be689eb460e0de93b1d3d1d9f1e431ecf41065a58286f', + '08418b42390837b9aeec5099df4ab63394a7d32118a30922ff57c75c71a55d63', + 'b35d822a94e6e9129c9c736474bac0e95ebde2b11bc33d0c6e0311cd33152218', + 'be788888a04e9fe92590d86cfc9b4dd4ca4da29ea75a6259b537edb1136e861b', + ], + 'process.parent.command_line': [ + 'C:\\Windows\\system32\\svchost.exe -k netsvcs -p -s Schedule', + ], + 'process.parent.name': ['svchost.exe'], + 'process.parent.pid': [1704], + 'kibana.alert.original_event.risk_score': [73], + 'kibana.alert.rule.tags': ['Data Source: Elastic Defend'], + 'process.code_signature.exists': [true], + 'kibana.alert.ancestors.depth': [0], + 'kibana.alert.rule.severity_mapping.severity': ['low', 'medium', 'high', 'critical'], + 'agent.build.original': [ + 'version: 8.10.3-SNAPSHOT, compiled: Sat Sep 23 01:00:00 2023, branch: HEAD, commit: 143a4099b8be01d6efb900247c6b65a3b2f9e7fc', + ], + 'event.agent_id_status': ['verified'], + 'event.outcome': ['success'], + 'process.parent.Ext.code_signature.subject_name': ['Microsoft Windows Publisher'], + 'process.Ext.dll.Ext.code_signature.trusted': [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + ], + 'Ransomware.files.metrics': [ + 'HEADER_MISMATCH', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + 'HEADER_MISMATCH', + 'HEADER_MISMATCH_EXTENSIONS_THRESHOLD_MET', + ], + 'kibana.alert.rule.risk_score_mapping.value': [''], + 'process.Ext.ancestry': [ + 'OWFmYTVmYjktN2U4My00MzgxLThjZjMtZjgxZjkyNTk4MDZjLTE3MDQtMTY5MzM5MDg0MS43NzAwOTAxMDA=', + 'OWFmYTVmYjktN2U4My00MzgxLThjZjMtZjgxZjkyNTk4MDZjLTY0NC0xNjkzMzkwODMyLjEwOTA0OTAwMA==', + 'OWFmYTVmYjktN2U4My00MzgxLThjZjMtZjgxZjkyNTk4MDZjLTUzMi0xNjkzMzkwODMxLjI5Nzk2MzAwMA==', + ], + 'process.parent.start': ['2023-08-30T10:20:41.770Z'], + 'signal.original_event.sequence': [19319894], + 'event.risk_score': [73], + 'host.architecture': ['x86_64'], + 'process.Ext.dll.code_signature.exists': [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + ], + 'kibana.alert.start': ['2023-11-07T18:23:38.709Z'], + 'process.Ext.code_signature.status': ['trusted'], + 'event.code': ['ransomware'], + 'kibana.alert.original_event.type': ['info', 'start', 'change', 'denied'], + 'agent.id': ['9afa5fb9-7e83-4381-8cf3-f81f9259806c'], + 'signal.original_event.module': ['endpoint'], + 'process.parent.code_signature.trusted': [true], + 'signal.rule.from': ['now-10m'], + 'kibana.alert.rule.exceptions_list.type': ['endpoint'], + 'process.Ext.token.domain': ['NT AUTHORITY'], + 'kibana.alert.rule.enabled': ['true'], + 'process.Ext.dll.Ext.mapped_address': [ + 140698113736704, 140715405803520, 140715400626176, 140715349704704, 140715385815040, + 140715401412608, 140715244978176, 140715356520448, 140715396366336, 140715352457216, + 140715361894400, 140715339218944, 140715358552064, 140715352588288, 140715392499712, + 140715357175808, 140715403116544, 140715398070272, 140715394400256, 140715083825152, + 140715083104256, 140715392106496, 140715338366976, 140715201593344, 140715017961472, + 140715159519232, 140715080744960, 140715398922240, 140714940039168, 140714877976576, + 140715053416448, 140715080024064, 140715348262912, 140715325194240, 140715349508096, + 140715331813376, 140714843635712, 140715393679360, 140715363794944, 140715347935232, + 140715357765632, 140715340267520, 140715339022336, 140715338629120, 140715159388160, + 140715337318400, 140715332403200, 140715354357760, 140715338498048, 140715348393984, + 140715079499776, 140715076681728, 140715048173568, 140715046666240, 140714930929664, + 140715158994944, 140715158863872, 140715102240768, 140715044438016, 140715320016896, + 140715223744512, 140715214176256, 140715318181888, 140715177934848, 140715189272576, + 140715327946752, 140715076288512, 140715317788672, 140714909433856, 140715036442624, + 140715402264576, 140715142676480, 140715074650112, 140715043061760, 140715042603008, + 140715041685504, 140715053088768, 140715209785344, 140715337515008, 140715051712512, + 140714829938688, 140715094245376, 140715032313856, 140715326832640, 140715327094784, + 140715358486528, 140715264311296, 140715262345216, 140715273093120, + ], + 'Ransomware.version': ['1.7.1'], + 'kibana.alert.ancestors.type': ['event'], + 'signal.ancestors.index': ['.ds-logs-endpoint.alerts-default-2023.10.29-000003'], + 'user.name': ['SYSTEM'], + 'Endpoint.policy.applied.artifacts.global.version': ['1.0.795'], + 'signal.original_event.id': ['NEze/ycl6FBijgcr+++1Vj+W'], + 'process.uptime': [23], + 'user.domain': ['NT AUTHORITY'], + 'process.parent.Ext.architecture': ['x86_64'], + 'process.Ext.token.integrity_level_name': ['system'], + 'signal.original_event.type': ['info', 'start', 'change', 'denied'], + 'process.parent.hash.md5': ['4dd18f001ac31d5f48f50f99e4aa1761'], + 'kibana.alert.rule.max_signals': [10000], + 'signal.rule.author': ['Elastic'], + 'kibana.alert.rule.risk_score': [47], + 'process.Ext.token.sid': ['S-1-5-18'], + 'Ransomware.files.extension': [ + 'doc', + 'docx', + 'gif', + 'jpg', + 'pdf', + 'doc', + 'docx', + 'gif', + 'jpg', + 'pdf', + 'doc', + 'docx', + 'gif', + 'jpg', + 'pdf', + 'doc', + 'docx', + 'gif', + 'jpg', + 'pdf', + 'doc', + 'docx', + 'gif', + 'jpg', + ], + 'process.code_signature.status': ['trusted'], + 'signal.original_event.dataset': ['endpoint.alerts'], + 'kibana.alert.rule.consumer': ['siem'], + 'kibana.alert.rule.category': ['Custom Query Rule'], + 'process.Ext.dll.code_signature.trusted': [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + ], + 'event.action': ['files-encrypted'], + 'event.ingested': ['2023-11-07T18:22:39.000Z'], + 'process.Ext.dll.Ext.code_signature.status': [ + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + 'trusted', + ], + '@timestamp': ['2023-11-07T18:23:38.681Z'], + 'kibana.alert.original_event.action': ['files-encrypted'], + 'kibana.alert.original_event.agent_id_status': ['verified'], + 'data_stream.dataset': ['endpoint.alerts'], + 'signal.rule.timestamp_override': ['event.ingested'], + 'host.risk.calculated_level': ['High'], + 'kibana.alert.rule.execution.uuid': ['36f40fa3-1f69-4ad3-8d77-b95a4156e5a4'], + 'kibana.alert.uuid': ['d53623e8fd0e343b4da7bbe856760e1f40a94b81ab1c2c2386409615757fccc4'], + 'process.hash.sha1': ['6cbce4a295c163791b60fc23d285e6d84f28ee4c'], + 'Endpoint.policy.applied.artifacts.user.identifiers.name': [ + 'endpoint-blocklist-windows-v1', + 'endpoint-eventfilterlist-windows-v1', + 'endpoint-exceptionlist-windows-v1', + 'endpoint-hostisolationexceptionlist-windows-v1', + 'endpoint-trustlist-windows-v1', + ], + 'signal.rule.license': ['Elastic License v2'], + 'kibana.alert.rule.rule_id': ['9a1a2dae-0b5f-4c3d-8305-a268d404c306'], + 'signal.rule.type': ['query'], + 'signal.rule.rule_name_override': ['message'], + 'kibana.alert.url': [ + 'https://kibana.siem.estc.dev/app/security/alerts/redirect/d53623e8fd0e343b4da7bbe856760e1f40a94b81ab1c2c2386409615757fccc4?index=.alerts-security.alerts-default×tamp=2023-11-07T18:23:38.681Z', + ], + 'user.risk.calculated_level': ['High'], + 'kibana.alert.rule.risk_score_mapping.field': ['event.risk_score'], + 'process.pid': [1504], + 'signal.rule.created_by': ['elastic'], + 'signal.rule.interval': ['5m'], + 'kibana.alert.rule.created_by': ['elastic'], + 'kibana.alert.rule.timestamp_override': ['event.ingested'], + 'process.code_signature.subject_name': ['Microsoft Windows'], + 'process.parent.entity_id': [ + 'OWFmYTVmYjktN2U4My00MzgxLThjZjMtZjgxZjkyNTk4MDZjLTE3MDQtMTY5MzM5MDg0MS43NzAwOTAxMDA=', + ], + 'kibana.alert.rule.name': ['Ransomware Prevention Alert'], + 'process.parent.Ext.code_signature.status': ['trusted'], + 'host.name': ['siem-windows-endpoint'], + 'event.kind': ['signal'], + 'process.Ext.protection': [''], + 'process.code_signature.trusted': [true], + 'signal.rule.created_at': ['2023-08-30T09:33:26.498Z'], + 'kibana.alert.workflow_status': ['open'], + 'kibana.alert.original_event.created': ['2023-11-07T18:22:22.815Z'], + 'kibana.alert.reason': [ + 'malware, intrusion_detection, process, file event with process powershell.exe, parent process svchost.exe, by SYSTEM on siem-windows-endpoint created high alert Ransomware Prevention Alert.', + ], + 'process.parent.args_count': [6], + 'data_stream.type': ['logs'], + 'process.Ext.dll.hash.md5': [ + '7353f60b1739074eb17c5f4dddefe239', + '022d546dbb73745fca8e0c8dc8442f93', + 'd5fad1cc387c31792b8fcae48ffea669', + 'b9fa0cc56e322f5550485b1483ccd805', + 'dd0349151478b48ffce769b50f8cdd33', + '1656f11a45579c55c90509ed7c4d9fa3', + 'c5374f765d9f27d8340d4b900722ff2b', + '967b050da2325cd7bc8f7b5a3eed70ed', + '1324e381194a9d55b888a29340469737', + 'dbc76713d70e2c48d334a7b6f41d06a1', + '4e1eb455e3fa0a19d49c32195dcee0c7', + '3c72fc810602812d8c03c8709519f115', + 'd84dab37c23bd942fdf4187090978ea8', + '7b0783c238226d2e148a06c0a7c5d1e2', + '03b7b079ce91ea347c3130e2fad85c26', + '26b511a8f9f8c934c9dbf327d485302a', + 'cbaadb49c1554e7d66ea44c6aeb11022', + '6d08ef2d650929b939ed3e6303604320', + '64674fca830a3326763948c2ffd7bd38', + 'a54e980e453ed712a6ecf639ca70f4db', + '899a8b655e52a061b33571d97c5c06ed', + 'e58ee3e50737e12ec7ba130158c62358', + '56753185d301d7718470a4adf780395b', + '5719b3abd0fc28e1284f2515ae17613a', + '22ab1a308b532de7ea2be4b5876b2da7', + '63936588122bdee9624d02ce3f8f54ea', + 'f8f171be1820544e15b555847005355c', + '07a2782251672ac335122a8bd0f498f1', + 'ae052d2f216cdf6a691a6982a502e694', + '56da5d2dafab970271d8856d22925d8c', + '9c466db1ff712133814e50a2ecd0921c', + 'f1ba87428e22a34c0c4b87887961dc40', + 'a30d4cc791292c3179f947669e41a1f2', + '54a0ff27c8bd30f18329b1bd040bdf88', + 'c8e1cb92aa7795566f8c906c7beb1c40', + '40349c0cc1a2d08e9e5fff65296e29df', + '84ee0c7c1b8612788f8db31d67382e76', + 'c8661bc60695b6ee94d5c3e3799ec9b2', + 'b8a4add0f1ad2461015d7c2de27ee10d', + '02411b2016d3a537759143033c2d3aa6', + '92ca6eedf7a48b436a1a5bdad951f03f', + 'c123f87e851921094c581c968b79e018', + 'fae2639927642d1e061cccedcc4e199f', + '082136dc077fad6c3d1ed64bf46888a6', + '1612156ec38e45657df29d719a728151', + '1996f05c22f775f207ffffdc87040701', + 'ea91a2a05c29cb927470ad4e6d07d38c', + 'd1420a761be8daf245f939d0fede126b', + '968f1e635bca4d966f3c43df10dec251', + 'd18d57883fb35f6a815f607d797f881d', + 'e8ea978a581e6c3a616e69939cb2f5f3', + 'a116ee20fcd33183a993bb68d6119c61', + '144571fde3f4f0062a7b76b734783c87', + '2d3120b34fe74de582edbe8b617829cf', + '333e2bb28cf870bc6d5d820555a5595a', + '0e4355ced5e70efa748ffc16db824a76', + '4f3d6149b191973e026db111e4f5900b', + 'c480f1cd2ccce6442be03d079539b12d', + 'd63b993092b8e9b1cb85a18278a8db63', + '647b11240db64e0b534d84907194e930', + '8594c4992aebf839c5d5af4858dff34c', + 'cd6b6baa121a123526f6b671c6a5de97', + '7f670d780993d32ddce86d4dc0791871', + '36f51283cd3fd36806d304a314f2a965', + '8d70eeedff9f4059635c4ab5ce15e16c', + '6bd99b341b0749cd702ef46b372ab2aa', + '8e764a0390bf0b3f5053b947fa96da14', + '2eb45b900f292de4c666ef3152b56088', + '4538e0ffe47a276ebf7c603e348a384a', + '2679e12f6efdc8534dbb904a89a325a9', + '464de82e2b728c26ab939314c5b7ab6e', + '9390fcd2ab50184198f9f1332af9f858', + 'bd149ebdb62419a881c4ba15d536e686', + '3d652ccf232e9f387d465d2f8df9604b', + '9e9636b1eb8088c4fbe76a654b003f49', + 'f211402b87af8efa3b4612238f2459f4', + 'd17e11ddf716089af736dba7c4f24c75', + '6e13163214c64bd6453fbe3af96f8944', + 'c04d99156049f345f59f065ae32d63b1', + 'f6241aa123b9835add945b91d3805629', + '6514f3deaaeaa852d83f65ae69ea64e5', + 'ea5666d57836ec1cb667102a5346f0d8', + '790a3f64d8b2c297c189ccf6423c0635', + '45a39ec9e8e2bf99955bc54be23171df', + 'af88adbe5a272bfdf978f705dff09d23', + 'b483730f4a3ada6df69673f01583b920', + 'b22fccd84e5cb52c0f6e88f40ac90714', + '21fd42b403a9ea5d9f95384952d2c5af', + '9061e02072e5aa9862baab295227470e', + ], + 'process.Ext.token.user': ['SYSTEM'], + 'signal.ancestors.id': ['cAAFq4sBrCLniDtDslEg'], + 'signal.original_time': ['2023-11-07T18:22:22.815Z'], + 'process.Ext.dll.hash.sha256': [ + 'de96a6e69944335375dc1ac238336066889d9ffc7d73628ef4fe1b1b160ab32c', + 'a98bcce1593eb73aad555e997979372fdca42384895662344b0dcfc2b9673a2e', + '2cf87abc6e3bf27da4f199f16a2037532751c775278ed4e287a49a8b12380fd2', + 'faaad9e40ad9dc1179d149e204787af6f87643d81559f4d23a224d249f405f0e', + '39095fe07ac2e244e2180c58bec2898a0986dda2bd2abbc4f739d11e67720f2e', + '41f981261699ed029a452b034aadf0c3eecb9d48f9c35d5b4a139328eb7c1520', + '43b1a0da0e8dbe27df40ad0cb39af517fc5e5c86f18667c02e54b0983321e1bc', + '2e365914142b4c0f8340594e253e8fa25f452338238b87e7d303af89d0747d78', + '255a5f0b04c2ca9db61c8a9fc45733420c1fc3a554a9f5deebd15aa4b21bb049', + '0be65aacd7fbb7c099681090ec84e0ffc4d14526b5609eb4ce0ebc85fd281951', + 'f925ad101307bc127a71d0ddaf93b30b32ba46550abcf6d32fe86c033eef3b5c', + 'da572f7c674178ba7b91f7d47643fed07f7e71dbb4aeb46e1671ce08d1b31d73', + '1e610f1499d7eef55c132ac782ed9593fa387fedec8610c088d711232576e77b', + 'b6b42abd82be6ea93a1710e199375a03e93868f6acfcb3f8e87f270ef4c813dd', + 'c8a54e2d30faaba0dadef19fe975a12d83f8c7581e6199dbbc3ade84552e4d87', + '45860819125c24fa624ac60fe3caef95f89459a0bc78f3667039eb67eee62e41', + '68d6d3796dab0693908dd3b092ecd89d189333eccbe85934011d8def5ca70a75', + 'dde582049178f4e5b06b6a8385f5d3d44c5168deaa5324d310a0c96eac38be1e', + 'f81ed819ac599db818e604f532b61c2c89edb81697544126307d177bee738a0c', + '10693c68d86a71a73fd9bd6cb7497beae746ba5ea8a044e5c7b6294f4ee5445e', + 'de05b03e37fb9ba5d74cf8fa36a6f0b15ab61705285b738bc90d14fde580a45e', + '0c81e34b8f06cbf00cb39433abc0378d4b2ef355fb87676df9d95c63b02df8f4', + 'ca954ac516f91f28301378214335ff808d0e9331018a6474dfaa25d18d0fd6a8', + '5b4c567dfd75eeb75cd4d59436e748aa14ec9f9fc7655f915093813332e93ab4', + '4f2506779cec605222b3262ab3ed36e204a3335818dcdb9a8be42bfc769003a0', + '21f7e6165ce8dd92db8cdf48cee83de64b2b0807b7b499cf87678b70c6f8c32f', + 'cddf9a2bf085ae59ba464b3ba6394aacfc342da5f17d77fd5306054c8aabf153', + '10b640aeeb310263d5418f65ec05e6127f2c224c0ac837e71816d03db207c510', + '203ce5c13619ef9869f2ab148e56a7d8a698aa8ee5d3cbe99623ddf23b18084b', + '232b8332e96b334937c9c36a652359f996a6982a3899cab45668a7c8d2597deb', + 'e658a09fa99ece447b45e3c7af16aa50bc53e511a57ba133d60408ff1787e3ff', + '9e2c7ddfb5e5fe5d0ff4bc7bef0e0baf0cdfb41d752e0506620385e916bf7713', + '6f417ca279d1e16b0b272e5074f5caea39a60a3e59dca25c36f3d8e99e90ab9e', + 'fc35ca276b82201d28336f64f2a09d659688bc64d91b8f50da79493da1453fce', + '0aabf5c66ffdaa29d3747b9b2600dc279aca7637b7916774ba4f191ca8ab382f', + 'f53c04cf0ee4943d4ea82d94604cb46816beb53545d3357c718d2a46516b1bdb', + '351c4038f8f670329bb2799d7831c0d727a649d4d2834403bff5477a74b36504', + '88f6990160ac38748ecb8ed3b9717d2ee396114dd9f36dfb9527d6b9a0b2acd6', + '6fe1c35cda859d05d20bd0a4d53d4d7e4bf9afccdbe62ecc353b02d5705d6683', + 'df1c3927c42a1c7b8b5ea009783bb3fcb1ff48fc8542a1ef5d18ecaf78ad5d3e', + '9619ca45ddd2467a04f262e1df633c138c8ebb93a46697caafa42db331ad1784', + '4579f9d3026095f264f8b3e49c1c49b2f08a3425fc29777b4021f14b6a07bee5', + 'bb809badb59326c12dae7998ba7035a15016639e35dc92b8fbb4e404e79c25a2', + 'f9c97cffab7d3a61175f902cf0062ca945bc8cecfc825bf3b6096864855d43d9', + '8c76b13cc54ac83d3639cbf5b15fb6e9be3018d0740d7b15a98cb1bc5b95dae8', + 'dd74efb99d66ad0fea891583af3128e4a9068ef8bc073409b5ab6fc61f940553', + 'fff9892d63f4775c0c61b667fbfa534ad31627379a96b91d9b12606526577ac9', + '2fa1b3e19047257271ffea36ad6cad8f01ccc55326c276533270977519ac310e', + 'f70b342004d628f3f3186dc4bd131eb6450725b6d5b53d331611076ea07dbbc0', + 'ef2aff60865d72cf8cfa58077cc5347cf4d4aea04a3ed7aeb08da93ee7d55245', + '077043850436f281bb354d03a7f33042543e7c2bf4f46a865bae60f37d8debdb', + 'fb7d4533765faf519aff7d36bd88d993a4a722c6892efa46108ae1c92b13b093', + '4c65ecc3db58b1642d142bc40658cb14c75fd93a519193051aa07a2655a84013', + '4a084ed091d8c2fad77843aa65805038d059d2be0bde1473049dd89d85647929', + 'b8cd365205c8fd690f334b31b929c15f135d6102ef91e7b1672b575a9e956a45', + '93bc31bf5629c8adb97862c5f93f28910b866a2d4f1e8f2baf128c7e52b0e14e', + '9730a98e0806478281efefc1df41bec9e6b64ee4fa755dc2118866e40f4c6c11', + '953c4a6c311da9aca25f5f23e3c689ce3b0934b14b787b236709159f956e5bc7', + 'f4a82fa21192e74802058888ef278f25c86967dae4b87d47331bb5e4ae28edd5', + '68d13f7b3c19d4df8790e60ac76a1731bbfdf1b29efba6c934987fb2fdc86d26', + '9c51ec1791e80b4445e5ec08bef746690139d5432cd4ba10cb485911b295eeed', + '87f1d8bfef9a604f1a39e187a875cbb4ae0ff25e8c2548d21d588926669cf972', + '0d6a5da4b9b84e01d5b03645f14221b23fa2523d65219c163a9da4b0cfcd6757', + 'a1acb31a6a9014d4c3c4346f0b277e3bd87acccfb20040a0a5ba3f877f80d22e', + '063ec2d785b90eb74c5e23dd25fbf8a32493cef995113c5a970708a6da44e8f2', + 'fa48ddb46aa0b5cd64ac0d9feba77a94cf0a0da554acb9dc9c80fb8104414c2d', + '74e8f44863acb0a40fed8f357cf9216cef2ab08d4b1eb588c686ab5bf7bfe116', + 'cd81fb3d9a8613270c274aabae1991da5db240f91e36589e10ac0cc12e3facc1', + 'af56205f18c10361a8d8317d59b133b23b5971ffad197116958b31ad61fcb68f', + '109105aedbd4698c332bfdb9d11c4cf70d739d304c2af69b1a0199698b0c3b16', + '2c5047e0b7daa607aa3971bd8c3e983297cede9c29dacf9c723bc253e288ced4', + 'db31fc3bcd2b327c3a281df9ec722016bbdb7f468398e29ce99705112dd90cea', + '937955f2117f21d52e57056ff9dbce98959fb2b79aa58cff7675608ae669cc5e', + '8abd9dd1c8b163154f52727f8c83e4ba75e4cb3ae147119f246769d3d8837262', + '0bb39a9d2d2eae945352993199054e5558ea22a33f74e96cf5ac57b27ae0894e', + 'cab6f6543c3951af049f80f6eeb0c2c7a910ef0bff341826b550a15c2078f6df', + 'df301f2f2a735a1a75eae79e64ccfdad335e319b98316e9e875f726fa2cb51d5', + '1cafa15cba7a29317359c6851292470e01b36ff92d9df2e2c9474c3b02036305', + '9a98f35f8bcb0c02cb86d979d93136f31027c055d1c4682e31b7a25a5dba19df', + '5cfa0acf6bd10fbeb3db7fb642ae68ebe9f9c01d9f49a6082d1432914e766c57', + 'ac211142521ca782c5deecbeee999ffe4b3bde522c89dcfc5c964bc9ee6583b3', + 'aab21d55ae02792e4511cda0ad517d406a047ae8e3a28a411a821185a605d307', + 'b0de497fc30a613893ce70353ec4eec7c216644a6055b8a8b9ec87eb2cd86814', + '0c7851c3c491fd7bdba0a4c97596c216565c92fe4216a631bcc5d7d530201a0f', + '698f40d1049316811ea447ce4869ef094b28bd07f6cf494cb1e49791acccec6e', + '7cabf50fb9087392cefb219ba17c6e10626663af6753c203ccf28b5cf09358e3', + 'a72b0b41a579fbc78915156ca0ebb579b8db82fc1151dc80037b273f62838846', + '4055fbe616ca16f2547d2f42d5a70164147fcc2d1b92f2772464bd882026fabd', + '2624fea2040ab5d42ef2fc6cd0085b415282434148f9aac5b96d1583dc56017b', + ], + 'ecs.version': ['1.11.0'], + 'signal.rule.severity': ['high'], + 'event.created': ['2023-11-07T18:22:22.815Z'], + 'process.Ext.dll.hash.sha1': [ + '6cbce4a295c163791b60fc23d285e6d84f28ee4c', + 'bb8837ca4b8527ea3f28a0b782a5ddf81690dc27', + 'ececa71f49ed67e90228bde3f527b298b7d40e1f', + '70ef8b379b14235a2aa042eea16c28dd0fc531d6', + 'eca51f7d37874cf1029bc2fe3b0cf0e8cdf71e8e', + 'e87ad0084ec10c3e7182e174821dcac6ab7c2500', + 'e6fba9bf33a757611329fb12d01ffc14d33553a6', + 'afb93defc8c6e399effc1d99bd719536a59e2510', + 'eb46488eb706320bad825d643bbfac70c6130481', + '94016e078788ed3fe316650624603dc40c4bf58c', + '9a39e386c82d0aa551bb1c784c63da727d9a686a', + '8956f79d95fe1eab1a06c4ad75588a49c2029994', + '2ea1edae5f99e358cce3a887dd47170914cd6c53', + '25d4e7573edb9b0f7e0e698ebd3fb0ab19c16a25', + '2c114eecf2f4d0498ccc5d53ce9675fcefc5e835', + '7a12b5700cf45af2473193fa0485ae62e3bc76f4', + 'f9a2313683b0d880e354af4eec928230b4227ab9', + 'c3709ee8eaa5c5114469b7128963c6d75111f06e', + '6066a43a30a8ec03441ea556a19d170fef45a66c', + 'c706d446be7ed725a720f59c039d6104aaebbc82', + '1283ef637fa53d571118f269f9b8c0a5cca2bf01', + '8abefda5348e43f65e1e3ca9bc78bc69fd379d8d', + '564655189dee96750d04cd9e05de1237ab30f49c', + 'd1f1344156c1f8431cf7350a09245455525359d4', + '9f3caaf393f92c586e0aa8cd0b8d2a69e3f29fdb', + '6790994b2e72e7fe8690cd8eba1fcf4577389280', + 'ff572be9c4959684f64cf1ead2636fe983e59627', + 'fb04164446aed512d628d35e1bb8408d44a30e0c', + '25a96da528fe6bb73e653dfebeaab2eef12a6bee', + '1fda63b3a719cfe53f298e3c1eaf4d09c6aa7d0f', + 'a71673d0014eb76ea1e1a242205e28cb699e5b79', + 'c73e8f219b5e2e525524f29ddccfddd2cf0503ce', + 'b127b6598e843d4b29f2a5c440b5b05606720b3a', + '849fdefc51337b60148d786131600a517817daad', + '53175583104b542ad149f870cc80f4743b5d3558', + '1a66610e0b793ee1510b93d26820e471ffede88c', + '0a32e394fd7a178bf04132b23dcd4fdfdf86dc17', + 'dcb773f9f978fdf8ad38030d3db14ec8bf6a5677', + '9d9e805f846605289a191ed11c6ce93c5e27f8fa', + '8130861654c05723bdab475587c7b4b131bd5ff6', + '8772849e8cbcaf8b53a36796b3d4dd4e7d3d49e0', + '69149f8f54cc94dbde681e2abbdb540e05cd2c95', + 'd91bc27398d9a25caea973a38360fecb71710f01', + 'c6be4dbbf31a2fd2a91fda8da0f7ed65b413d31a', + '20f7eed446e3ec3c74e7fadc04a99f695871597d', + '8ac9a864de60b752193495f9dfa684d40d5a5c6b', + 'cf33ccc83f0c7d99fca330e366fd6e4fb229b875', + '216de891d5b4ff0e3c429c48e40457588e215894', + '0e684a2625445b8d3988e7f037b323455f90a948', + 'c578dd97ec96f33c3b185b0fa309213422a05375', + 'e5e75a15ee46e0968665ff180c34880e163f27f0', + '43039addc25f5af93cd5feed2a4870bd37dfaf39', + '40e003ba4c5af1f2a7633cc975c762bcbbab4873', + '6ddc6a8175f15efa139072a0e403b9f98722b78e', + '4033dc8b89ba97387bfecb966eb5bd3a27df5c09', + 'f4ca83f2af84715bf9d6ba8d5a31d8aa43bc90f3', + 'ba785e1011f5a218f8ba3eae3d460efb046804f0', + 'e6541cc322d079118ede4c6451a8683a4ad95518', + '0e75a30e394c19b3290a31833a6d59c33c6eea13', + 'af5e42b893ef23f706b9f9753925bbff1e9ca363', + '9ef6511a1e22763424a7f130fdcc226b0701b897', + '24ad2d080dd8a7c83a49adce50265e8670713cfa', + '45882cabd6323e443cde5a6756540b3e6f493a94', + '24dd316d7895a0af1d2d2f558d5228b0d6a98ac1', + 'deb001070c06d8f43b4c697f200705d8f563850e', + 'bedead6f57891986f543b2d668a332de6d735cfc', + '3852c24bfb9314915e0770e296eee5c842cbd2f3', + 'cba2b235d7062af37c8d0bef85489f6a990a88ce', + 'dcff59f6a132a092a3326a303635b7d0a039c096', + '31501381a08f1b996c2da5d2e46d7b42d6e198a5', + '9994ea84bda917f1062209feb5cdab97e2a2e55f', + '3ccdd83bb369370431c039e74881f64a631a9158', + 'ea4e463b797064b69978f113a35580455093a90c', + '0ddb4aacd6f03a814faf4b9081a91fa14c613161', + '3d6d3270def499d165979c17e3b1c0eabb8024a3', + '13ab091ab4720852bdb6ce073ceb814bcfaf0ad6', + '2531ebab7925d379b5852fc57cca6efe0b343746', + 'd71861c344ec4070d494c0216d1efae59e755a5b', + '1b9289bd0dd5ccaabc755d2c2da94de5ee59a604', + '212a30c8880bb14fe79802a1b0492cae21d1b736', + 'de2e0efb576e7262fe011a37bbb4d66474ce12ab', + 'c3f143251ad20456ad34e819dba282b93dd9d926', + '59a6fdc3066d2b841af10ecba96089fba5d0b929', + '25a3353d89d794ca454f166ae627b60d76175e85', + 'ce0ab115fef8d1d0681494f0548496495772ab93', + '0da2b0816c3234a9fc77da1c7698869d88d8faa0', + '3ffdc5a9e2b7832ec0342b8b185a1f83a00f1d22', + '7c2cd88f8746b1cb4474d6bcc542667e6384f37a', + '7b7ef4e41c2db1b15c995b83b645d28f7f00a4c7', + ], + 'kibana.alert.depth': [1], + 'process.parent.ppid': [644], + 'process.Ext.dll.Ext.code_signature.exists': [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + ], + 'process.parent.Ext.protection': [''], + 'kibana.alert.rule.revision': [0], + 'process.start': ['2023-11-07T18:21:59.148Z'], + 'signal.rule.version': ['102'], + 'kibana.alert.status': ['active'], + 'kibana.alert.last_detected': ['2023-11-07T18:23:38.709Z'], + 'kibana.alert.rule.severity_mapping.field': [ + 'event.severity', + 'event.severity', + 'event.severity', + 'event.severity', + ], + 'kibana.alert.original_event.dataset': ['endpoint.alerts'], + 'process.parent.code_signature.exists': [true], + 'Ransomware.files.operation': [ + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + 'modification', + ], + 'kibana.alert.rule.rule_type_id': ['siem.queryRule'], + 'signal.rule.rule_id': ['9a1a2dae-0b5f-4c3d-8305-a268d404c306'], + 'process.executable': ['C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe'], + 'kibana.alert.original_event.severity': [73], + 'process.parent.code_signature.subject_name': ['Microsoft Windows Publisher'], + 'process.parent.executable': ['C:\\Windows\\System32\\svchost.exe'], + 'process.args_count': [6], + 'kibana.alert.rule.updated_at': ['2023-08-30T09:33:26.498Z'], + 'process.Ext.token.elevation': [true], + 'data_stream.namespace': ['default'], + 'kibana.alert.rule.author': ['Elastic'], + 'process.Ext.code_signature.exists': [true], + 'process.parent.args': [ + 'C:\\Windows\\system32\\svchost.exe', + '-k', + 'netsvcs', + '-p', + '-s', + 'Schedule', + ], + 'signal.original_event.action': ['files-encrypted'], + 'kibana.alert.rule.created_at': ['2023-08-30T09:33:26.498Z'], + 'signal.rule.to': ['now'], + 'event.type': ['info', 'start', 'change', 'denied'], + 'process.command_line': [ + '"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" -ExecutionPolicy Bypass -NonInteractive -File C:\\Tools\\alerting\\mock_ransomware.ps1', + ], + 'kibana.alert.rule.exceptions_list.id': ['endpoint_list'], + 'event.dataset': ['endpoint.alerts'], + 'kibana.alert.original_time': ['2023-11-07T18:22:22.815Z'], + }, + }, + { + _index: '.internal.alerts-security.alerts-default-000001', + _id: '07cce0b9b3d3b2c55ec61fa978159dd8c0bf5bce31ecdef67af3f29f502086d4', + _score: 1, + fields: { + 'kibana.alert.severity': ['critical'], + 'process.hash.md5': ['5b3cf2c0-16c0-4955-9736-66efd08ccb20'], + 'host.os.full.text': ['Windows 10'], + 'kibana.alert.rule.updated_by': ['elastic'], + 'signal.ancestors.depth': [0], + 'event.category': ['process'], + 'host.os.name.text': ['Windows'], + 'process.parent.pid': [3948], + 'host.hostname': ['Host-ffhve1li02'], + 'kibana.alert.rule.tags': ['test'], + 'host.mac': ['15-42-cb-8d-d6-c8'], + 'kibana.alert.rule.threat.technique.id': ['T1219'], + 'kibana.alert.ancestors.depth': [0], + 'signal.rule.enabled': ['true'], + 'host.os.version': ['10.0'], + 'signal.rule.max_signals': [100], + 'kibana.alert.risk_score': [99], + 'signal.rule.updated_at': ['2023-10-27T16:34:23.297Z'], + 'event.agent_id_status': ['auth_metadata_missing'], + 'kibana.alert.original_event.id': ['8f4fa153-d3a2-4112-b7a6-e46ed5b42086'], + 'event.outcome': [''], + 'process.Ext.ancestry': ['yybc8cgr8a', 'xpr211xjvm'], + 'kibana.alert.rule.interval': ['5m'], + 'kibana.alert.rule.type': ['query'], + 'signal.original_event.sequence': [29], + 'host.architecture': ['sls014vbcb'], + 'kibana.alert.start': ['2023-11-07T13:54:29.095Z'], + 'kibana.alert.rule.immutable': ['false'], + 'kibana.alert.original_event.type': ['start'], + 'agent.id': ['419413b4-cd07-41bf-9273-1c40a57d79b7'], + 'signal.rule.from': ['now-360s'], + 'process.group_leader.entity_id': ['qkngtu1ty9'], + 'kibana.alert.rule.enabled': ['true'], + 'kibana.alert.rule.version': ['2'], + 'kibana.alert.ancestors.type': ['event'], + 'process.session_leader.name.text': ['fake session'], + 'process.entry_leader.name': ['fake entry'], + 'signal.ancestors.index': ['.ds-logs-endpoint.events.process-default-2023.10.27-000001'], + 'user.name': ['05gdvfffaa'], + 'signal.original_event.outcome': [''], + 'process.working_directory': ['/home/05gdvfffaa/'], + 'process.entity_id': ['ys9391nvad'], + 'host.ip': ['10.185.21.68', '10.198.36.199'], + 'agent.type': ['endpoint'], + 'process.executable.text': ['C:\\mimikatz.exe'], + 'signal.original_event.category': ['process'], + 'signal.original_event.id': ['8f4fa153-d3a2-4112-b7a6-e46ed5b42086'], + 'signal.rule.threat.framework': ['MITRE ATT&CK'], + 'user.domain': ['fmm3zfw3c7'], + 'host.id': ['10f91578-370d-41b4-a806-fa80c591955f'], + 'signal.original_event.type': ['start'], + 'kibana.alert.rule.max_signals': [100], + 'process.working_directory.text': ['/home/05gdvfffaa/'], + 'kibana.alert.rule.risk_score': [99], + 'process.code_signature.status': ['trusted'], + 'signal.rule.threat.technique.id': ['T1219'], + 'kibana.alert.rule.consumer': ['siem'], + 'process.group_leader.name.text': ['fake leader'], + 'kibana.alert.rule.indices': [ + 'apm-*-transaction*', + 'traces-apm*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + 'kibana.alert.rule.category': ['Custom Query Rule'], + 'host.os.Ext.variant': ['Windows Pro'], + 'event.ingested': ['2023-11-07T13:50:44.000Z'], + '@timestamp': ['2023-11-07T13:54:29.030Z'], + 'signal.rule.updated_by': ['elastic'], + 'host.os.platform': ['Windows'], + 'process.session_leader.entity_id': ['qkngtu1ty9'], + 'kibana.alert.rule.severity': ['critical'], + 'kibana.alert.original_event.agent_id_status': ['auth_metadata_missing'], + 'data_stream.dataset': ['endpoint.events.process'], + 'signal.rule.threat.technique.reference': ['https://attack.mitre.org/techniques/T1219'], + 'kibana.alert.rule.execution.uuid': ['7afa7716-7dd3-4674-8d9f-31d231228197'], + 'kibana.alert.uuid': ['07cce0b9b3d3b2c55ec61fa978159dd8c0bf5bce31ecdef67af3f29f502086d4'], + 'kibana.alert.rule.meta.kibana_siem_app_url': ['http://localhost:5601/app/security'], + 'kibana.version': ['8.12.0'], + 'event.id': ['8f4fa153-d3a2-4112-b7a6-e46ed5b42086'], + 'process.entry_leader.pid': [397], + 'signal.rule.threat.technique.name': ['Remote Access Software'], + 'signal.rule.license': [''], + 'signal.ancestors.type': ['event'], + 'kibana.alert.rule.rule_id': ['36053388-4288-4de4-b9ec-9a0066812049'], + 'user.name.text': ['05gdvfffaa'], + 'process.session_leader.pid': [393], + 'signal.rule.type': ['query'], + 'kibana.alert.ancestors.id': ['WKsMqosB1rJhB-h4wsnG'], + 'process.name.text': ['mimikatz.exe'], + 'process.group_leader.name': ['fake leader'], + 'host.os.full': ['Windows 10'], + 'kibana.alert.rule.description': ['mimikatz process started'], + 'process.pid': [2157], + 'kibana.alert.rule.producer': ['siem'], + 'kibana.alert.rule.to': ['now'], + 'signal.rule.created_by': ['elastic'], + 'signal.rule.interval': ['5m'], + 'kibana.alert.rule.created_by': ['elastic'], + 'kibana.alert.original_event.ingested': ['2023-11-07T13:50:44.000Z'], + 'signal.rule.id': ['af876450-74e6-11ee-b0ed-29fb31c95fbe'], + 'process.code_signature.subject_name': ['Microsoft'], + 'process.parent.entity_id': ['yybc8cgr8a'], + 'signal.reason': [ + 'process event with process mimikatz.exe, by 05gdvfffaa on Host-ffhve1li02 created critical alert mimikatz process started.', + ], + 'signal.rule.risk_score': [99], + 'host.os.name': ['Windows'], + 'kibana.alert.rule.name': ['mimikatz process started'], + 'host.name': ['Host-ffhve1li02'], + 'kibana.alert.rule.threat.technique.reference': ['https://attack.mitre.org/techniques/T1219'], + 'signal.status': ['open'], + 'event.kind': ['signal'], + 'signal.rule.created_at': ['2023-10-27T16:34:23.297Z'], + 'signal.rule.tags': ['test'], + 'kibana.alert.workflow_status': ['open'], + 'kibana.alert.rule.threat.tactic.name': ['Command and Control'], + 'kibana.alert.rule.uuid': ['af876450-74e6-11ee-b0ed-29fb31c95fbe'], + 'kibana.alert.original_event.category': ['process'], + 'kibana.alert.reason': [ + 'process event with process mimikatz.exe, by 05gdvfffaa on Host-ffhve1li02 created critical alert mimikatz process started.', + ], + 'signal.rule.threat.tactic.id': ['TA0011'], + 'data_stream.type': ['logs'], + 'signal.ancestors.id': ['WKsMqosB1rJhB-h4wsnG'], + 'signal.original_time': ['2023-11-07T13:50:53.919Z'], + 'process.name': ['mimikatz.exe'], + 'ecs.version': ['1.4.0'], + 'signal.rule.severity': ['critical'], + 'kibana.alert.ancestors.index': [ + '.ds-logs-endpoint.events.process-default-2023.10.27-000001', + ], + 'process.entry_leader.name.text': ['fake entry'], + 'agent.version': ['8.12.0'], + 'kibana.alert.depth': [1], + 'host.os.family': ['windows'], + 'kibana.alert.rule.from': ['now-360s'], + 'kibana.alert.rule.parameters': [ + { + description: 'mimikatz process started', + risk_score: 99, + severity: 'critical', + license: '', + meta: { + from: '1m', + kibana_siem_app_url: 'http://localhost:5601/app/security', + }, + author: [], + false_positives: [], + from: 'now-360s', + rule_id: '36053388-4288-4de4-b9ec-9a0066812049', + max_signals: 100, + risk_score_mapping: [], + severity_mapping: [], + threat: [ + { + framework: 'MITRE ATT&CK', + tactic: { + id: 'TA0011', + name: 'Command and Control', + reference: 'https://attack.mitre.org/tactics/TA0011', + }, + technique: [ + { + id: 'T1219', + name: 'Remote Access Software', + reference: 'https://attack.mitre.org/techniques/T1219', + subtechnique: [], + }, + ], + }, + ], + to: 'now', + references: [], + version: 2, + exceptions_list: [], + immutable: false, + related_integrations: [], + required_fields: [], + setup: '', + type: 'query', + language: 'kuery', + index: [ + 'apm-*-transaction*', + 'traces-apm*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + query: + 'process.name: "mimikatz.exe" and event.category: "process" and event.type: "start"', + filters: [], + }, + ], + 'kibana.alert.rule.revision': [0], + 'kibana.alert.rule.threat.tactic.id': ['TA0011'], + 'signal.rule.version': ['2'], + 'signal.original_event.kind': ['event'], + 'kibana.alert.rule.threat.technique.name': ['Remote Access Software'], + 'kibana.alert.status': ['active'], + 'kibana.alert.last_detected': ['2023-11-07T13:54:29.095Z'], + 'signal.depth': [1], + 'signal.rule.immutable': ['false'], + 'process.group_leader.pid': [618], + 'event.sequence': [29], + 'kibana.alert.rule.rule_type_id': ['siem.queryRule'], + 'process.session_leader.name': ['fake session'], + 'signal.rule.name': ['mimikatz process started'], + 'signal.rule.rule_id': ['36053388-4288-4de4-b9ec-9a0066812049'], + 'signal.rule.threat.tactic.reference': ['https://attack.mitre.org/tactics/TA0011'], + 'kibana.alert.rule.license': [''], + 'kibana.alert.original_event.kind': ['event'], + 'process.executable': ['C:\\mimikatz.exe'], + 'process.entry_leader.start': ['1970-01-01T00:00:00.000Z'], + 'signal.rule.threat.tactic.name': ['Command and Control'], + 'kibana.alert.rule.threat.framework': ['MITRE ATT&CK'], + 'kibana.alert.rule.updated_at': ['2023-10-27T16:34:23.297Z'], + 'signal.rule.description': ['mimikatz process started'], + 'data_stream.namespace': ['default'], + 'process.args': ['"C:\\mimikatz.exe"', '--v30'], + 'kibana.alert.original_event.outcome': [''], + 'kibana.alert.original_event.sequence': [29], + 'kibana.alert.rule.threat.tactic.reference': ['https://attack.mitre.org/tactics/TA0011'], + 'kibana.alert.rule.created_at': ['2023-10-27T16:34:23.297Z'], + 'signal.rule.to': ['now'], + 'event.type': ['start'], + 'kibana.space_ids': ['default'], + 'process.entry_leader.entity_id': ['qkngtu1ty9'], + 'kibana.alert.rule.meta.from': ['1m'], + 'kibana.alert.original_time': ['2023-11-07T13:50:53.919Z'], + }, + }, +]; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts index 7db042a9c9cf0..4dbc0fb53fc0d 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts @@ -16,7 +16,6 @@ import { langChainMessages } from '../../../__mocks__/lang_chain_messages'; import { ESQL_RESOURCE } from '../../../routes/knowledge_base/constants'; import { ResponseBody } from '../types'; import { callAgentExecutor } from '.'; -import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; jest.mock('../llm/actions_client_llm'); @@ -70,10 +69,12 @@ describe('callAgentExecutor', () => { it('creates an instance of ActionsClientLlm with the expected context from the request', async () => { await callAgentExecutor({ actions: mockActions, + assistantLangChain: true, connectorId: mockConnectorId, esClient: esClientMock, langChainMessages, logger: mockLogger, + onNewReplacements: jest.fn(), request: mockRequest, kbResource: ESQL_RESOURCE, }); @@ -89,10 +90,12 @@ describe('callAgentExecutor', () => { it('kicks off the chain with (only) the last message', async () => { await callAgentExecutor({ actions: mockActions, + assistantLangChain: true, connectorId: mockConnectorId, esClient: esClientMock, langChainMessages, logger: mockLogger, + onNewReplacements: jest.fn(), request: mockRequest, kbResource: ESQL_RESOURCE, }); @@ -111,10 +114,12 @@ describe('callAgentExecutor', () => { await callAgentExecutor({ actions: mockActions, + assistantLangChain: true, connectorId: mockConnectorId, esClient: esClientMock, langChainMessages: onlyOneMessage, logger: mockLogger, + onNewReplacements: jest.fn(), request: mockRequest, kbResource: ESQL_RESOURCE, }); @@ -131,10 +136,12 @@ describe('callAgentExecutor', () => { it('returns the expected response body', async () => { const result: ResponseBody = await callAgentExecutor({ actions: mockActions, + assistantLangChain: true, connectorId: mockConnectorId, esClient: esClientMock, langChainMessages, logger: mockLogger, + onNewReplacements: jest.fn(), request: mockRequest, kbResource: ESQL_RESOURCE, }); @@ -145,24 +152,4 @@ describe('callAgentExecutor', () => { status: 'ok', }); }); - - it('throws an error if ELSER model is not installed', async () => { - (ElasticsearchStore as unknown as jest.Mock).mockImplementationOnce(() => ({ - isModelInstalled: jest.fn().mockResolvedValue(false), - })); - - await expect( - callAgentExecutor({ - actions: mockActions, - connectorId: mockConnectorId, - esClient: esClientMock, - langChainMessages, - logger: mockLogger, - request: mockRequest, - kbResource: ESQL_RESOURCE, - }) - ).rejects.toThrow( - 'Please ensure ELSER is configured to use the Knowledge Base, otherwise disable the Knowledge Base in Advanced Settings to continue.' - ); - }); }); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts index 3a27226dc804d..52a066e54de1e 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts @@ -8,7 +8,7 @@ import { initializeAgentExecutorWithOptions } from 'langchain/agents'; import { RetrievalQAChain } from 'langchain/chains'; import { BufferMemory, ChatMessageHistory } from 'langchain/memory'; -import { ChainTool, Tool } from 'langchain/tools'; +import { Tool } from 'langchain/tools'; import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; import { ActionsClientLlm } from '../llm/actions_client_llm'; @@ -16,6 +16,7 @@ import { KNOWLEDGE_BASE_INDEX_PATTERN } from '../../../routes/knowledge_base/con import type { AgentExecutorParams, AgentExecutorResponse } from '../executors/types'; import { withAssistantSpan } from '../tracers/with_assistant_span'; import { APMTracer } from '../tracers/apm_tracer'; +import { getApplicableTools } from '../tools'; export const DEFAULT_AGENT_EXECUTOR_ID = 'Elastic AI Assistant Agent Executor'; @@ -26,14 +27,21 @@ export const DEFAULT_AGENT_EXECUTOR_ID = 'Elastic AI Assistant Agent Executor'; */ export const callAgentExecutor = async ({ actions, + alertsIndexPattern, + allow, + allowReplacement, + assistantLangChain, connectorId, + elserId, esClient, + kbResource, langChainMessages, llmType, logger, + onNewReplacements, + replacements, request, - elserId, - kbResource, + size, traceOptions, }: AgentExecutorParams): AgentExecutorResponse => { const llm = new ActionsClientLlm({ actions, connectorId, request, llmType, logger }); @@ -59,25 +67,25 @@ export const callAgentExecutor = async ({ ); const modelExists = await esStore.isModelInstalled(); - if (!modelExists) { - throw new Error( - 'Please ensure ELSER is configured to use the Knowledge Base, otherwise disable the Knowledge Base in Advanced Settings to continue.' - ); - } // Create a chain that uses the ELSER backed ElasticsearchStore, override k=10 for esql query generation for now const chain = RetrievalQAChain.fromLLM(llm, esStore.asRetriever(10)); - // TODO: Dependency inject these tools - const tools: Tool[] = [ - new ChainTool({ - name: 'ESQLKnowledgeBaseTool', - description: - 'Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language.', - chain, - tags: ['esql', 'query-generation', 'knowledge-base'], - }), - ]; + const tools: Tool[] = getApplicableTools({ + allow, + allowReplacement, + alertsIndexPattern, + assistantLangChain, + chain, + esClient, + modelExists, + onNewReplacements, + replacements, + request, + size, + }); + + logger.debug(`applicable tools: ${JSON.stringify(tools.map((t) => t.name).join(', '), null, 2)}`); const executor = await initializeAgentExecutorWithOptions(tools, llm, { agentType: 'chat-conversational-react-description', @@ -116,6 +124,7 @@ export const callAgentExecutor = async ({ connector_id: connectorId, data: llm.getActionResultData(), // the response from the actions framework trace_data: traceData, + replacements, status: 'ok', }; }; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts index e4d564f677e14..bd6a38da5cdc4 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts @@ -14,14 +14,21 @@ import type { LangChainTracer } from 'langchain/callbacks'; import { RequestBody, ResponseBody } from '../types'; export interface AgentExecutorParams { + alertsIndexPattern?: string; actions: ActionsPluginStart; + allow?: string[]; + allowReplacement?: string[]; + assistantLangChain: boolean; connectorId: string; esClient: ElasticsearchClient; kbResource: string | undefined; langChainMessages: BaseMessage[]; llmType?: string; logger: Logger; + onNewReplacements?: (newReplacements: Record) => void; + replacements?: Record; request: KibanaRequest; + size?: number; elserId?: string; traceOptions?: TraceOptions; } diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.test.ts index 1156a8e758c13..20066afc68947 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.test.ts @@ -5,11 +5,18 @@ * 2.0. */ +import { KibanaRequest } from '@kbn/core-http-server'; import type { Message } from '@kbn/elastic-assistant'; import { AIMessage, BaseMessage, HumanMessage, SystemMessage } from 'langchain/schema'; -import { getLangChainMessage, getLangChainMessages, getMessageContentAndRole } from './helpers'; +import { + getLangChainMessage, + getLangChainMessages, + getMessageContentAndRole, + requestHasRequiredAnonymizationParams, +} from './helpers'; import { langChainMessages } from '../../__mocks__/lang_chain_messages'; +import { RequestBody } from './types'; describe('helpers', () => { describe('getLangChainMessage', () => { @@ -105,4 +112,118 @@ describe('helpers', () => { }); }); }); + + describe('requestHasRequiredAnonymizationParams', () => { + it('returns true if the request has valid anonymization params', () => { + const request = { + body: { + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 'c'], + replacements: { key: 'value' }, + }, + } as unknown as KibanaRequest; + + const result = requestHasRequiredAnonymizationParams(request); + + expect(result).toBe(true); + }); + + it('returns false if allow is undefined', () => { + const request = { + body: { + // allow is undefined + allowReplacement: ['b', 'c'], + replacements: { key: 'value' }, + }, + } as unknown as KibanaRequest; + + const result = requestHasRequiredAnonymizationParams(request); + + expect(result).toBe(false); + }); + + it('returns false if allow is empty', () => { + const request = { + body: { + allow: [], // <-- empty + allowReplacement: ['b', 'c'], + replacements: { key: 'value' }, + }, + } as unknown as KibanaRequest; + + const result = requestHasRequiredAnonymizationParams(request); + + expect(result).toBe(false); + }); + + it('returns false if allow has non-string values', () => { + const request = { + body: { + allow: ['a', 9876, 'c'], // <-- non-string value + allowReplacement: ['b', 'c'], + replacements: { key: 'value' }, + }, + } as unknown as KibanaRequest; + + const result = requestHasRequiredAnonymizationParams(request); + + expect(result).toBe(false); + }); + + it('returns true if allowReplacement is empty', () => { + const request = { + body: { + allow: ['a', 'b', 'c'], + allowReplacement: [], + replacements: { key: 'value' }, + }, + } as unknown as KibanaRequest; + + const result = requestHasRequiredAnonymizationParams(request); + + expect(result).toBe(true); + }); + + it('returns false if allowReplacement has non-string values', () => { + const request = { + body: { + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 12345], // <-- non-string value + replacements: { key: 'value' }, + }, + } as unknown as KibanaRequest; + + const result = requestHasRequiredAnonymizationParams(request); + + expect(result).toBe(false); + }); + + it('returns true if replacements is empty', () => { + const request = { + body: { + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 'c'], + replacements: {}, + }, + } as unknown as KibanaRequest; + + const result = requestHasRequiredAnonymizationParams(request); + + expect(result).toBe(true); + }); + + it('returns false if replacements has non-string values', () => { + const request = { + body: { + allow: ['a', 'b', 'c'], + allowReplacement: ['b', 'c'], + replacements: { key: 76543 }, // <-- non-string value + }, + } as unknown as KibanaRequest; + + const result = requestHasRequiredAnonymizationParams(request); + + expect(result).toBe(false); + }); + }); }); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.ts index 5f21ef9707d44..7850e2818e005 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.ts @@ -5,9 +5,12 @@ * 2.0. */ +import { KibanaRequest } from '@kbn/core-http-server'; import type { Message } from '@kbn/elastic-assistant'; import { AIMessage, BaseMessage, HumanMessage, SystemMessage } from 'langchain/schema'; +import { RequestBody } from './types'; + export const getLangChainMessage = ( assistantMessage: Pick ): BaseMessage => { @@ -31,3 +34,23 @@ export const getMessageContentAndRole = (prompt: string): Pick +): boolean => { + const { allow, allowReplacement, replacements } = request?.body ?? {}; + + const allowIsValid = + Array.isArray(allow) && + allow.length > 0 && // at least one field must be in the allow list + allow.every((item) => typeof item === 'string'); + + const allowReplacementIsValid = + Array.isArray(allowReplacement) && allowReplacement.every((item) => typeof item === 'string'); + + const replacementsIsValid = + typeof replacements === 'object' && + Object.keys(replacements).every((key) => typeof replacements[key] === 'string'); + + return allowIsValid && allowReplacementIsValid && replacementsIsValid; +}; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_query.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_query.test.ts new file mode 100644 index 0000000000000..27e210d53d51d --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_query.test.ts @@ -0,0 +1,59 @@ +/* + * 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 { getAlertsCountQuery } from './get_alert_counts_query'; + +describe('getAlertsCountQuery', () => { + it('returns the expected query', () => { + const alertsIndexPattern = 'alerts-index-pattern'; + const query = getAlertsCountQuery(alertsIndexPattern); + + expect(query).toEqual({ + aggs: { + statusBySeverity: { + terms: { + field: 'kibana.alert.severity', + }, + }, + }, + index: ['alerts-index-pattern'], + query: { + bool: { + filter: [ + { + bool: { + filter: [ + { + match_phrase: { + 'kibana.alert.workflow_status': 'open', + }, + }, + ], + must_not: [ + { + exists: { + field: 'kibana.alert.building_block_type', + }, + }, + ], + }, + }, + { + range: { + '@timestamp': { + gte: 'now/d', + lte: 'now/d', + }, + }, + }, + ], + }, + }, + size: 0, + }); + }); +}); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_query.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_query.ts new file mode 100644 index 0000000000000..10ca556ad59e1 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_query.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const getAlertsCountQuery = (alertsIndexPattern: string) => ({ + aggs: { + statusBySeverity: { + terms: { + field: 'kibana.alert.severity', + }, + }, + }, + index: [alertsIndexPattern], + query: { + bool: { + filter: [ + { + bool: { + filter: [ + { + match_phrase: { + 'kibana.alert.workflow_status': 'open', + }, + }, + ], + must_not: [ + { + exists: { + field: 'kibana.alert.building_block_type', + }, + }, + ], + }, + }, + { + range: { + '@timestamp': { + gte: 'now/d', + lte: 'now/d', + }, + }, + }, + ], + }, + }, + size: 0, +}); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_tool.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_tool.test.ts new file mode 100644 index 0000000000000..cffe31cbcfd39 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_tool.test.ts @@ -0,0 +1,105 @@ +/* + * 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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { KibanaRequest } from '@kbn/core-http-server'; +import { DynamicTool } from 'langchain/tools'; +import { omit } from 'lodash/fp'; + +import { getAlertCountsTool } from './get_alert_counts_tool'; +import type { RequestBody } from '../../types'; + +describe('getAlertCountsTool', () => { + const alertsIndexPattern = 'alerts-index'; + const esClient = { + search: jest.fn().mockResolvedValue({}), + } as unknown as ElasticsearchClient; + const replacements = { key: 'value' }; + const request = { + body: { + assistantLangChain: false, + alertsIndexPattern: '.alerts-security.alerts-default', + allow: ['@timestamp', 'cloud.availability_zone', 'user.name'], + allowReplacement: ['user.name'], + replacements, + size: 20, + }, + } as unknown as KibanaRequest; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('returns a `DynamicTool` with a `func` that calls `esClient.search()` with the expected query', async () => { + const tool: DynamicTool = getAlertCountsTool({ + alertsIndexPattern, + esClient, + replacements, + request, + }) as DynamicTool; + + await tool.func(''); + + expect(esClient.search).toHaveBeenCalledWith({ + aggs: { statusBySeverity: { terms: { field: 'kibana.alert.severity' } } }, + index: ['alerts-index'], + query: { + bool: { + filter: [ + { + bool: { + filter: [{ match_phrase: { 'kibana.alert.workflow_status': 'open' } }], + must_not: [{ exists: { field: 'kibana.alert.building_block_type' } }], + }, + }, + { range: { '@timestamp': { gte: 'now/d', lte: 'now/d' } } }, + ], + }, + }, + size: 0, + }); + }); + + it('returns null when the request is missing required anonymization parameters', () => { + const requestWithMissingParams = omit('body.allow', request) as unknown as KibanaRequest< + unknown, + unknown, + RequestBody + >; + + const tool = getAlertCountsTool({ + alertsIndexPattern, + esClient, + replacements, + request: requestWithMissingParams, + }); + + expect(tool).toBeNull(); + }); + + it('returns null when the alertsIndexPattern is undefined', () => { + const tool = getAlertCountsTool({ + // alertsIndexPattern is undefined + esClient, + replacements, + request, + }); + + expect(tool).toBeNull(); + }); + + it('returns a tool instance with the expected tags', () => { + const tool = getAlertCountsTool({ + alertsIndexPattern, + esClient, + replacements, + request, + }) as DynamicTool; + + expect(tool.tags).toEqual(['alerts', 'alerts-count']); + }); +}); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_tool.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_tool.ts new file mode 100644 index 0000000000000..9c5ec2555d2e5 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_tool.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SearchResponse } from '@elastic/elasticsearch/lib/api/types'; +import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { KibanaRequest } from '@kbn/core-http-server'; +import { DynamicTool, Tool } from 'langchain/tools'; + +import { getAlertsCountQuery } from './get_alert_counts_query'; +import { requestHasRequiredAnonymizationParams } from '../../helpers'; +import type { RequestBody } from '../../types'; + +export const ALERT_COUNTS_TOOL_DESCRIPTION = + 'Call this for the counts of last 24 hours of open alerts in the environment, grouped by their severity'; + +export const getAlertCountsTool = ({ + alertsIndexPattern, + esClient, + replacements, + request, +}: { + alertsIndexPattern?: string; + esClient: ElasticsearchClient; + replacements?: Record; + request: KibanaRequest; +}): Tool | null => { + if (!requestHasRequiredAnonymizationParams(request) || alertsIndexPattern == null) { + return null; + } + + return new DynamicTool({ + name: 'alert-counts', + description: ALERT_COUNTS_TOOL_DESCRIPTION, + func: async () => { + const query = getAlertsCountQuery(alertsIndexPattern); + + const result = await esClient.search(query); + + return JSON.stringify(result); + }, + tags: ['alerts', 'alerts-count'], + }); +}; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/esql_language_knowledge_base/get_esql_language_knowledge_base_tool.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/esql_language_knowledge_base/get_esql_language_knowledge_base_tool.test.ts new file mode 100644 index 0000000000000..ccd97b7deb088 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/esql_language_knowledge_base/get_esql_language_knowledge_base_tool.test.ts @@ -0,0 +1,55 @@ +/* + * 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 { RetrievalQAChain } from 'langchain/chains'; +import { DynamicTool } from 'langchain/tools'; + +import { getEsqlLanguageKnowledgeBaseTool } from './get_esql_language_knowledge_base_tool'; + +const chain = {} as RetrievalQAChain; + +describe('getEsqlLanguageKnowledgeBaseTool', () => { + it('returns null if assistantLangChain is false', () => { + const tool = getEsqlLanguageKnowledgeBaseTool({ + assistantLangChain: false, + chain, + modelExists: true, + }); + + expect(tool).toBeNull(); + }); + + it('returns null if modelExists is false (the ELSER model is not installed)', () => { + const tool = getEsqlLanguageKnowledgeBaseTool({ + assistantLangChain: true, + chain, + modelExists: false, // <-- ELSER model is not installed + }); + + expect(tool).toBeNull(); + }); + + it('should return a Tool instance if assistantLangChain and modelExists are true', () => { + const tool = getEsqlLanguageKnowledgeBaseTool({ + assistantLangChain: true, + modelExists: true, + chain, + }); + + expect(tool?.name).toEqual('ESQLKnowledgeBaseTool'); + }); + + it('should return a tool with the expected tags', () => { + const tool = getEsqlLanguageKnowledgeBaseTool({ + assistantLangChain: true, + chain, + modelExists: true, + }) as DynamicTool; + + expect(tool.tags).toEqual(['esql', 'query-generation', 'knowledge-base']); + }); +}); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/esql_language_knowledge_base/get_esql_language_knowledge_base_tool.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/esql_language_knowledge_base/get_esql_language_knowledge_base_tool.ts new file mode 100644 index 0000000000000..f49551261a79d --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/esql_language_knowledge_base/get_esql_language_knowledge_base_tool.ts @@ -0,0 +1,29 @@ +/* + * 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 { RetrievalQAChain } from 'langchain/chains'; +import { ChainTool, Tool } from 'langchain/tools'; + +export const getEsqlLanguageKnowledgeBaseTool = ({ + assistantLangChain, + modelExists, + chain, +}: { + assistantLangChain: boolean; + chain: RetrievalQAChain; + /** true when the ELSER model is installed */ + modelExists: boolean; +}): Tool | null => + assistantLangChain && modelExists + ? new ChainTool({ + name: 'ESQLKnowledgeBaseTool', + description: + 'Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language.', + chain, + tags: ['esql', 'query-generation', 'knowledge-base'], + }) + : null; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/index.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/index.test.ts new file mode 100644 index 0000000000000..cb0e79c0558d4 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/index.test.ts @@ -0,0 +1,58 @@ +/* + * 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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { KibanaRequest } from '@kbn/core-http-server'; +import { RetrievalQAChain } from 'langchain/chains'; + +import { RequestBody } from '../types'; +import { getApplicableTools } from '.'; + +describe('getApplicableTools', () => { + const alertsIndexPattern = 'alerts-index'; + const esClient = { + search: jest.fn().mockResolvedValue({}), + } as unknown as ElasticsearchClient; + const modelExists = true; // the ELSER model is installed + const onNewReplacements = jest.fn(); + const replacements = { key: 'value' }; + const request = { + body: { + assistantLangChain: true, + alertsIndexPattern: '.alerts-security.alerts-default', + allow: ['@timestamp', 'cloud.availability_zone', 'user.name'], + allowReplacement: ['user.name'], + replacements, + size: 20, + }, + } as unknown as KibanaRequest; + const chain = {} as unknown as RetrievalQAChain; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return an array of applicable tools', () => { + const tools = getApplicableTools({ + alertsIndexPattern, + allow: request.body.allow, + allowReplacement: request.body.allowReplacement, + assistantLangChain: request.body.assistantLangChain, + chain, + esClient, + modelExists, + onNewReplacements, + replacements, + request, + size: request.body.size, + }); + + const minExpectedTools = 3; // 3 tools are currently implemented + + expect(tools.length).toBeGreaterThanOrEqual(minExpectedTools); + }); +}); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/index.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/index.ts new file mode 100644 index 0000000000000..edc9c264b636a --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/index.ts @@ -0,0 +1,63 @@ +/* + * 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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { KibanaRequest } from '@kbn/core-http-server'; +import { RetrievalQAChain } from 'langchain/chains'; +import { Tool } from 'langchain/tools'; + +import { getAlertCountsTool } from './alert_counts/get_alert_counts_tool'; +import { getEsqlLanguageKnowledgeBaseTool } from './esql_language_knowledge_base/get_esql_language_knowledge_base_tool'; +import { getOpenAlertsTool } from './open_alerts/get_open_alerts_tool'; +import type { RequestBody } from '../types'; + +export interface GetApplicableTools { + alertsIndexPattern?: string; + allow?: string[]; + allowReplacement?: string[]; + assistantLangChain: boolean; + chain: RetrievalQAChain; + esClient: ElasticsearchClient; + modelExists: boolean; + onNewReplacements?: (newReplacements: Record) => void; + replacements?: Record; + request: KibanaRequest; + size?: number; +} + +export const getApplicableTools = ({ + alertsIndexPattern, + allow, + allowReplacement, + assistantLangChain, + chain, + esClient, + modelExists, + onNewReplacements, + replacements, + request, + size, +}: GetApplicableTools): Tool[] => + [ + getEsqlLanguageKnowledgeBaseTool({ assistantLangChain, chain, modelExists }) ?? [], + getAlertCountsTool({ + alertsIndexPattern, + esClient, + replacements, + request, + }) ?? [], + getOpenAlertsTool({ + alertsIndexPattern, + allow, + allowReplacement, + esClient, + onNewReplacements, + replacements, + request, + size, + }) ?? [], + ].flat(); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_query.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_query.test.ts new file mode 100644 index 0000000000000..673b1cae326fb --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_query.test.ts @@ -0,0 +1,72 @@ +/* + * 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 { getOpenAlertsQuery } from './get_open_alerts_query'; + +describe('getOpenAlertsQuery', () => { + it('returns the expected query', () => { + const alertsIndexPattern = 'alerts-*'; + const allow = ['field1', 'field2']; + const size = 10; + + const query = getOpenAlertsQuery({ alertsIndexPattern, allow, size }); + + expect(query).toEqual({ + allow_no_indices: true, + body: { + fields: [ + { field: 'field1', include_unmapped: true }, + { field: 'field2', include_unmapped: true }, + ], + query: { + bool: { + filter: [ + { + bool: { + must: [], + filter: [ + { + match_phrase: { + 'kibana.alert.workflow_status': 'open', + }, + }, + { + range: { + '@timestamp': { + gte: 'now-1d/d', + lte: 'now/d', + format: 'strict_date_optional_time', + }, + }, + }, + ], + should: [], + must_not: [ + { + exists: { + field: 'kibana.alert.building_block_type', + }, + }, + ], + }, + }, + ], + }, + }, + runtime_mappings: {}, + size: 10, + sort: [ + { 'kibana.alert.risk_score': { order: 'desc' } }, + { '@timestamp': { order: 'desc' } }, + ], + _source: false, + }, + ignore_unavailable: true, + index: ['alerts-*'], + }); + }); +}); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_query.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_query.ts new file mode 100644 index 0000000000000..4b8e1afb23ee0 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_query.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const getOpenAlertsQuery = ({ + alertsIndexPattern, + allow, + size, +}: { + alertsIndexPattern: string; + allow: string[]; + size: number; +}) => ({ + allow_no_indices: true, + body: { + fields: allow.map((field) => ({ + field, + include_unmapped: true, + })), + query: { + bool: { + filter: [ + { + bool: { + must: [], + filter: [ + { + match_phrase: { + 'kibana.alert.workflow_status': 'open', + }, + }, + { + range: { + '@timestamp': { + gte: 'now-1d/d', + lte: 'now/d', + format: 'strict_date_optional_time', + }, + }, + }, + ], + should: [], + must_not: [ + { + exists: { + field: 'kibana.alert.building_block_type', + }, + }, + ], + }, + }, + ], + }, + }, + runtime_mappings: {}, + size, + sort: [ + { + 'kibana.alert.risk_score': { + order: 'desc', + }, + }, + { + '@timestamp': { + order: 'desc', + }, + }, + ], + _source: false, + }, + ignore_unavailable: true, + index: [alertsIndexPattern], +}); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_tool.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_tool.test.ts new file mode 100644 index 0000000000000..8c996db2d63b4 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_tool.test.ts @@ -0,0 +1,206 @@ +/* + * 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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { KibanaRequest } from '@kbn/core-http-server'; +import { DynamicTool } from 'langchain/tools'; +import { omit } from 'lodash/fp'; + +import { getOpenAlertsTool } from './get_open_alerts_tool'; +import { mockAlertsFieldsApi } from '../../../../__mocks__/alerts'; +import type { RequestBody } from '../../types'; +import { MAX_SIZE } from './helpers'; + +describe('getOpenAlertsTool', () => { + const alertsIndexPattern = 'alerts-index'; + const esClient = { + search: jest.fn().mockResolvedValue(mockAlertsFieldsApi), + } as unknown as ElasticsearchClient; + const replacements = { key: 'value' }; + const request = { + body: { + assistantLangChain: false, + alertsIndexPattern: '.alerts-security.alerts-default', + allow: ['@timestamp', 'cloud.availability_zone', 'user.name'], + allowReplacement: ['user.name'], + replacements, + size: 20, + }, + } as unknown as KibanaRequest; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('returns a `DynamicTool` with a `func` that calls `esClient.search()` with the expected query', async () => { + const tool: DynamicTool = getOpenAlertsTool({ + alertsIndexPattern, + allow: request.body.allow, + allowReplacement: request.body.allowReplacement, + esClient, + onNewReplacements: jest.fn(), + replacements, + request, + size: request.body.size, + }) as DynamicTool; + + await tool.func(''); + + expect(esClient.search).toHaveBeenCalledWith({ + allow_no_indices: true, + body: { + _source: false, + fields: [ + { + field: '@timestamp', + include_unmapped: true, + }, + { + field: 'cloud.availability_zone', + include_unmapped: true, + }, + { + field: 'user.name', + include_unmapped: true, + }, + ], + query: { + bool: { + filter: [ + { + bool: { + filter: [ + { + match_phrase: { + 'kibana.alert.workflow_status': 'open', + }, + }, + { + range: { + '@timestamp': { + format: 'strict_date_optional_time', + gte: 'now-1d/d', + lte: 'now/d', + }, + }, + }, + ], + must: [], + must_not: [ + { + exists: { + field: 'kibana.alert.building_block_type', + }, + }, + ], + should: [], + }, + }, + ], + }, + }, + runtime_mappings: {}, + size: 20, + sort: [ + { + 'kibana.alert.risk_score': { + order: 'desc', + }, + }, + { + '@timestamp': { + order: 'desc', + }, + }, + ], + }, + ignore_unavailable: true, + index: ['alerts-index'], + }); + }); + + it('returns null when the request is missing required anonymization parameters', () => { + const requestWithMissingParams = omit('body.allow', request) as unknown as KibanaRequest< + unknown, + unknown, + RequestBody + >; + + const tool = getOpenAlertsTool({ + alertsIndexPattern, + allow: requestWithMissingParams.body.allow, + allowReplacement: requestWithMissingParams.body.allowReplacement, + esClient, + onNewReplacements: jest.fn(), + replacements, + request: requestWithMissingParams, + size: requestWithMissingParams.body.size, + }); + + expect(tool).toBeNull(); + }); + + it('returns null when alertsIndexPattern is undefined', () => { + const tool = getOpenAlertsTool({ + // alertsIndexPattern is undefined + allow: request.body.allow, + allowReplacement: request.body.allowReplacement, + esClient, + onNewReplacements: jest.fn(), + replacements, + request, + size: request.body.size, + }); + + expect(tool).toBeNull(); + }); + + it('returns null when size is undefined', () => { + const tool = getOpenAlertsTool({ + alertsIndexPattern, + allow: request.body.allow, + allowReplacement: request.body.allowReplacement, + esClient, + onNewReplacements: jest.fn(), + replacements, + request, + // size is undefined + }); + + expect(tool).toBeNull(); + }); + + it('returns null when size out of range', () => { + const tool = getOpenAlertsTool({ + alertsIndexPattern, + allow: request.body.allow, + allowReplacement: request.body.allowReplacement, + esClient, + onNewReplacements: jest.fn(), + replacements, + request, + size: MAX_SIZE + 1, // <-- size is out of range + }); + + expect(tool).toBeNull(); + }); + + it('returns a tool instance with the expected tags', () => { + const tool = getOpenAlertsTool({ + alertsIndexPattern, + allow: request.body.allow, + allowReplacement: request.body.allowReplacement, + esClient, + onNewReplacements: jest.fn(), + replacements, + request, + size: request.body.size, + }) as DynamicTool; + + expect(tool.tags).toEqual(['alerts', 'open-alerts']); + }); +}); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_tool.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_tool.ts new file mode 100644 index 0000000000000..755bfa7f9dc3a --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_tool.ts @@ -0,0 +1,90 @@ +/* + * 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 { SearchResponse } from '@elastic/elasticsearch/lib/api/types'; +import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { KibanaRequest } from '@kbn/core-http-server'; +import { getAnonymizedValue, transformRawData } from '@kbn/elastic-assistant-common'; +import { DynamicTool, Tool } from 'langchain/tools'; +import { requestHasRequiredAnonymizationParams } from '../../helpers'; +import { RequestBody } from '../../types'; + +import { getOpenAlertsQuery } from './get_open_alerts_query'; +import { getRawDataOrDefault, sizeIsOutOfRange } from './helpers'; + +export const OPEN_ALERTS_TOOL_DESCRIPTION = + 'Call this for knowledge about the latest n open alerts (sorted by `kibana.alert.risk_score`) in the environment, or when answering questions about open alerts'; + +/** + * Returns a tool for querying open alerts, or null if the request + * doesn't have all the required parameters. + */ +export const getOpenAlertsTool = ({ + alertsIndexPattern, + allow, + allowReplacement, + esClient, + onNewReplacements, + replacements, + request, + size, +}: { + alertsIndexPattern?: string; + allow?: string[]; + allowReplacement?: string[]; + esClient: ElasticsearchClient; + onNewReplacements?: (newReplacements: Record) => void; + replacements?: Record; + request: KibanaRequest; + size?: number; +}): Tool | null => { + if ( + !requestHasRequiredAnonymizationParams(request) || + alertsIndexPattern == null || + size == null || + sizeIsOutOfRange(size) + ) { + return null; + } + + return new DynamicTool({ + name: 'open-alerts', + description: OPEN_ALERTS_TOOL_DESCRIPTION, + func: async () => { + const query = getOpenAlertsQuery({ + alertsIndexPattern, + allow: allow ?? [], + size, + }); + + const result = await esClient.search(query); + + // Accumulate replacements locally so we can, for example use the same + // replacement for a hostname when we see it in multiple alerts: + let localReplacements = { ...replacements }; + const localOnNewReplacements = (newReplacements: Record) => { + localReplacements = { ...localReplacements, ...newReplacements }; // update the local state + + onNewReplacements?.(localReplacements); // invoke the callback with the latest replacements + }; + + return JSON.stringify( + result.hits?.hits?.map((x) => + transformRawData({ + allow: allow ?? [], + allowReplacement: allowReplacement ?? [], + currentReplacements: localReplacements, // <-- the latest local replacements + getAnonymizedValue, + onNewReplacements: localOnNewReplacements, // <-- the local callback + rawData: getRawDataOrDefault(x.fields), + }) + ) + ); + }, + tags: ['alerts', 'open-alerts'], + }); +}; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/helpers.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/helpers.test.ts new file mode 100644 index 0000000000000..722936a368b36 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/helpers.test.ts @@ -0,0 +1,117 @@ +/* + * 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 { + getRawDataOrDefault, + isRawDataValid, + MAX_SIZE, + MIN_SIZE, + sizeIsOutOfRange, +} from './helpers'; + +describe('helpers', () => { + describe('isRawDataValid', () => { + it('returns true for valid raw data', () => { + const rawData = { + field1: [1, 2, 3], // the Fields API may return a number array + field2: ['a', 'b', 'c'], // the Fields API may return a string array + }; + + expect(isRawDataValid(rawData)).toBe(true); + }); + + it('returns true when a field array is empty', () => { + const rawData = { + field1: [1, 2, 3], // the Fields API may return a number array + field2: ['a', 'b', 'c'], // the Fields API may return a string array + field3: [], // the Fields API may return an empty array + }; + + expect(isRawDataValid(rawData)).toBe(true); + }); + + it('returns false when a field does not have an array of values', () => { + const rawData = { + field1: [1, 2, 3], + field2: 'invalid', + }; + + expect(isRawDataValid(rawData)).toBe(false); + }); + + it('returns true for empty raw data', () => { + const rawData = {}; + + expect(isRawDataValid(rawData)).toBe(true); + }); + + it('returns false when raw data is an unexpected type', () => { + const rawData = 1234; + + // @ts-expect-error + expect(isRawDataValid(rawData)).toBe(false); + }); + }); + + describe('getRawDataOrDefault', () => { + it('returns the raw data when it is valid', () => { + const rawData = { + field1: [1, 2, 3], + field2: ['a', 'b', 'c'], + }; + + expect(getRawDataOrDefault(rawData)).toEqual(rawData); + }); + + it('returns an empty object when the raw data is invalid', () => { + const rawData = { + field1: [1, 2, 3], + field2: 'invalid', + }; + + expect(getRawDataOrDefault(rawData)).toEqual({}); + }); + }); + + describe('sizeIsOutOfRange', () => { + it('returns true when size is undefined', () => { + const size = undefined; + + expect(sizeIsOutOfRange(size)).toBe(true); + }); + + it('returns true when size is less than MIN_SIZE', () => { + const size = MIN_SIZE - 1; + + expect(sizeIsOutOfRange(size)).toBe(true); + }); + + it('returns true when size is greater than MAX_SIZE', () => { + const size = MAX_SIZE + 1; + + expect(sizeIsOutOfRange(size)).toBe(true); + }); + + it('returns false when size is exactly MIN_SIZE', () => { + const size = MIN_SIZE; + + expect(sizeIsOutOfRange(size)).toBe(false); + }); + + it('returns false when size is exactly MAX_SIZE', () => { + const size = MAX_SIZE; + + expect(sizeIsOutOfRange(size)).toBe(false); + }); + + it('returns false when size is within the valid range', () => { + const size = MIN_SIZE + 1; + + expect(sizeIsOutOfRange(size)).toBe(false); + }); + }); +}); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/helpers.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/helpers.ts new file mode 100644 index 0000000000000..dcb30e04e9dbc --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/helpers.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SearchResponse } from '@elastic/elasticsearch/lib/api/types'; + +export const MIN_SIZE = 10; +export const MAX_SIZE = 10000; + +export type MaybeRawData = SearchResponse['fields'] | undefined; // note: this is the type of the "fields" property in the ES response + +export const isRawDataValid = (rawData: MaybeRawData): rawData is Record => + typeof rawData === 'object' && Object.keys(rawData).every((x) => Array.isArray(rawData[x])); + +export const getRawDataOrDefault = (rawData: MaybeRawData): Record => + isRawDataValid(rawData) ? rawData : {}; + +export const sizeIsOutOfRange = (size?: number): boolean => + size == null || size < MIN_SIZE || size > MAX_SIZE; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts index 03f106b4b8796..1b7a140ab2c14 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts @@ -10,9 +10,10 @@ import { PostActionsConnectorExecuteBodyInputs } from '../../schemas/post_action export type RequestBody = PostActionsConnectorExecuteBodyInputs; export interface ResponseBody { - status: string; data: string; connector_id: string; + replacements?: Record; + status: string; trace_data?: { transaction_id: string; trace_id: string; diff --git a/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts b/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts index 52f820db17a01..39e3233f63744 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts @@ -39,6 +39,8 @@ const AGENT_EXECUTOR_MAP: Record = { OpenAIFunctionsExecutor: callOpenAIFunctionsExecutor, }; +const DEFAULT_SIZE = 20; + export const postEvaluateRoute = ( router: IRouter, getElser: GetElser @@ -109,12 +111,17 @@ export const postEvaluateRoute = ( const skeletonRequest: KibanaRequest = { ...request, body: { + alertsIndexPattern: '', + allow: [], + allowReplacement: [], params: { subAction: 'invokeAI', subActionParams: { messages: [], }, }, + replacements: {}, + size: DEFAULT_SIZE, assistantLangChain: true, }, }; @@ -134,6 +141,7 @@ export const postEvaluateRoute = ( agentEvaluator: (langChainMessages, exampleId) => AGENT_EXECUTOR_MAP[agentName]({ actions, + assistantLangChain: true, connectorId, esClient, elserId, diff --git a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts index 507246670833c..537ead452c8ea 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts @@ -145,6 +145,7 @@ describe('postActionsConnectorExecuteRoute', () => { body: { connector_id: 'mock-connector-id', data: mockActionResponse, + replacements: {}, status: 'ok', }, }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts index 299d8ade24a3f..ed68f3526a112 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts @@ -7,9 +7,13 @@ import { IRouter, Logger } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; + import { executeAction } from '../lib/executor'; import { POST_ACTIONS_CONNECTOR_EXECUTE } from '../../common/constants'; -import { getLangChainMessages } from '../lib/langchain/helpers'; +import { + getLangChainMessages, + requestHasRequiredAnonymizationParams, +} from '../lib/langchain/helpers'; import { buildResponse } from '../lib/build_response'; import { buildRouteValidation } from '../schemas/common'; import { @@ -43,8 +47,8 @@ export const postActionsConnectorExecuteRoute = ( const actions = (await context.elasticAssistant).actions; // if not langchain, call execute action directly and return the response: - if (!request.body.assistantLangChain) { - logger.debug('Executing via actions framework directly, assistantLangChain: false'); + if (!request.body.assistantLangChain && !requestHasRequiredAnonymizationParams(request)) { + logger.debug('Executing via actions framework directly'); const result = await executeAction({ actions, request, connectorId }); return response.ok({ body: result, @@ -64,19 +68,34 @@ export const postActionsConnectorExecuteRoute = ( const elserId = await getElser(request, (await context.core).savedObjects.getClient()); + let latestReplacements = { ...request.body.replacements }; + const onNewReplacements = (newReplacements: Record) => { + latestReplacements = { ...latestReplacements, ...newReplacements }; + }; + const langChainResponseBody = await callAgentExecutor({ + alertsIndexPattern: request.body.alertsIndexPattern, + allow: request.body.allow, + allowReplacement: request.body.allowReplacement, actions, + assistantLangChain: request.body.assistantLangChain, connectorId, + elserId, esClient, + kbResource: ESQL_RESOURCE, langChainMessages, logger, + onNewReplacements, request, - elserId, - kbResource: ESQL_RESOURCE, + replacements: request.body.replacements, + size: request.body.size, }); return response.ok({ - body: langChainResponseBody, + body: { + ...langChainResponseBody, + replacements: latestReplacements, + }, }); } catch (err) { logger.error(err); diff --git a/x-pack/plugins/elastic_assistant/server/schemas/post_actions_connector_execute.ts b/x-pack/plugins/elastic_assistant/server/schemas/post_actions_connector_execute.ts index 7a8d52e725722..cee6f31df6c71 100644 --- a/x-pack/plugins/elastic_assistant/server/schemas/post_actions_connector_execute.ts +++ b/x-pack/plugins/elastic_assistant/server/schemas/post_actions_connector_execute.ts @@ -34,7 +34,12 @@ export const PostActionsConnectorExecuteBody = t.type({ ]), subAction: t.string, }), + alertsIndexPattern: t.union([t.string, t.undefined]), + allow: t.union([t.array(t.string), t.undefined]), + allowReplacement: t.union([t.array(t.string), t.undefined]), assistantLangChain: t.boolean, + replacements: t.union([t.record(t.string, t.string), t.undefined]), + size: t.union([t.number, t.undefined]), }); export type PostActionsConnectorExecuteBodyInputs = t.TypeOf< diff --git a/x-pack/plugins/elastic_assistant/tsconfig.json b/x-pack/plugins/elastic_assistant/tsconfig.json index 53616fc2dc2b0..5cad4d4b52141 100644 --- a/x-pack/plugins/elastic_assistant/tsconfig.json +++ b/x-pack/plugins/elastic_assistant/tsconfig.json @@ -21,6 +21,7 @@ "@kbn/securitysolution-io-ts-utils", "@kbn/actions-plugin", "@kbn/elastic-assistant", + "@kbn/elastic-assistant-common", "@kbn/logging-mocks", "@kbn/core-elasticsearch-server-mocks", "@kbn/core-logging-server-mocks", diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index f5980dd808b9c..81e8906b73039 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -94,6 +94,11 @@ export const allowedExperimentalValues = Object.freeze({ */ assistantModelEvaluation: false, + /** + * Enables Retrieval Augmented Generation (RAG) on Alerts in the assistant + */ + assistantRagOnAlerts: false, + /* * Enables the new user details flyout displayed on the Alerts page and timeline. * diff --git a/x-pack/plugins/security_solution/public/assistant/content/anonymization/index.ts b/x-pack/plugins/security_solution/public/assistant/content/anonymization/index.ts index 84cd9ad09cacb..06be36e0a2bc9 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/anonymization/index.ts +++ b/x-pack/plugins/security_solution/public/assistant/content/anonymization/index.ts @@ -25,20 +25,50 @@ export const DEFAULT_ALLOW = [ 'file.name', 'file.path', 'host.name', + 'host.risk.calculated_level', + 'host.risk.calculated_score_norm', + 'kibana.alert.last_detected', + 'kibana.alert.rule.description', 'kibana.alert.rule.name', - 'network.protocol', + 'kibana.alert.rule.references', + 'kibana.alert.rule.threat.framework', + 'kibana.alert.rule.threat.tactic.id', + 'kibana.alert.rule.threat.tactic.name', + 'kibana.alert.rule.threat.tactic.reference', + 'kibana.alert.rule.threat.technique.id', + 'kibana.alert.rule.threat.technique.name', + 'kibana.alert.rule.threat.technique.reference', + 'kibana.alert.rule.threat.technique.subtechnique.id', + 'kibana.alert.rule.threat.technique.subtechnique.name', + 'kibana.alert.rule.threat.technique.subtechnique.reference', + 'kibana.alert.severity', 'process.args', + 'process.command_line', + 'process.executable', + 'process.Ext.token.integrity_level_name', + 'process.entity_id', 'process.exit_code', 'process.hash.md5', 'process.hash.sha1', - 'process.hash.sha256', - 'process.parent.name', - 'process.parent.pid', 'process.name', + 'process.hash.sha256', + 'process.parent.args', + 'process.parent.args_count', + 'process.parent.code_signature.exists', + 'process.parent.code_signature.status', + 'process.parent.code_signature.subject_name', + 'process.parent.code_signature.trusted', + 'process.parent.command_line', + 'process.parent.entity_id', + 'process.parent.executable', 'process.pid', + 'process.working_directory', + 'network.protocol', 'source.ip', 'user.domain', 'user.name', + 'user.risk.calculated_level', + 'user.risk.calculated_score_norm', ]; /** By default, these fields will be anonymized */ diff --git a/x-pack/plugins/security_solution/public/assistant/provider.tsx b/x-pack/plugins/security_solution/public/assistant/provider.tsx index 053c878c29937..7a17a98bc0d6e 100644 --- a/x-pack/plugins/security_solution/public/assistant/provider.tsx +++ b/x-pack/plugins/security_solution/public/assistant/provider.tsx @@ -6,7 +6,9 @@ */ import React, { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; +import type { IToasts } from '@kbn/core-notifications-browser'; import { AssistantProvider as ElasticAssistantProvider } from '@kbn/elastic-assistant'; + import { useBasePath, useKibana } from '../common/lib/kibana'; import { useAssistantTelemetry } from './use_assistant_telemetry'; import { getComments } from './get_comments'; @@ -19,7 +21,9 @@ import { BASE_SECURITY_SYSTEM_PROMPTS } from './content/prompts/system'; import { useAnonymizationStore } from './use_anonymization_store'; import { useAssistantAvailability } from './use_assistant_availability'; import { APP_ID } from '../../common/constants'; +import { useAppToasts } from '../common/hooks/use_app_toasts'; import { useIsExperimentalFeatureEnabled } from '../common/hooks/use_experimental_features'; +import { useSignalIndex } from '../detections/containers/detection_engine/alerts/use_signal_index'; const ASSISTANT_TITLE = i18n.translate('xpack.securitySolution.assistant.title', { defaultMessage: 'Elastic AI Assistant', @@ -51,9 +55,15 @@ export const AssistantProvider: React.FC = ({ children }) => { const nameSpace = `${APP_ID}.${LOCAL_STORAGE_KEY}`; + const { signalIndexName } = useSignalIndex(); + const alertsIndexPattern = signalIndexName ?? undefined; + const ragOnAlerts = useIsExperimentalFeatureEnabled('assistantRagOnAlerts'); + const toasts = useAppToasts() as unknown as IToasts; // useAppToasts is the current, non-deprecated method of getting the toasts service in the Security Solution, but it doesn't return the IToasts interface (defined by core) + return ( { assistantStreamingEnabled={assistantStreamingEnabled} modelEvaluatorEnabled={isModelEvaluationEnabled} nameSpace={nameSpace} + ragOnAlerts={ragOnAlerts} setConversations={setConversations} setDefaultAllow={setDefaultAllow} setDefaultAllowReplacement={setDefaultAllowReplacement} title={ASSISTANT_TITLE} + toasts={toasts} > {children} diff --git a/yarn.lock b/yarn.lock index d2efd008f3670..dd4e1988b5727 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4335,6 +4335,10 @@ version "0.0.0" uid "" +"@kbn/elastic-assistant-common@link:x-pack/packages/kbn-elastic-assistant-common": + version "0.0.0" + uid "" + "@kbn/elastic-assistant-plugin@link:x-pack/plugins/elastic_assistant": version "0.0.0" uid ""