From 3f0fa7d2458e115280c4c7bcc65e58bc0ec935d0 Mon Sep 17 00:00:00 2001 From: Andrew Macri Date: Wed, 6 Dec 2023 00:56:04 -0500 Subject: [PATCH] [Security Solution] [Elastic AI Assistant] Retrieval Augmented Generation (RAG) for Alerts (#172542) ## [Security Solution] [Elastic AI Assistant] Retrieval Augmented Generation (RAG) for Alerts This PR implements _Retrieval Augmented Generation_ (RAG) for Alerts in the Security Solution. This feature enables users to ask the assistant questions about the latest and riskiest open alerts in their environment using natural language, for example: - _How many alerts are currently open?_ - _Which alerts should I look at first?_ - _Did we have any alerts with suspicious activity on Windows machines?_ ### More context Previously, the assistant relied solely on the knowledge of the configured LLM and _singular_ alerts or events passed _by the client_ to the LLM as prompt context. This new feature: - Enables _multiple_ alerts to be passed by the _server_ as context to the LLM, via [LangChain tools](https://github.com/elastic/kibana/pull/167097) - Applies the user's [anonymization](https://github.com/elastic/kibana/pull/159857) settings to those alerts - Only fields allowed by the user will be sent as context to the LLM - Users may enable or disable anonymization for specific fields (via settings) - Click the conversation's `Show anonymized` toggle to see the anonymized values sent to / received from the LLM: ![show_anonymized](https://github.com/elastic/kibana/assets/4459398/7db85f69-9352-4422-adbf-c97248ccb3dd) ### Settings This feature is enabled and configured via the `Knowledge Base` > `Alerts` settings in the screenshot below: ![rag_on_alerts_setting](https://github.com/elastic/kibana/assets/4459398/9161b6d4-b7c3-4f37-bcde-f032f5a02966) - The `Alerts` toggle enables or disables the feature - The slider has a range of `10` - `100` alerts (default: `20`) When the setting above is enabled, up to `n` alerts (as determined by the slider) that meet the following criteria will be returned: - the `kibana.alert.workflow_status` must be `open` - the alert must have been generated in the last `24 hours` - the alert must NOT be a `kibana.alert.building_block_type` alert - the `n` alerts are ordered by `kibana.alert.risk_score`, to prioritize the riskiest alerts ### Feature flag To use this feature: 1) Add the `assistantRagOnAlerts` feature flag to the `xpack.securitySolution.enableExperimental` setting in `config/kibana.yml` (or `config/kibana.dev.yml` in local development environments), per the example below: ``` xpack.securitySolution.enableExperimental: ['assistantRagOnAlerts'] ``` 2) Enable the `Alerts` toggle in the Assistant's `Knowledge Base` settings, per the screenshot below: ![alerts_toggle](https://github.com/elastic/kibana/assets/4459398/07f241ea-af4a-43a4-bd19-0dc6337db167) ## How it works - When the `Alerts` settings toggle is enabled, http `POST` requests to the `/internal/elastic_assistant/actions/connector/{id}/_execute` route include the following new (optional) parameters: - `alertsIndexPattern`, the alerts index for the current Kibana Space, e.g. `.alerts-security.alerts-default` - `allow`, the user's `Allowed` fields in the `Anonymization` settings, e.g. `["@timestamp", "cloud.availability_zone", "file.name", "user.name", ...]` - `allowReplacement`, the user's `Anonymized` fields in the `Anonymization` settings, e.g. `["cloud.availability_zone", "host.name", "user.name", ...]` - `replacements`, a `Record` of replacements (generated on the server) that starts empty for a new conversation, and accumulates anonymized values until the conversation is cleared, e.g. ```json "replacements": { "e4f935c0-5a80-47b2-ac7f-816610790364": "Host-itk8qh4tjm", "cf61f946-d643-4b15-899f-6ffe3fd36097": "rpwmjvuuia", "7f80b092-fb1a-48a2-a634-3abc61b32157": "6astve9g6s", "f979c0d5-db1b-4506-b425-500821d00813": "Host-odqbow6tmc", // ... }, ``` - `size`, the numeric value set by the slider in the user's `Knowledge Base > Alerts` setting, e.g. `20` - The `postActionsConnectorExecuteRoute` function in `x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts` was updated to accept the new optional parameters, and to return an updated `replacements` with every response. (Every new request that is processed on the server may add additional anonymized values to the `replacements` returned in the response.) - The `callAgentExecutor` function in `x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts` previously used a hard-coded array of LangChain tools that had just one entry, for the `ESQLKnowledgeBaseTool` tool. That hard-coded array was replaced in this PR with a call to the (new) `getApplicableTools` function: ```typescript const tools: Tool[] = getApplicableTools({ allow, allowReplacement, alertsIndexPattern, assistantLangChain, chain, esClient, modelExists, onNewReplacements, replacements, request, size, }); ``` - The `getApplicableTools` function in `x-pack/plugins/elastic_assistant/server/lib/langchain/tools/index.ts` examines the parameters in the `KibanaRequest` and only returns a filtered set of LangChain tools. If the request doesn't contain all the parameters required by a tool, it will NOT be returned by `getApplicableTools`. For example, if the required anonymization parameters are not included in the request, the `open-alerts` tool will not be returned. - The new `alert-counts` LangChain tool returned by the `getAlertCountsTool` function in `x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_tool.ts` provides the LLM the results of an aggregation on the last `24` hours of alerts (in the current Kibana Space), grouped by `kibana.alert.severity`. See the `getAlertsCountQuery` function in `x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_query.ts` for details - The new `open-alerts` LangChain tool returned by the `getOpenAlertsTool` function in `x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_tool.ts` provides the LLM up to `size` non-building-block alerts generated in the last `24` hours (in the current Kibana Space) with an `open` workflow status, ordered by `kibana.alert.risk_score` to prioritize the riskiest alerts. See the `getOpenAlertsQuery` function in `x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_query.ts` for details. - On the client, a conversation continues to accumulate additional `replacements` (and send them in subsequent requests) until the conversation is cleared - Anonymization functions that were only invoked by the browser were moved from the (browser) `kbn-elastic-assistant` package in `x-pack/packages/kbn-elastic-assistant/` to a new common package: `x-pack/packages/kbn-elastic-assistant-common` - The new `kbn-elastic-assistant-common` package is also consumed by the `elastic_assistant` (server) plugin: `x-pack/plugins/elastic_assistant` --- .eslintrc.js | 5 + .github/CODEOWNERS | 1 + package.json | 1 + tsconfig.base.json | 2 + x-pack/.i18nrc.json | 1 + .../kbn-elastic-assistant-common/README.md | 20 + .../get_anonymized_data/index.test.ts | 0 .../get_anonymized_data/index.ts | 9 +- .../get_anonymized_value/index.test.ts | 45 + .../get_anonymized_value/index.ts | 26 + .../get_anonymized_values/index.test.tsx | 0 .../get_anonymized_values/index.ts | 13 +- .../get_csv_from_data/index.test.ts | 0 .../get_csv_from_data/index.ts | 0 .../data_anonymization/helpers/index.test.ts | 97 + .../impl/data_anonymization/helpers/index.ts | 23 + .../transform_raw_data/index.test.tsx | 25 +- .../transform_raw_data/index.tsx | 19 +- .../impl/data_anonymization/types.ts | 2 +- .../impl/mock/get_anonymized_value/index.ts | 15 + .../kbn-elastic-assistant-common/index.ts | 17 + .../jest.config.js | 23 + .../kbn-elastic-assistant-common/kibana.jsonc | 5 + .../kbn-elastic-assistant-common/package.json | 6 + .../setup_tests.ts | 9 + .../tsconfig.json | 20 + .../alerts/settings/alerts_settings.test.tsx | 105 + .../impl/alerts/settings/alerts_settings.tsx | 117 + .../impl/assistant/api.test.tsx | 34 +- .../impl/assistant/api.tsx | 53 +- .../chat_send/use_chat_send.test.tsx | 27 +- .../assistant/chat_send/use_chat_send.tsx | 34 +- .../impl/assistant/helpers.test.ts | 104 + .../impl/assistant/helpers.ts | 57 + .../impl/assistant/prompt/helpers.ts | 8 +- .../settings/assistant_settings_button.tsx | 10 +- .../impl/assistant/settings/translations.ts | 7 + .../use_settings_updater.test.tsx | 4 + .../impl/assistant/types.ts | 2 + .../use_send_messages/helpers.test.ts | 45 + .../assistant/use_send_messages/helpers.ts | 28 + .../assistant/use_send_messages/index.tsx | 44 +- .../impl/assistant_context/constants.tsx | 5 + .../impl/assistant_context/index.tsx | 18 +- .../impl/assistant_context/types.tsx | 1 + .../context_editor/get_rows/index.ts | 3 +- .../get_stats/index.ts | 4 +- .../knowledge_base_settings.test.tsx | 43 + .../knowledge_base_settings.tsx | 19 +- .../impl/knowledge_base/translations.ts | 29 + .../kbn-elastic-assistant/tsconfig.json | 1 + .../server/__mocks__/alerts.ts | 3210 +++++++++++++++++ .../execute_custom_llm_chain/index.test.ts | 29 +- .../execute_custom_llm_chain/index.ts | 45 +- .../server/lib/langchain/executors/types.ts | 7 + .../server/lib/langchain/helpers.test.ts | 123 +- .../server/lib/langchain/helpers.ts | 23 + .../get_alert_counts_query.test.ts | 59 + .../alert_counts/get_alert_counts_query.ts | 50 + .../get_alert_counts_tool.test.ts | 105 + .../alert_counts/get_alert_counts_tool.ts | 47 + ..._esql_language_knowledge_base_tool.test.ts | 55 + .../get_esql_language_knowledge_base_tool.ts | 29 + .../server/lib/langchain/tools/index.test.ts | 58 + .../server/lib/langchain/tools/index.ts | 63 + .../open_alerts/get_open_alerts_query.test.ts | 72 + .../open_alerts/get_open_alerts_query.ts | 76 + .../open_alerts/get_open_alerts_tool.test.ts | 206 ++ .../tools/open_alerts/get_open_alerts_tool.ts | 90 + .../tools/open_alerts/helpers.test.ts | 117 + .../langchain/tools/open_alerts/helpers.ts | 22 + .../server/lib/langchain/types.ts | 3 +- .../server/routes/evaluate/post_evaluate.ts | 8 + .../post_actions_connector_execute.test.ts | 1 + .../routes/post_actions_connector_execute.ts | 31 +- .../schemas/post_actions_connector_execute.ts | 5 + .../plugins/elastic_assistant/tsconfig.json | 1 + .../common/experimental_features.ts | 5 + .../assistant/content/anonymization/index.ts | 38 +- .../public/assistant/provider.tsx | 12 + yarn.lock | 4 + 81 files changed, 5656 insertions(+), 124 deletions(-) create mode 100644 x-pack/packages/kbn-elastic-assistant-common/README.md rename x-pack/packages/{kbn-elastic-assistant => kbn-elastic-assistant-common}/impl/data_anonymization/get_anonymized_data/index.test.ts (100%) rename x-pack/packages/{kbn-elastic-assistant => kbn-elastic-assistant-common}/impl/data_anonymization/get_anonymized_data/index.ts (84%) create mode 100644 x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_value/index.test.ts create mode 100644 x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/get_anonymized_value/index.ts rename x-pack/packages/{kbn-elastic-assistant => kbn-elastic-assistant-common}/impl/data_anonymization/get_anonymized_values/index.test.tsx (100%) rename x-pack/packages/{kbn-elastic-assistant => kbn-elastic-assistant-common}/impl/data_anonymization/get_anonymized_values/index.ts (75%) rename x-pack/packages/{kbn-elastic-assistant => kbn-elastic-assistant-common}/impl/data_anonymization/get_csv_from_data/index.test.ts (100%) rename x-pack/packages/{kbn-elastic-assistant => kbn-elastic-assistant-common}/impl/data_anonymization/get_csv_from_data/index.ts (100%) create mode 100644 x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/helpers/index.test.ts create mode 100644 x-pack/packages/kbn-elastic-assistant-common/impl/data_anonymization/helpers/index.ts rename x-pack/packages/{kbn-elastic-assistant => kbn-elastic-assistant-common}/impl/data_anonymization/transform_raw_data/index.test.tsx (81%) rename x-pack/packages/{kbn-elastic-assistant => kbn-elastic-assistant-common}/impl/data_anonymization/transform_raw_data/index.tsx (74%) rename x-pack/packages/{kbn-elastic-assistant => kbn-elastic-assistant-common}/impl/data_anonymization/types.ts (96%) create mode 100644 x-pack/packages/kbn-elastic-assistant-common/impl/mock/get_anonymized_value/index.ts create mode 100644 x-pack/packages/kbn-elastic-assistant-common/index.ts create mode 100644 x-pack/packages/kbn-elastic-assistant-common/jest.config.js create mode 100644 x-pack/packages/kbn-elastic-assistant-common/kibana.jsonc create mode 100644 x-pack/packages/kbn-elastic-assistant-common/package.json create mode 100644 x-pack/packages/kbn-elastic-assistant-common/setup_tests.ts create mode 100644 x-pack/packages/kbn-elastic-assistant-common/tsconfig.json create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/helpers.test.ts create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_messages/helpers.ts create mode 100644 x-pack/plugins/elastic_assistant/server/__mocks__/alerts.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_query.test.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_query.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_tool.test.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/alert_counts/get_alert_counts_tool.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/esql_language_knowledge_base/get_esql_language_knowledge_base_tool.test.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/esql_language_knowledge_base/get_esql_language_knowledge_base_tool.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/index.test.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/index.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_query.test.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_query.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_tool.test.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/get_open_alerts_tool.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/helpers.test.ts create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/tools/open_alerts/helpers.ts 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 ""