[9.0] [Security solution] Read config from preconfigured connectors in Assistant/Attack Discovery (#216700) (#216872)

# Backport

This will backport the following commits from `main` to `9.0`:
- [[Security solution] Read `config` from preconfigured connectors in
Assistant/Attack Discovery
(#216700)](https://github.com/elastic/kibana/pull/216700)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Steph
Milovic","email":"stephanie.milovic@elastic.co"},"sourceCommit":{"committedDate":"2025-04-02T15:04:06Z","message":"[Security
solution] Read `config` from preconfigured connectors in
Assistant/Attack Discovery
(#216700)","sha":"73974a2f88a2b0971dd94c8775ebc1805f1a2078","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:
SecuritySolution","Team:Security Generative
AI","backport:version","v9.1.0","v8.19.0","v8.18.1","v9.0.1"],"title":"[Security
solution] Read `config` from preconfigured connectors in
Assistant/Attack
Discovery","number":216700,"url":"https://github.com/elastic/kibana/pull/216700","mergeCommit":{"message":"[Security
solution] Read `config` from preconfigured connectors in
Assistant/Attack Discovery
(#216700)","sha":"73974a2f88a2b0971dd94c8775ebc1805f1a2078"}},"sourceBranch":"main","suggestedTargetBranches":["8.18","9.0"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/216700","number":216700,"mergeCommit":{"message":"[Security
solution] Read `config` from preconfigured connectors in
Assistant/Attack Discovery
(#216700)","sha":"73974a2f88a2b0971dd94c8775ebc1805f1a2078"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/216869","number":216869,"state":"OPEN"},{"branch":"8.18","label":"v8.18.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.0","label":"v9.0.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
This commit is contained in:
Steph Milovic 2025-04-02 11:25:00 -06:00 committed by GitHub
parent d6901a94e9
commit 6c432a835a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 108 additions and 19 deletions

View file

@ -0,0 +1,94 @@
/*
* 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 {
getGenAiConfig,
getActionTypeTitle,
getConnectorTypeTitle,
GenAiConfig,
OpenAiProviderType,
} from './helpers';
import { PRECONFIGURED_CONNECTOR } from './translations';
import type {
ActionConnector,
ActionTypeModel,
ActionTypeRegistryContract,
} from '@kbn/triggers-actions-ui-plugin/public';
const mockConnector = (config: GenAiConfig, isPreconfigured = false) => ({
isPreconfigured,
config,
actionTypeId: 'test-action',
});
describe('getGenAiConfig', () => {
test('returns empty object when connector is undefined', () => {
expect(getGenAiConfig(undefined)).toEqual({});
});
test('extracts apiProvider, apiUrl, and defaultModel from connector config', () => {
const connector = mockConnector({
apiProvider: OpenAiProviderType.OpenAi,
apiUrl: 'https://api.openai.com',
defaultModel: 'gpt-4',
}) as ActionConnector;
expect(getGenAiConfig(connector)).toEqual({
apiProvider: OpenAiProviderType.OpenAi,
apiUrl: 'https://api.openai.com',
defaultModel: 'gpt-4',
});
});
test('extracts api-version from Azure API URL', () => {
const connector = mockConnector({
apiProvider: OpenAiProviderType.AzureAi,
apiUrl: 'https://api.azure.com?api-version=2024-01-01',
}) as ActionConnector;
expect(getGenAiConfig(connector)).toEqual({
apiProvider: OpenAiProviderType.AzureAi,
apiUrl: 'https://api.azure.com?api-version=2024-01-01',
defaultModel: '2024-01-01',
});
});
});
describe('getActionTypeTitle', () => {
test('returns actionTypeTitle if defined', () => {
expect(getActionTypeTitle({ actionTypeTitle: 'Test Action' } as ActionTypeModel)).toBe(
'Test Action'
);
});
test('returns id if actionTypeTitle is undefined', () => {
expect(getActionTypeTitle({ id: 'test-id' } as ActionTypeModel)).toBe('test-id');
});
});
describe('getConnectorTypeTitle', () => {
const mockActionTypeRegistry = {
get: jest.fn().mockReturnValue({ actionTypeTitle: 'Fallback Action' }),
} as unknown as ActionTypeRegistryContract;
test('returns null when connector is undefined', () => {
expect(getConnectorTypeTitle(undefined, mockActionTypeRegistry)).toBeNull();
});
test('returns PRECONFIGURED_CONNECTOR for preconfigured connectors', () => {
const connector = mockConnector({}, true) as ActionConnector;
expect(getConnectorTypeTitle(connector, mockActionTypeRegistry)).toBe(PRECONFIGURED_CONNECTOR);
});
test('returns apiProvider if defined in config', () => {
const connector = mockConnector({ apiProvider: OpenAiProviderType.OpenAi }) as ActionConnector;
expect(getConnectorTypeTitle(connector, mockActionTypeRegistry)).toBe('OpenAI');
});
test('returns action type title from registry if apiProvider is undefined', () => {
const connector = mockConnector({}) as ActionConnector;
expect(getConnectorTypeTitle(connector, mockActionTypeRegistry)).toBe('Fallback Action');
});
});

View file

@ -15,13 +15,13 @@ import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/typ
import { PRECONFIGURED_CONNECTOR } from './translations';
// aligns with OpenAiProviderType from '@kbn/stack-connectors-plugin/common/openai/types'
enum OpenAiProviderType {
export enum OpenAiProviderType {
OpenAi = 'OpenAI',
AzureAi = 'Azure OpenAI',
Other = 'Other',
}
interface GenAiConfig {
export interface GenAiConfig {
apiProvider?: OpenAiProviderType;
apiUrl?: string;
defaultModel?: string;
@ -29,26 +29,21 @@ interface GenAiConfig {
/**
* Returns the GenAiConfig for a given ActionConnector. Note that if the connector is preconfigured,
* the config will be undefined as the connector is neither available nor editable.
* the config MAY be undefined if exposeConfig: true is absent
*
* @param connector
*/
export const getGenAiConfig = (connector: ActionConnector | undefined): GenAiConfig | undefined => {
if (!connector?.isPreconfigured) {
const config = (connector as ActionConnectorProps<GenAiConfig, unknown>)?.config;
const { apiProvider, apiUrl, defaultModel } = config ?? {};
return {
apiProvider,
apiUrl,
defaultModel:
apiProvider === OpenAiProviderType.AzureAi
? getAzureApiVersionParameter(apiUrl ?? '')
: defaultModel,
};
}
return undefined; // the connector is neither available nor editable
export const getGenAiConfig = (connector: ActionConnector | undefined): GenAiConfig => {
const config = (connector as ActionConnectorProps<GenAiConfig, unknown>)?.config;
const { apiProvider, apiUrl, defaultModel } = config ?? {};
return {
apiProvider,
apiUrl,
defaultModel:
apiProvider === OpenAiProviderType.AzureAi
? getAzureApiVersionParameter(apiUrl ?? '')
: defaultModel,
};
};
export const getActionTypeTitle = (actionType: ActionTypeModel): string => {