Skip to content

Commit

Permalink
[Security Solution] [AI Insights] AI Insights (elastic#180611)
Browse files Browse the repository at this point in the history
## [Security Solution] [AI Insights] AI Insights

### Summary

This PR introduces _AI Insights_ to the Security Solution:


![ai_insights](https://github.com/elastic/kibana/assets/4459398/51b9d6f5-f3d0-4a94-9b14-0b7f1b10cb5f)

_Above: AI Insights in the Security Solution_

AI Insights identify active attacks in the environment, without the time
(or prior experience) required to manually investigate individual alerts
in Elastic Security, identify if they are related, and document the
identified attack progression.

While users can ask the Assistant to find these progressions today, AI
Insights is a dedicated UI to identify these progressions and action
them accordingly. This feature adds a new page, `AI Insights`, to the
Security Solution's global navigation.

AI Insights are generated from Large Language Models (LLMs) to identify
attack progressions in alert data, and to correlate and identify related
entities and events. When possible, attack progressions are attributed
to threat actors.

### Details

Users may generate insights from a varetiy of LLMs, configured via
[Connectors](https://www.elastic.co/guide/en/kibana/master/action-types.html):


![connector_selection](https://github.com/elastic/kibana/assets/4459398/394fdcdf-3d23-4b92-a0b6-c6ba6a203600)

_Above: LLM selection via the connectors popup menu_

Clicking on the title of an insight toggles the insight between the
collapsed and expanded state:


![toggle_expand_collapse](https://github.com/elastic/kibana/assets/4459398/6f87725f-dda1-44aa-ba96-7966544826c4)

_Above: Collapsing / expanding an insight (animated gif)_

The first three insights displayed on the AI Insights page are expanded
by default. Any additional insights that appear after the first three
must be expanded manually.

Insights provide a summary of the entities impacted by an attack.
Clicking on an entity, i.e. a hostname or username, displays the entity
flyout with the entity's risk summary:


![view_host_details](https://github.com/elastic/kibana/assets/4459398/316399dd-db7d-4701-8318-0f3a96d8b4c0)

_Above: Clicking on a host in the summary of the insight reveals the
host risk summary (animated gif)_

Hover over fields in the insight's summary or details to reveal pivot
actions for investigations:


![field_hover_actions](https://github.com/elastic/kibana/assets/4459398/30c89370-9f5e-4c78-8b42-6274ff1d2604)

_Above: Hovering over fields in the details of an insight reveals pivot
actions (animated gif)_

Insights are generated from alerts provided as context to the selected
LLM. The alert data provided to the LLM is anonymized automatically.
Anonymization is
[configured](https://www.elastic.co/guide/en/security/current/security-assistant.html#ai-assistant-anonymization)
via the same anonymization settings as the Assistant. Users may override
the defaults to allow or deny specific alert fields, and to toggle
anonymization on or off for specific fields.

Click the Anonymization toggle to show or hide the actual values sent to
the LLM:


![toggle_anonymization](https://github.com/elastic/kibana/assets/4459398/6856c894-6065-4a98-8f9b-813f9fb06f28)

_Above: Toggling anonymization to reveal the actual values sent to the
LLM (animated gif)_

### Empty prompt

At the start of a session, or when a user selects a connector that
doesn't (yet) have any insights, an [empty
prompt](https://eui.elastic.co/#/display/empty-prompt) is displayed.

The animated counter in the empty prompt counts up until it displays the
maximum number of alerts that will be sent to the LLM:


![empty_prompt](https://github.com/elastic/kibana/assets/4459398/00ef81f0-a8f9-4cad-8e50-96870e500ea3)

_Above: An animated counter displays the maximum number of alerts that
will be sent to the LLM (animiated gif)_

The _Settings_ section of this PR details how users configure the number
of alerts sent to the LLM. The animated counter in the empty prompt
immediately re-animates to the newly-selected number when the setting is
updated.

### Take action workflows

The _Take action_ popover displays the following actions:

- `Add to new case`
- `Add to existing case`
- `View in AI Assistant`


![take_action_popover](https://github.com/elastic/kibana/assets/4459398/c1e7b4fe-0d04-4aa3-a04c-750b403def65)

_Above: The Take action popover_

#### Add to new case

Clicking the `Add to new` case action displays the `Create case` flyout.


![add_to_new_case](https://github.com/elastic/kibana/assets/4459398/7a253856-c52c-4d78-a5a9-8fb51b5d70e5)

_Above: The `Add to new case` workflow_

An `Alerts were added to <case name>` toast is displayed when the case
is created:


![case_creation_toast](https://github.com/elastic/kibana/assets/4459398/17cf3a0a-3e66-4d7f-a7a9-d3bc00c76459)

_Above: Case creation toast_

A markdown representation of the insight is added to the case:


![case_from_insight](https://github.com/elastic/kibana/assets/4459398/b856540e-ef8a-4a13-94ec-60e08a720f4d)

_Above: A markdown representation of an insight in a case_

The alerts correlated to generate the insight are attached to the case:


![case_alerts](https://github.com/elastic/kibana/assets/4459398/7d8efc6f-28ad-4b2d-a343-40bb51437a29)

_Above: Insight alerts attached to a case_

#### Add to existing case

Clicking the `Add to existing case` action displays the `Select case`
popover.


![select_case](https://github.com/elastic/kibana/assets/4459398/16f09eb5-a1c7-491e-b63e-5e0c83a968fe)

_Above: The `Select case` popover_

When users select an existing case, a markdown representation of the
insight, and the alerts correlated to generate the insight are attached
to the case, as described above in the _Add to new case_ section.

#### View in AI Assistant

The `View in AI Assistant` action in the `Take action` popover, and two
additional `View in AI Assistant` affordances that appear in each
insight have the same behavior:

Clicking `View in AI Assistant` opens the assistant and adds the insight
as context to the current conversation.


![view_in_assistant](https://github.com/elastic/kibana/assets/4459398/869ed310-b3ee-44f9-b39f-1f7e7a086dcc)

_Above: An insight added as context to the current conversation_

Clicking on the insight in the assistant expands it to reveal a preview
of the insight.


![insight_preview](https://github.com/elastic/kibana/assets/4459398/b7f23015-6b8d-4386-9336-5c4b085fcefe)

_Above: An expanded insight preview in the assistant_

The expanded insight preview reveals the number of anonymzied fields
from the insight that were made available to the conversation. This
feature ensures insights are added to a conversation with the anonymized
field values.

An insight viewed in the AI assistant doesn't become part of the
conversation until the user submits it by asking a question, e.g. `How
do I remediate this?`.

Insights provided as context to a conversation are formatted as markdown
when sent to the LLM:


![context_as_markdown](https://github.com/elastic/kibana/assets/4459398/625ba555-526c-4770-8038-cd6c7aadbd05)

_Above: Insights provided as context to a conversation are formatted as
markdown_

Users may toggle anonymization in the conversation to reveal the
original field values.


![anonymization_in_assistant](https://github.com/elastic/kibana/assets/4459398/ce47344d-c9d2-4462-9039-047863702a4f)

_Above: Revealing the original field values of an insight added as
markdown to a conversation (animated gif)_

#### Alerts tab

The _Alerts_ tab displays the alerts correlated to generate the insight.


![alerts_tab](https://github.com/elastic/kibana/assets/4459398/5bd7f5a0-4a00-450f-b16f-ad397e3fe1be)

_Above: The alerts correlated to generate the insight in the Alerts tab_

The `View details`, `Investigate in timeline`, and overflow row-level
alert actions displayed in the Alerts tab are the same actions available
on the Cases's page's Alerts tab:


![alert_actions](https://github.com/elastic/kibana/assets/4459398/f993b6c2-3aaa-4d98-9d7a-45a6632c6b09)

_Above: Row-level actions are the same as the Cases pages Alert's tab_

#### Investigate in Timeline

Click an insight's `Investigate in Timeline` button to begin an
investigation of an insights's alerts in Timeline. Alert IDs are queried
via the `Alert Ids` filter:


![investigate_in_timeline](https://github.com/elastic/kibana/assets/4459398/0694903a-995d-4530-bb78-a49798b3e982)

_Above: Clicking Investigte in Timeline (animated gif)_

The alerts from the insight are explained via row renderers in Timeline:


![insight_alerts_in_timeline](https://github.com/elastic/kibana/assets/4459398/26fbb19d-3480-4df5-a1de-5d823d91fca9)

_Above: Row rendered insight alerts in Timeline_

### Attack Chain

When alerts are indicative of attack
[tactics](https://attack.mitre.org/tactics/enterprise/), those tactics
are displayed in the insights's _Attack Chain_ section:


![insight_with_attack_chain](https://github.com/elastic/kibana/assets/4459398/cff26c0a-ef07-4b96-b295-f27be34c2536)

_Above: An insight with tactics in the Attach chain_

The Attack Chain section will be hidden if an insight is not indicative
of specific tactics.

### Mini attack chain

Every insight includes a mini attack chain that visually summarizes the
tactics in an insight. Hovering over the mini attack chain reveals a
tooltip with the details:


![mini_attack_chain](https://github.com/elastic/kibana/assets/4459398/65daa760-f892-4c39-991c-28126e8e47ea)

_Above: The mini attack chain tooltip_

### Storage

The latest insights generated for each connector are cached in the
browser's session storage in the following key:

```
elasticAssistantDefault.aiInsights.cachedInsights
```

Caching insights in session storage makes it possible to immediately
display the latest when users return to to the AI insights page from
other pages in the security solution (e.g. Cases).


![cached_insights](https://github.com/elastic/kibana/assets/4459398/8ad94572-1588-4497-b8f9-9cbb6730446a)

_Above: Cached insights from sesion storage are immediately displayed
when users navigate back to AI Insights (animated gif)_

While waiting for a connector to generate results, users may view the
cached results from other connectors.

Cached insights are immediately available, even after a full page
refresh, as long as the browser session is still active.

### `Approximate time remaining` / `Above average time` counters

Some LLMs may take seconds, or even minutes to generate insights. To
help users anticipate the time it might take to generate an insight, the
AI insights feature displays a `Approximate time remaining: mm:ss`
countdown timer that counts down to zero from the average time it takes
to generate an insight for the selected LLM:


![approximate_time_remaining](https://github.com/elastic/kibana/assets/4459398/3e568113-de92-4f07-a9fa-151445d9268d)

_Above: The `Approximate time remaining: mm:ss` countdown counter
(animated gif)_

If the LLM doesn't generate insights before the counter reaches zero,
the text will change from `Approximate time remaining: mm:ss` to `Above
average time: mm:ss`, and start counting up from `00:00` until the
insights are generated:


![above_average_time](https://github.com/elastic/kibana/assets/4459398/b095f4cc-bdf4-4aa1-9b2a-fb5cc1870c25)

_Above: The `Above average time: mm:ss` counter (animated gif)_

The first time insights are generated for a model, the `Approximate time
remaining: mm:ss` counter is not displayed.

Average time is calculated over the last 5 generations on the selected
connector. This is illustrated by clicking on the (?) information icon
next to the timer. The popover displays the average time, and the time
in seconds for the last 5 runs:


![time_remaining_popover](https://github.com/elastic/kibana/assets/4459398/4e5d6a46-e171-42c0-a10e-47236b84587d)

_Above: Clicking on the (?) information icon displays the average time,
and the duration / datetimes for the last 5 generations_

The time and duration of the last 5 generations (for each connector) are
persisted in the browser's local storage in the following key:

```
elasticAssistantDefault.aiInsights.generationIntervals
```

### Errors

When insight generation fails, an error toaster is displayed to explain
the failure:


![error_toast](https://github.com/elastic/kibana/assets/4459398/04f8492f-33d1-4cf2-8833-765526e54cad)

_Above: An error toaster explains why insights generation failed_

### Feature flag

The `assistantAlertsInsights` feature flag must be enabled to view the
`AI Insights` link in the Security Solution's global navigation.

Add the `assistantAlertsInsights` 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: ['assistantAlertsInsights']
```

### Settings

The number of alerts sent as context to the LLM is configured by
`Knowledge Base` > `Alerts` slider in the screenshot below:


![alerts_slider](https://github.com/elastic/kibana/assets/4459398/01c8a3bb-f40b-4280-bb97-764e4f42d8d5)

- The slider has a range of `10` - `100` alerts (default: `20`)

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

### License

An Enterprise license is required to use AI Insights.

The following AI Insights view is displayed for users who don't have an
Enterprise license:


![upgrade](https://github.com/elastic/kibana/assets/4459398/a83e392a-d209-40d2-9738-8ec7968b7eff)

## How it works

- Users navigate to the AI insights page:
`x-pack/plugins/security_solution/public/ai_insights/pages/index.tsx`

- When users click the `Generate` button(s) on the AI Insights page,
insights are fetched via the `useInsights` hook in
`x-pack/plugins/security_solution/public/ai_insights/use_insights/index.tsx`.

- The `fetchInsights` function makes an http `POST` request is made to
the `/internal/elastic_assistant/insights/alerts` route. include the
following new (optional) parameters:
- `actionTypeId`, determines tempature and other connector-specific
request 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", ...]`
  - `connectorId`, id of the connector to generate the insights
- `replacements`, an optional `Record<string, string>` collection of
replacements that always empty in the current implementation. When
non-empty, this collection enables new insights to be generated using
existing replacements.

```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 maximum number of alerts to generate insights from. This
numeric value is set by the slider in the user's `Knowledge Base >
Alerts` setting, e.g. `20`

- The `postAlertsInsightsRoute` function in
`x-pack/plugins/elastic_assistant/server/routes/insights/alerts/post_alerts_insights.ts`
handles the request.

- The inputs and outputs to this route are defined by the
[OpenAPI](https://spec.openapis.org/oas/v3.1.0) schema in
`x-pack/packages/kbn-elastic-assistant-common/impl/schemas/insights/alerts/post_alerts_insights_route.schema.yaml`.

```
node scripts/generate_openapi --rootDir ./x-pack/packages/kbn-elastic-assistant-common
```

- The `postAlertsInsightsRoute` route handler function in
`x-pack/plugins/elastic_assistant/server/routes/insights/alerts/post_alerts_insights.ts`
invokes the `insights-tool`, defined in
`x-pack/plugins/security_solution/server/assistant/tools/insights/insights_tool.ts`.

The `insights-tool` is registered by the Security Solution. Note: The
`insights-tool` is only used for generating insights. It is not used to
generate new insights from the context of an assistant conversation, but
that feature could be enabled in a future release.

- The `insights-tool` uses a LangChain `OutputFixingParser` to create a
[prompt
sandwich](https://www.elastic.co/blog/crafting-prompt-sandwiches-generative-ai)
with the following parts:

```
  _________________________________________________
 /                                                 \
|     Insight JSON formatting instructions         | (1)
 \ _______________________________________________/
 +------------------------------------------------+
 |    Insights prompt                             |  (2)
 +------------------------------------------------+
 /                                               \
|    Anonymized Alerts                           |   (3)
 \_______________________________________________/
 ```

- The `Insight JSON formatting instructions` in section `(1)` of the prompt sandwich are defined in the `getOutputParser()` function in `x-pack/plugins/security_solution/server/assistant/tools/insights/get_output_parser.ts`. This function creates a LangChain `StructuredOutputParser` from a Zod schema. This parser validates responses from the LLM to ensure they are formatted as JSON representing an insight.

- The `Insights prompt` in section `(2)` of the prompt sandwich is defined in the `getInsightsPrompt()` function in `x-pack/plugins/security_solution/server/assistant/tools/insights/get_insights_prompt.ts`. This part of the prompt sandwich includes instructions for correlating insights, and additional instructions to the LLM for formatting JSON.

- The `Anonymized Alerts` in section `(3)` of the prompt sandwich are returned by the `getAnonymizedAlerts()` function in `x-pack/plugins/security_solution/server/assistant/tools/insights/get_anonymized_alerts.ts`. The allow lists configured by the user determine which alert fields will be included and anonymized.

- The `postAlertsInsightsRoute` route handler returns the insights generated by the `insights-tool` to the client (browser).

- Insights are rendered in the browser via the `Insight` component in `x-pack/plugins/security_solution/public/ai_insights/insight/index.tsx`

- The `AiInsights` tab in `x-pack/plugins/security_solution/public/ai_insights/insight/tabs/ai_insights/index.tsx` includes the _Summary_ and _Details_ section of the Insight.

- The `InsightMarkdownFormatter` in `x-pack/plugins/security_solution/public/ai_insights/insight_markdown_formatter/index.tsx` renders hover actions on entities (like hostnames and usernames) and other fields in the insight.

- The `Insight` component makes use of the `useAssistantOverlay` hook in `x-pack/packages/kbn-elastic-assistant/impl/assistant/use_assistant_overlay/index.tsx` to register the insight as context with the assistant. This registration process makes it possible to view insights in the assistant, and ask questions like "How do I remediate this?".  In this PR, the `useAssistantOverlay` hook was enhanced to accept anonymizaton replacements. This enables an assistant conversation to (re)use replacements originally generated for an insight.
  • Loading branch information
andrew-goldstein authored Apr 16, 2024
1 parent c4e40ea commit 32f43bf
Show file tree
Hide file tree
Showing 143 changed files with 6,994 additions and 75 deletions.
1 change: 1 addition & 0 deletions packages/deeplinks/security/deep_links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

export enum SecurityPageName {
administration = 'administration',
aiInsights = 'ai_insights',
alerts = 'alerts',
assets = 'assets',
blocklist = 'blocklist',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ export type AssistantFeatures = { [K in keyof typeof defaultAssistantFeatures]:
* Default features available to the elastic assistant
*/
export const defaultAssistantFeatures = Object.freeze({
assistantAlertsInsights: false,
assistantModelEvaluation: false,
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Replacements } from '../../schemas';
import { AnonymizationFieldResponse } from '../../schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen';
import { isAllowed } from '../helpers';
import type { AnonymizedData, GetAnonymizedValues } from '../types';
Expand All @@ -16,12 +17,12 @@ export const getAnonymizedData = ({
rawData,
}: {
anonymizationFields?: AnonymizationFieldResponse[];
currentReplacements: Record<string, string> | undefined;
currentReplacements: Replacements | undefined;
getAnonymizedValue: ({
currentReplacements,
rawValue,
}: {
currentReplacements: Record<string, string> | undefined;
currentReplacements: Replacements | undefined;
rawValue: string;
}) => string;
getAnonymizedValues: GetAnonymizedValues;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@

import { invert } from 'lodash/fp';
import { v4 } from 'uuid';
import { Replacements } from '../../schemas';

export const getAnonymizedValue = ({
currentReplacements,
rawValue,
}: {
currentReplacements: Record<string, string> | undefined;
currentReplacements: Replacements | undefined;
rawValue: string;
}): string => {
if (currentReplacements != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const transformRawData = ({
currentReplacements,
rawValue,
}: {
currentReplacements: Record<string, string> | undefined;
currentReplacements: Replacements | undefined;
rawValue: string;
}) => string;
onNewReplacements?: (replacements: Replacements) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@
* 2.0.
*/

import { Replacements } from '../schemas';
import { AnonymizationFieldResponse } from '../schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen';

export interface AnonymizedValues {
/** The original values were transformed to these anonymized values */
anonymizedValues: string[];

/** A map from replacement value to original value */
replacements: Record<string, string>;
replacements: Replacements;
}

export interface AnonymizedData {
/** The original data was transformed to this anonymized data */
anonymizedData: Record<string, string[]>;

/** A map from replacement value to original value */
replacements: Record<string, string>;
replacements: Replacements;
}

export type GetAnonymizedValues = ({
Expand All @@ -31,13 +32,13 @@ export type GetAnonymizedValues = ({
rawData,
}: {
anonymizationFields?: AnonymizationFieldResponse[];
currentReplacements: Record<string, string> | undefined;
currentReplacements: Replacements | undefined;
field: string;
getAnonymizedValue: ({
currentReplacements,
rawValue,
}: {
currentReplacements: Record<string, string> | undefined;
currentReplacements: Replacements | undefined;
rawValue: string;
}) => string;
rawData: Record<string, unknown[]>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ import { getMessageContentAndRole } from './helpers';

const LLM_TYPE = 'ActionsClientLlm';

const DEFAULT_OPEN_AI_TEMPERATURE = 0.2;
const DEFAULT_TEMPERATURE = 0;

interface ActionsClientLlmParams {
actions: ActionsPluginStart;
connectorId: string;
llmType?: string;
logger: Logger;
request: KibanaRequest;
model?: string;
temperature?: number;
traceId?: string;
}

Expand All @@ -37,6 +41,7 @@ export class ActionsClientLlm extends LLM {
protected llmType: string;

model?: string;
temperature?: number;

constructor({
actions,
Expand All @@ -46,6 +51,7 @@ export class ActionsClientLlm extends LLM {
logger,
model,
request,
temperature,
}: ActionsClientLlmParams) {
super({});

Expand All @@ -56,6 +62,7 @@ export class ActionsClientLlm extends LLM {
this.#logger = logger;
this.#request = request;
this.model = model;
this.temperature = temperature;
}

_llmType() {
Expand Down Expand Up @@ -87,8 +94,8 @@ export class ActionsClientLlm extends LLM {
model: this.model,
messages: [assistantMessage], // the assistant message
...(this.llmType === 'openai'
? { n: 1, stop: null, temperature: 0.2 }
: { temperature: 0, stopSequences: [] }),
? { n: 1, stop: null, temperature: this.temperature ?? DEFAULT_OPEN_AI_TEMPERATURE }
: { temperature: this.temperature ?? DEFAULT_TEMPERATURE, stopSequences: [] }),
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
* 2.0.
*/

import { Replacements } from '../../schemas';

/** This mock returns the reverse of `value` */
export const mockGetAnonymizedValue = ({
currentReplacements,
rawValue,
}: {
currentReplacements: Record<string, string> | undefined;
currentReplacements: Replacements | undefined;
rawValue: string;
}): string => rawValue.split('').reverse().join('');
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ import { z } from 'zod';

export type GetCapabilitiesResponse = z.infer<typeof GetCapabilitiesResponse>;
export const GetCapabilitiesResponse = z.object({
assistantAlertsInsights: z.boolean(),
assistantModelEvaluation: z.boolean(),
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ paths:
schema:
type: object
properties:
assistantAlertsInsights:
type: boolean
assistantModelEvaluation:
type: boolean
required:
- assistantAlertsInsights
- assistantModelEvaluation
'400':
description: Generic Error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export const API_VERSIONS = {
export const PUBLIC_API_ACCESS = 'public';
export const INTERNAL_API_ACCESS = 'internal';

// Alerts Insights Schemas
export * from './insights/alerts/post_alerts_insights_route.gen';

// Evaluation Schemas
export * from './evaluation/post_evaluate_route.gen';
export * from './evaluation/get_evaluate_route.gen';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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 { z } from 'zod';

/*
* NOTICE: Do not edit this file manually.
* This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
*
* info:
* title: Alerts insights API endpoint
* version: 1
*/

import { AnonymizationFieldResponse } from '../../anonymization_fields/bulk_crud_anonymization_fields_route.gen';
import { Replacements, TraceData } from '../../conversations/common_attributes.gen';

/**
* An insight generated from one or more alerts
*/
export type AlertsInsight = z.infer<typeof AlertsInsight>;
export const AlertsInsight = z.object({
/**
* The alert IDs that the insight is based on
*/
alertIds: z.array(z.string()),
/**
* A detailed insight with bulleted markdown that always uses special syntax for field names and values from the source data.
*/
detailsMarkdown: z.string(),
/**
* A short (no more than a sentence) summary of the insight featuring only the host.name and user.name fields (when they are applicable), using the same syntax
*/
entitySummaryMarkdown: z.string(),
/**
* An array of MITRE ATT&CK tactic for the insight
*/
mitreAttackTactics: z.array(z.string()).optional(),
/**
* A markdown summary of insight, using the same syntax
*/
summaryMarkdown: z.string(),
/**
* A title for the insight, in plain text
*/
title: z.string(),
});

export type AlertsInsightsPostRequestBody = z.infer<typeof AlertsInsightsPostRequestBody>;
export const AlertsInsightsPostRequestBody = z.object({
alertsIndexPattern: z.string(),
anonymizationFields: z.array(AnonymizationFieldResponse),
connectorId: z.string(),
actionTypeId: z.string(),
model: z.string().optional(),
replacements: Replacements.optional(),
size: z.number(),
subAction: z.enum(['invokeAI', 'invokeStream']),
});
export type AlertsInsightsPostRequestBodyInput = z.input<typeof AlertsInsightsPostRequestBody>;

export type AlertsInsightsPostResponse = z.infer<typeof AlertsInsightsPostResponse>;
export const AlertsInsightsPostResponse = z.object({
connector_id: z.string().optional(),
insights: z.array(AlertsInsight).optional(),
replacements: Replacements.optional(),
status: z.string().optional(),
trace_data: TraceData.optional(),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
openapi: 3.0.0
info:
title: Alerts insights API endpoint
version: '1'
components:
x-codegen-enabled: true
schemas:
AlertsInsight:
type: object
description: An insight generated from one or more alerts
required:
- 'alertIds'
- 'detailsMarkdown'
- 'entitySummaryMarkdown'
- 'summaryMarkdown'
- 'title'
properties:
alertIds:
description: The alert IDs that the insight is based on
items:
type: string
type: array
detailsMarkdown:
description: A detailed insight with bulleted markdown that always uses special syntax for field names and values from the source data.
type: string
entitySummaryMarkdown:
description: A short (no more than a sentence) summary of the insight featuring only the host.name and user.name fields (when they are applicable), using the same syntax
type: string
mitreAttackTactics:
description: An array of MITRE ATT&CK tactic for the insight
items:
type: string
type: array
summaryMarkdown:
description: A markdown summary of insight, using the same syntax
type: string
title:
description: A title for the insight, in plain text
type: string


paths:
/internal/elastic_assistant/insights/alerts:
post:
operationId: AlertsInsightsPost
x-codegen-enabled: true
description: Generate insights from alerts
summary: Generate insights from alerts via the Elastic Assistant
tags:
- insights
- alerts
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- actionTypeId
- alertsIndexPattern
- anonymizationFields
- connectorId
- size
- subAction
properties:
alertsIndexPattern:
type: string
anonymizationFields:
items:
$ref: '../../anonymization_fields/bulk_crud_anonymization_fields_route.schema.yaml#/components/schemas/AnonymizationFieldResponse'
type: array
connectorId:
type: string
actionTypeId:
type: string
model:
type: string
replacements:
$ref: '../../conversations/common_attributes.schema.yaml#/components/schemas/Replacements'
size:
type: number
subAction:
type: string
enum:
- invokeAI
- invokeStream
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: object
properties:
connector_id:
type: string
insights:
type: array
items:
$ref: '#/components/schemas/AlertsInsight'
replacements:
$ref: '../../conversations/common_attributes.schema.yaml#/components/schemas/Replacements'
status:
type: string
trace_data:
$ref: '../../conversations/common_attributes.schema.yaml#/components/schemas/TraceData'
'400':
description: Bad request
content:
application/json:
schema:
type: object
properties:
statusCode:
type: number
error:
type: string
message:
type: string

Loading

0 comments on commit 32f43bf

Please sign in to comment.