Skip to content

Commit

Permalink
[Security AI] Add Kibana Support for Security AI Prompts Integration (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
stephmilovic authored Jan 28, 2025
1 parent b998946 commit 7af5a83
Show file tree
Hide file tree
Showing 86 changed files with 1,921 additions and 399 deletions.
9 changes: 9 additions & 0 deletions packages/kbn-check-mappings-update-cli/current_fields.json
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,15 @@
"username"
],
"search-telemetry": [],
"security-ai-prompt": [
"description",
"model",
"prompt",
"prompt.default",
"promptGroupId",
"promptId",
"provider"
],
"security-rule": [
"rule_id",
"version"
Expand Down
27 changes: 27 additions & 0 deletions packages/kbn-check-mappings-update-cli/current_mappings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3023,6 +3023,33 @@
"dynamic": false,
"properties": {}
},
"security-ai-prompt": {
"dynamic": false,
"properties": {
"description": {
"type": "text"
},
"model": {
"type": "keyword"
},
"prompt": {
"properties": {
"default": {
"type": "text"
}
}
},
"promptGroupId": {
"type": "keyword"
},
"promptId": {
"type": "keyword"
},
"provider": {
"type": "keyword"
}
}
},
"security-rule": {
"dynamic": false,
"properties": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ export { registerCoreObjectTypes } from './registration';

// set minimum number of registered saved objects to ensure no object types are removed after 8.8
// declared in internal implementation exclicilty to prevent unintended changes.
export const SAVED_OBJECT_TYPES_COUNT = 127 as const;
export const SAVED_OBJECT_TYPES_COUNT = 128 as const;
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"search": "0aa6eefb37edd3145be340a8b67779c2ca578b22",
"search-session": "b2fcd840e12a45039ada50b1355faeafa39876d1",
"search-telemetry": "b568601618744720b5662946d3103e3fb75fe8ee",
"security-ai-prompt": "cc8ee5aaa9d001e89c131bbd5af6bc80bc271046",
"security-rule": "07abb4d7e707d91675ec0495c73816394c7b521f",
"security-solution-signals-migration": "9d99715fe5246f19de2273ba77debd2446c36bb1",
"siem-detection-engine-rule-actions": "54f08e23887b20da7c805fab7c60bc67c428aff9",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ const previouslyRegisteredTypes = [
'search',
'search-session',
'search-telemetry',
'security-ai-prompt',
'security-rule',
'security-solution-signals-migration',
'risk-engine-configuration',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export {
isInferenceRequestError,
isInferenceRequestAbortedError,
} from './src/errors';
export { elasticModelDictionary } from './src/const';

export { truncateList } from './src/truncate_list';
export {
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*/

import { ElasticModelDictionary } from './types';

export const elasticModelDictionary: ElasticModelDictionary = {
'rainbow-sprinkles': {
provider: 'bedrock',
model: 'us.anthropic.claude-3-5-sonnet-20240620-v1:0',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* 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 ElasticModelDictionary {
[key: string]: {
provider: string;
model: string;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ export const item: GetInfoResponse['item'] = {
index_pattern: [],
lens: [],
map: [],
security_ai_prompt: [],
security_rule: [],
csp_rule_template: [],
tag: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export const item: GetInfoResponse['item'] = {
ml_module: [],
osquery_pack_asset: [],
osquery_saved_query: [],
security_ai_prompt: [],
security_rule: [],
csp_rule_template: [],
tag: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ describe('Fleet - packageToPackagePolicy', () => {
map: [],
lens: [],
ml_module: [],
security_ai_prompt: [],
security_rule: [],
tag: [],
osquery_pack_asset: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export enum KibanaAssetType {
indexPattern = 'index_pattern',
map = 'map',
mlModule = 'ml_module',
securityAIPrompt = 'security_ai_prompt',
securityRule = 'security_rule',
cloudSecurityPostureRuleTemplate = 'csp_rule_template',
osqueryPackAsset = 'osquery_pack_asset',
Expand All @@ -77,6 +78,7 @@ export enum KibanaSavedObjectType {
indexPattern = 'index-pattern',
map = 'map',
mlModule = 'ml-module',
securityAIPrompt = 'security-ai-prompt',
securityRule = 'security-rule',
cloudSecurityPostureRuleTemplate = 'csp-rule-template',
osqueryPackAsset = 'osquery-pack-asset',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ export const AssetTitleMap: Record<
map: i18n.translate('xpack.fleet.epm.assetTitles.maps', {
defaultMessage: 'Maps',
}),
'security-ai-prompt': i18n.translate('xpack.fleet.epm.assetTitles.securityAIPrompt', {
defaultMessage: 'Security AI prompt',
}),
security_ai_prompt: i18n.translate('xpack.fleet.epm.assetTitles.securityAIPrompt', {
defaultMessage: 'Security AI prompt',
}),
'security-rule': i18n.translate('xpack.fleet.epm.assetTitles.securityRules', {
defaultMessage: 'Security rules',
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ describe('schema validation', () => {
map: [],
index_pattern: [],
ml_module: [],
security_ai_prompt: [],
security_rule: [],
tag: [],
csp_rule_template: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ packageInfoCache.set('test_package-0.0.0', {
index_pattern: [],
map: [],
lens: [],
security_ai_prompt: [],
security_rule: [],
ml_module: [],
tag: [],
Expand Down Expand Up @@ -122,6 +123,7 @@ packageInfoCache.set('osquery_manager-0.3.0', {
index_pattern: [],
map: [],
lens: [],
security_ai_prompt: [],
security_rule: [],
ml_module: [],
tag: [],
Expand Down Expand Up @@ -172,6 +174,7 @@ packageInfoCache.set('profiler_symbolizer-8.8.0-preview', {
index_pattern: [],
map: [],
lens: [],
security_ai_prompt: [],
security_rule: [],
ml_module: [],
tag: [],
Expand Down Expand Up @@ -222,6 +225,7 @@ packageInfoCache.set('profiler_collector-8.9.0-preview', {
index_pattern: [],
map: [],
lens: [],
security_ai_prompt: [],
security_rule: [],
ml_module: [],
tag: [],
Expand Down Expand Up @@ -264,6 +268,7 @@ packageInfoCache.set('apm-8.9.0-preview', {
index_pattern: [],
map: [],
lens: [],
security_ai_prompt: [],
security_rule: [],
ml_module: [],
tag: [],
Expand Down Expand Up @@ -306,6 +311,7 @@ packageInfoCache.set('elastic_connectors-1.0.0', {
index_pattern: [],
map: [],
lens: [],
security_ai_prompt: [],
security_rule: [],
ml_module: [],
tag: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ import { deleteKibanaSavedObjectsAssets } from '../../packages/remove';
import { FleetError, KibanaSOReferenceError } from '../../../../errors';
import { withPackageSpan } from '../../packages/utils';

import { appContextService } from '../../..';

import { tagKibanaAssets } from './tag_assets';
import { getSpaceAwareSaveobjectsClients } from './saved_objects';
import { appContextService } from '../../..';

const MAX_ASSETS_TO_INSTALL_IN_PARALLEL = 1000;

Expand Down Expand Up @@ -70,6 +71,7 @@ export const KibanaSavedObjectTypeMapping: Record<KibanaAssetType, KibanaSavedOb
[KibanaAssetType.visualization]: KibanaSavedObjectType.visualization,
[KibanaAssetType.lens]: KibanaSavedObjectType.lens,
[KibanaAssetType.mlModule]: KibanaSavedObjectType.mlModule,
[KibanaAssetType.securityAIPrompt]: KibanaSavedObjectType.securityAIPrompt,
[KibanaAssetType.securityRule]: KibanaSavedObjectType.securityRule,
[KibanaAssetType.cloudSecurityPostureRuleTemplate]:
KibanaSavedObjectType.cloudSecurityPostureRuleTemplate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ export const CAPABILITIES = `${BASE_PATH}/capabilities`;
Licensing requirements
*/
export const MINIMUM_AI_ASSISTANT_LICENSE = 'enterprise' as const;

// Saved Objects
export const promptSavedObjectType = 'security-ai-prompt';
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ import type { Logger } from '@kbn/logging';
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { FakeLLM } from '@langchain/core/utils/testing';
import { createOpenAIFunctionsAgent } from 'langchain/agents';
import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock';
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
import {
ATTACK_DISCOVERY_GENERATION_DETAILS_MARKDOWN,
ATTACK_DISCOVERY_GENERATION_ENTITY_SUMMARY_MARKDOWN,
ATTACK_DISCOVERY_GENERATION_INSIGHTS,
ATTACK_DISCOVERY_GENERATION_MITRE_ATTACK_TACTICS,
ATTACK_DISCOVERY_GENERATION_SUMMARY_MARKDOWN,
ATTACK_DISCOVERY_GENERATION_TITLE,
ATTACK_DISCOVERY_CONTINUE,
ATTACK_DISCOVERY_DEFAULT,
ATTACK_DISCOVERY_REFINE,
} from '../server/lib/prompt/prompts';
import { getDefaultAssistantGraph } from '../server/lib/langchain/graphs/default_assistant_graph/graph';
import { getDefaultAttackDiscoveryGraph } from '../server/lib/attack_discovery/graphs/default_attack_discovery_graph';

Expand Down Expand Up @@ -49,11 +62,13 @@ async function getAssistantGraph(logger: Logger): Promise<Drawable> {
streamRunnable: false,
});
const graph = getDefaultAssistantGraph({
actionsClient: actionsClientMock.create(),
agentRunnable,
logger,
createLlmInstance,
tools: [],
replacements: {},
savedObjectsClient: savedObjectsClientMock.create(),
});
return graph.getGraph();
}
Expand All @@ -67,6 +82,17 @@ async function getAttackDiscoveryGraph(logger: Logger): Promise<Drawable> {
llm: mockLlm as unknown as ActionsClientLlm,
logger,
replacements: {},
prompts: {
default: ATTACK_DISCOVERY_DEFAULT,
refine: ATTACK_DISCOVERY_REFINE,
continue: ATTACK_DISCOVERY_CONTINUE,
detailsMarkdown: ATTACK_DISCOVERY_GENERATION_DETAILS_MARKDOWN,
entitySummaryMarkdown: ATTACK_DISCOVERY_GENERATION_ENTITY_SUMMARY_MARKDOWN,
mitreAttackTactics: ATTACK_DISCOVERY_GENERATION_MITRE_ATTACK_TACTICS,
summaryMarkdown: ATTACK_DISCOVERY_GENERATION_SUMMARY_MARKDOWN,
title: ATTACK_DISCOVERY_GENERATION_TITLE,
insights: ATTACK_DISCOVERY_GENERATION_INSIGHTS,
},
size: 20,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ export const createMockClients = () => {
getCurrentUser: jest.fn(),
inference: jest.fn(),
llmTasks: jest.fn(),
savedObjectsClient: core.savedObjects.client,
},
savedObjectsClient: core.savedObjects.client,

licensing: {
...licensingMock.createRequestHandlerContext({ license }),
Expand Down Expand Up @@ -148,6 +148,7 @@ const createElasticAssistantRequestContextMock = (
inference: { getClient: jest.fn() },
llmTasks: { retrieveDocumentationAvailable: jest.fn(), retrieveDocumentation: jest.fn() },
core: clients.core,
savedObjectsClient: clients.elasticAssistant.savedObjectsClient,
telemetry: clients.elasticAssistant.telemetry,
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { ActionsClient } from '@kbn/actions-plugin/server';
import type { Connector } from '@kbn/actions-plugin/server/application/connector/types';
import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks';
Expand Down Expand Up @@ -46,7 +45,6 @@ jest.mock('./helpers/get_evaluator_llm', () => {
getEvaluatorLlm: jest.fn().mockResolvedValue(mockLlm),
};
});

const actionsClient = {
get: jest.fn(),
} as unknown as ActionsClient;
Expand All @@ -61,7 +59,22 @@ const logger = loggerMock.create();
const mockEsClient = elasticsearchServiceMock.createElasticsearchClient();
const runName = 'test-run-name';

const connectors = [mockExperimentConnector];
const connectors = [
{
...mockExperimentConnector,
prompts: {
default: '',
refine: '',
continue: '',
detailsMarkdown: '',
entitySummaryMarkdown: '',
mitreAttackTactics: '',
summaryMarkdown: '',
title: '',
insights: '',
},
},
];

const projectName = 'test-lang-smith-project';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ import { getLangSmithTracer } from '@kbn/langchain/server/tracers/langsmith';
import { asyncForEach } from '@kbn/std';
import { PublicMethodsOf } from '@kbn/utility-types';

import { CombinedPrompts } from '../graphs/default_attack_discovery_graph/nodes/helpers/prompts';
import { DEFAULT_EVAL_ANONYMIZATION_FIELDS } from './constants';
import { AttackDiscoveryGraphMetadata } from '../../langchain/graphs';
import { DefaultAttackDiscoveryGraph } from '../graphs/default_attack_discovery_graph';
import { getLlmType } from '../../../routes/utils';
import { runEvaluations } from './run_evaluations';

interface ConnectorWithPrompts extends Connector {
prompts: CombinedPrompts;
}
export const evaluateAttackDiscovery = async ({
actionsClient,
attackDiscoveryGraphs,
Expand All @@ -43,7 +47,7 @@ export const evaluateAttackDiscovery = async ({
attackDiscoveryGraphs: AttackDiscoveryGraphMetadata[];
alertsIndexPattern: string;
anonymizationFields?: AnonymizationFieldResponse[];
connectors: Connector[];
connectors: ConnectorWithPrompts[];
connectorTimeout: number;
datasetName: string;
esClient: ElasticsearchClient;
Expand Down Expand Up @@ -96,6 +100,7 @@ export const evaluateAttackDiscovery = async ({
esClient,
llm,
logger,
prompts: connector.prompts,
size,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const graphState: GraphState = {
],
combinedGenerations: 'generations',
combinedRefinements: 'refinements',
continuePrompt: 'continue',
errors: [],
generationAttempts: 0,
generations: [],
Expand Down
Loading

0 comments on commit 7af5a83

Please sign in to comment.