Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ export const SECURITY_SOLUTION_ENABLE_ASSET_INVENTORY_SETTING =
'securitySolution:enableAssetInventory' as const;
export const SECURITY_SOLUTION_ENABLE_CLOUD_CONNECTOR_SETTING =
'securitySolution:enableCloudConnector' as const;
export const SECURITY_SOLUTION_DEFAULT_VALUE_REPORT_MINUTES =
'securitySolution:defaultValueReportMinutes' as const;
export const SECURITY_SOLUTION_DEFAULT_VALUE_REPORT_RATE =
'securitySolution:defaultValueReportRate' as const;
export const SECURITY_SOLUTION_DEFAULT_VALUE_REPORT_TITLE =
'securitySolution:defaultValueReportTitle' as const;
// Timelion settings
export const TIMELION_ES_DEFAULT_INDEX_ID = 'timelion:es.default_index';
export const TIMELION_ES_TIME_FIELD_ID = 'timelion:es.timefield';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export const SECURITY_PROJECT_SETTINGS = [
settings.SECURITY_SOLUTION_ENABLE_GRAPH_VISUALIZATION_SETTING,
settings.SECURITY_SOLUTION_ENABLE_ASSET_INVENTORY_SETTING,
settings.SECURITY_SOLUTION_ENABLE_CLOUD_CONNECTOR_SETTING,
settings.SECURITY_SOLUTION_DEFAULT_VALUE_REPORT_MINUTES,
settings.SECURITY_SOLUTION_DEFAULT_VALUE_REPORT_RATE,
settings.SECURITY_SOLUTION_DEFAULT_VALUE_REPORT_TITLE,
Comment on lines +30 to +32
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stephmilovic, while cleaning up x-pack/solutions/security/plugins/security_solution_serverless/server/plugin.ts and removing the old default llm setting, I noticed that the other value report settings were not whitelisted in here. Were these intentionally not whitelisted before?

settings.GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR,
settings.GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR_DEFAULT_ONLY,
];
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,3 @@
*/

export const NO_DEFAULT_CONNECTOR = 'NO_DEFAULT_CONNECTOR';
export const AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED =
'aiAssistant.defaultLlmSettingEnabled' as const;
export const AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED_VALUE = true as const;
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,10 @@ const mockUseEnabledFeatures = useEnabledFeatures as jest.MockedFunction<typeof
describe('GenAiSettingsApp', () => {
const coreStart = coreMock.createStart();
const setBreadcrumbs = jest.fn();
const featureFlagsGetBooleanValueMock = jest.fn();

beforeEach(() => {
jest.clearAllMocks();

featureFlagsGetBooleanValueMock.mockReturnValue(true);

coreStart.application.capabilities = {
...coreStart.application.capabilities,
management: {
Expand All @@ -38,11 +35,6 @@ describe('GenAiSettingsApp', () => {
},
};

coreStart.featureFlags = {
...coreStart.featureFlags,
getBooleanValue: featureFlagsGetBooleanValueMock,
};

// Default mock for enabled features
mockUseEnabledFeatures.mockReturnValue({
showSpacesIntegration: true,
Expand Down Expand Up @@ -115,15 +107,6 @@ describe('GenAiSettingsApp', () => {
expect(screen.getByTestId('goToSpacesButton')).toBeInTheDocument();
});

it('does not render default llm setting when feature is disabled', () => {
featureFlagsGetBooleanValueMock.mockReturnValue(false);

renderComponent();

expect(screen.queryByTestId('defaultAiConnectorComboBox')).not.toBeInTheDocument();
expect(screen.queryByTestId('defaultAiConnectorCheckbox')).not.toBeInTheDocument();
});

it('should conditionally render sections based on settings', () => {
mockUseEnabledFeatures.mockReturnValue({
showSpacesIntegration: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,13 @@ import {
EuiTitle,
EuiLink,
useEuiTheme,
EuiButton,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import type { ManagementAppMountParams } from '@kbn/management-plugin/public';

import { getSpaceIdFromPath } from '@kbn/spaces-utils';
import { isEmpty } from 'lodash';
import {
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED,
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED_VALUE,
} from '../../common/constants';
import { useEnabledFeatures } from '../contexts/enabled_features_context';
import { useKibana } from '../hooks/use_kibana';
import { GoToSpacesButton } from './go_to_spaces_button';
Expand All @@ -46,7 +41,7 @@ interface GenAiSettingsAppProps {

export const GenAiSettingsApp: React.FC<GenAiSettingsAppProps> = ({ setBreadcrumbs }) => {
const { services } = useKibana();
const { application, http, docLinks, featureFlags } = services;
const { application, http, docLinks } = services;
const {
showSpacesIntegration,
isPermissionsBased,
Expand Down Expand Up @@ -97,11 +92,6 @@ export const GenAiSettingsApp: React.FC<GenAiSettingsAppProps> = ({ setBreadcrum
});
}, [application, http.basePath, isPermissionsBased]);

const showDefaultLlmSetting = featureFlags.getBooleanValue(
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED,
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED_VALUE
);

const connectorDescription = useMemo(() => {
if (!hasElasticManagedLlm) {
return (
Expand All @@ -112,7 +102,7 @@ export const GenAiSettingsApp: React.FC<GenAiSettingsAppProps> = ({ setBreadcrum
hasConnectorsAllPrivilege ? 'set up' : 'have'
} a Generative AI connector. {manageConnectors}`}
values={{
manageConnectors: showDefaultLlmSetting ? (
manageConnectors: (
<EuiLink
href={application.getUrlForApp('management', {
path: 'insightsAndAlerting/triggersActionsConnectors/connectors',
Expand All @@ -126,7 +116,7 @@ export const GenAiSettingsApp: React.FC<GenAiSettingsAppProps> = ({ setBreadcrum
}
/>
</EuiLink>
) : null,
),
}}
/>
</p>
Expand Down Expand Up @@ -156,7 +146,7 @@ export const GenAiSettingsApp: React.FC<GenAiSettingsAppProps> = ({ setBreadcrum
/>
</EuiLink>
),
manageConnectors: showDefaultLlmSetting ? (
manageConnectors: (
<EuiLink
href={application.getUrlForApp('management', {
path: 'insightsAndAlerting/triggersActionsConnectors/connectors',
Expand All @@ -168,7 +158,7 @@ export const GenAiSettingsApp: React.FC<GenAiSettingsAppProps> = ({ setBreadcrum
defaultMessage="Manage connectors"
/>
</EuiLink>
) : null,
),
elasticManagedLlm: (
<strong>
<FormattedMessage
Expand Down Expand Up @@ -198,7 +188,6 @@ export const GenAiSettingsApp: React.FC<GenAiSettingsAppProps> = ({ setBreadcrum
canManageSpaces,
docLinks,
application,
showDefaultLlmSetting,
]);

async function handleSave() {
Expand All @@ -208,34 +197,6 @@ export const GenAiSettingsApp: React.FC<GenAiSettingsAppProps> = ({ setBreadcrum
}
}

const manageConnectorsButton = useMemo(() => {
return (
<EuiButton
iconType="popout"
iconSide="right"
data-test-subj="manageConnectorsLink"
onClick={() => {
application.navigateToApp('management', {
path: 'insightsAndAlerting/triggersActionsConnectors/connectors',
openInNewTab: true,
});
}}
>
{hasConnectorsAllPrivilege ? (
<FormattedMessage
id="genAiSettings.goToConnectorsButtonLabel"
defaultMessage="Manage connectors"
/>
) : (
<FormattedMessage
id="genAiSettings.viewConnectorsButtonLabel"
defaultMessage="View connectors"
/>
)}
</EuiButton>
);
}, [application, hasConnectorsAllPrivilege]);

return (
<>
<div data-test-subj="genAiSettingsPage">
Expand Down Expand Up @@ -277,11 +238,7 @@ export const GenAiSettingsApp: React.FC<GenAiSettingsAppProps> = ({ setBreadcrum
<EuiFormRow fullWidth>
<EuiFlexGroup gutterSize="m" responsive={false}>
<EuiFlexItem grow={false}>
{showDefaultLlmSetting ? (
<DefaultAIConnector connectors={connectors} />
) : (
manageConnectorsButton
)}
<DefaultAIConnector connectors={connectors} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFormRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,22 +194,6 @@ export const ENABLE_NEWS_FEED_SETTING = 'securitySolution:enableNewsFeed' as con
/** This Kibana Advanced Setting sets a default AI connector for serverless AI features (EASE) */
export const DEFAULT_AI_CONNECTOR = 'securitySolution:defaultAIConnector' as const;

/** Feature flag for the default AI connector setting */
export const AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED =
'aiAssistant.defaultLlmSettingEnabled' as const;

/** The default value for the default AI connector setting */
export const AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED_VALUE = true as const;

/** This Kibana Advanced Setting sets a default AI value report minutes per alert */
export const DEFAULT_VALUE_REPORT_MINUTES = 'securitySolution:defaultValueReportMinutes' as const;

/** This Kibana Advanced Setting sets a default AI value report hourly analyst rate */
export const DEFAULT_VALUE_REPORT_RATE = 'securitySolution:defaultValueReportRate' as const;

/** This Kibana Advanced Setting sets a default title for the AI value report page */
export const DEFAULT_VALUE_REPORT_TITLE = 'securitySolution:defaultValueReportTitle' as const;

/** This Kibana Advanced Setting allows users to enable/disable querying cold and frozen data tiers in analyzer */
export const EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER =
'securitySolution:excludeColdAndFrozenTiersInAnalyzer' as const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ import { useDefaultAIConnectorId } from './use_default_ai_connector_id';
import { useKibana } from '../lib/kibana';
import { useAIConnectors } from './use_ai_connectors';
import { getDefaultConnector } from '@kbn/elastic-assistant/impl/assistant/helpers';
import {
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED,
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED_VALUE,
DEFAULT_AI_CONNECTOR,
} from '../../../common/constants';

jest.mock('../lib/kibana');
jest.mock('./use_ai_connectors');
Expand All @@ -26,12 +21,6 @@ const mockGetDefaultConnector = getDefaultConnector as jest.Mock;

describe('useDefaultAIConnectorId', () => {
const mockSettings = {};
const mockUiSettings = {
get: jest.fn(),
};
const mockFeatureFlags = {
getBooleanValue: jest.fn(),
};
const mockConnectors = [
{ id: 'connector-1', name: 'Connector 1' },
{ id: 'connector-2', name: 'Connector 2' },
Expand All @@ -43,8 +32,6 @@ describe('useDefaultAIConnectorId', () => {
mockUseKibana.mockReturnValue({
services: {
settings: mockSettings,
uiSettings: mockUiSettings,
featureFlags: mockFeatureFlags,
},
});

Expand All @@ -53,75 +40,37 @@ describe('useDefaultAIConnectorId', () => {
isLoading: false,
});

mockUiSettings.get.mockReturnValue('legacy-connector-id');
mockFeatureFlags.getBooleanValue.mockReturnValue(false);
mockGetDefaultConnector.mockReturnValue({ id: 'new-connector-id' });
mockGetDefaultConnector.mockReturnValue({ id: 'connector-id' });
});

it('should return legacy connector id when new default connector feature is disabled', () => {
mockFeatureFlags.getBooleanValue.mockReturnValue(false);

const { result } = renderHook(() => useDefaultAIConnectorId());

expect(result.current.defaultConnectorId).toBe('legacy-connector-id');
});

it('should return new connector id when new default connector feature is enabled', () => {
mockFeatureFlags.getBooleanValue.mockReturnValue(true);

it('should return connector id from getDefaultConnector', () => {
const { result } = renderHook(() => useDefaultAIConnectorId());

expect(result.current.defaultConnectorId).toBe('new-connector-id');
expect(result.current.defaultConnectorId).toBe('connector-id');
});

it('should return undefined when new default connector feature is enabled but getDefaultConnector returns undefined', () => {
mockFeatureFlags.getBooleanValue.mockReturnValue(true);
it('should return undefined when getDefaultConnector returns undefined', () => {
mockGetDefaultConnector.mockReturnValue(undefined);

const { result } = renderHook(() => useDefaultAIConnectorId());

expect(result.current.defaultConnectorId).toBeUndefined();
});

it('should return undefined when new default connector feature is enabled but getDefaultConnector returns null', () => {
mockFeatureFlags.getBooleanValue.mockReturnValue(true);
it('should return undefined when getDefaultConnector returns null', () => {
mockGetDefaultConnector.mockReturnValue(null);

const { result } = renderHook(() => useDefaultAIConnectorId());

expect(result.current.defaultConnectorId).toBeUndefined();
});

it('should call getBooleanValue with correct parameters', () => {
renderHook(() => useDefaultAIConnectorId());

expect(mockFeatureFlags.getBooleanValue).toHaveBeenCalledWith(
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED,
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED_VALUE
);
});

it('should call uiSettings.get with correct parameter', () => {
renderHook(() => useDefaultAIConnectorId());

expect(mockUiSettings.get).toHaveBeenCalledWith(DEFAULT_AI_CONNECTOR);
});

it('should call getDefaultConnector with correct parameters', () => {
renderHook(() => useDefaultAIConnectorId());

expect(mockGetDefaultConnector).toHaveBeenCalledWith(mockConnectors, mockSettings);
});

it('should return undefined when legacy connector id is undefined and new feature is disabled', () => {
mockUiSettings.get.mockReturnValue(undefined);
mockFeatureFlags.getBooleanValue.mockReturnValue(false);

const { result } = renderHook(() => useDefaultAIConnectorId());

expect(result.current.defaultConnectorId).toBeUndefined();
});

it('should return isLoading true when connectors are loading', () => {
mockUseAIConnectors.mockReturnValue({
aiConnectors: mockConnectors,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,20 @@

import { getDefaultConnector } from '@kbn/elastic-assistant/impl/assistant/helpers';
import { useMemo } from 'react';
import {
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED,
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED_VALUE,
DEFAULT_AI_CONNECTOR,
} from '../../../common/constants';
import { useAIConnectors } from './use_ai_connectors';
import { useKibana } from '../lib/kibana';

export const useDefaultAIConnectorId = () => {
const { settings, uiSettings, featureFlags } = useKibana().services;
const { settings } = useKibana().services;

const { aiConnectors: connectors, isLoading: isLoadingConnectors } = useAIConnectors();
const legacyDefaultConnectorId = uiSettings.get<string>(DEFAULT_AI_CONNECTOR);
const useNewDefaultConnector = featureFlags.getBooleanValue(
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED,
AI_ASSISTANT_DEFAULT_LLM_SETTING_ENABLED_VALUE
);
const newDefaultConnectorId = getDefaultConnector(connectors, settings)?.id;
const defaultConnectorId = getDefaultConnector(connectors, settings)?.id;

return useMemo(
() => ({
defaultConnectorId: useNewDefaultConnector ? newDefaultConnectorId : legacyDefaultConnectorId,
defaultConnectorId,
isLoading: isLoadingConnectors,
}),
[useNewDefaultConnector, newDefaultConnectorId, legacyDefaultConnectorId, isLoadingConnectors]
[defaultConnectorId, isLoadingConnectors]
);
};
Loading