[8.x] [Attack Discovery][Scheduling] Use core.services.featureFlags to control access to assistantAttackDiscoverySchedulingEnabled feature flag (#12005) (#217306) (#217480)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Attack Discovery][Scheduling] Use `core.services.featureFlags` to
control access to `assistantAttackDiscoverySchedulingEnabled` feature
flag (#12005) (#217306)](https://github.com/elastic/kibana/pull/217306)

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

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

<!--BACKPORT [{"author":{"name":"Ievgen
Sorokopud","email":"ievgen.sorokopud@elastic.co"},"sourceCommit":{"committedDate":"2025-04-08T08:24:35Z","message":"[Attack
Discovery][Scheduling] Use `core.services.featureFlags` to control
access to `assistantAttackDiscoverySchedulingEnabled` feature flag
(#12005) (#217306)\n\n## Summary\n\nFeature description:
[internal\nlink](https://github.com/elastic/security-team/issues/10142)\nPart
of:
[internal\nlink](https://github.com/elastic/security-team/issues/12005)\n\nThese
changes we switched to `core.services.featureFlags` to manage
the\n`assistantAttackDiscoverySchedulingEnabled` feature flag to
control\nvisibility of the Attack Discovery Scheduling feature.\n\nTo
enable the flag locally, add this in the
`kibana.dev.yml`:\n\n```\nfeature_flags.overrides:\n
securitySolution.assistantAttackDiscoverySchedulingEnabled:
true\n```","sha":"6ab8808d72e2482646ad832a1cad2a59e94cb32d","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:
SecuritySolution","Team:Security Generative
AI","backport:version","v9.1.0","v8.19.0"],"title":"[Attack
Discovery][Scheduling] Use `core.services.featureFlags` to control
access to `assistantAttackDiscoverySchedulingEnabled` feature flag
(#12005)","number":217306,"url":"https://github.com/elastic/kibana/pull/217306","mergeCommit":{"message":"[Attack
Discovery][Scheduling] Use `core.services.featureFlags` to control
access to `assistantAttackDiscoverySchedulingEnabled` feature flag
(#12005) (#217306)\n\n## Summary\n\nFeature description:
[internal\nlink](https://github.com/elastic/security-team/issues/10142)\nPart
of:
[internal\nlink](https://github.com/elastic/security-team/issues/12005)\n\nThese
changes we switched to `core.services.featureFlags` to manage
the\n`assistantAttackDiscoverySchedulingEnabled` feature flag to
control\nvisibility of the Attack Discovery Scheduling feature.\n\nTo
enable the flag locally, add this in the
`kibana.dev.yml`:\n\n```\nfeature_flags.overrides:\n
securitySolution.assistantAttackDiscoverySchedulingEnabled:
true\n```","sha":"6ab8808d72e2482646ad832a1cad2a59e94cb32d"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/217306","number":217306,"mergeCommit":{"message":"[Attack
Discovery][Scheduling] Use `core.services.featureFlags` to control
access to `assistantAttackDiscoverySchedulingEnabled` feature flag
(#12005) (#217306)\n\n## Summary\n\nFeature description:
[internal\nlink](https://github.com/elastic/security-team/issues/10142)\nPart
of:
[internal\nlink](https://github.com/elastic/security-team/issues/12005)\n\nThese
changes we switched to `core.services.featureFlags` to manage
the\n`assistantAttackDiscoverySchedulingEnabled` feature flag to
control\nvisibility of the Attack Discovery Scheduling feature.\n\nTo
enable the flag locally, add this in the
`kibana.dev.yml`:\n\n```\nfeature_flags.overrides:\n
securitySolution.assistantAttackDiscoverySchedulingEnabled:
true\n```","sha":"6ab8808d72e2482646ad832a1cad2a59e94cb32d"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
This commit is contained in:
Ievgen Sorokopud 2025-04-08 14:23:04 +02:00 committed by GitHub
parent 815dfb01a9
commit a6915c1a32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 45 additions and 28 deletions

View file

@ -62,4 +62,6 @@ export const DEFEND_INSIGHTS = `${ELASTIC_AI_ASSISTANT_INTERNAL_URL}/defend_insi
export const DEFEND_INSIGHTS_BY_ID = `${DEFEND_INSIGHTS}/{id}`;
// Attack Discovery
export const ATTACK_DISCOVERY_SCHEDULES_ENABLED_FEATURE_FLAG =
'securitySolution.assistantAttackDiscoverySchedulingEnabled' as const;
export const ATTACK_DISCOVERY_SCHEDULES_ALERT_TYPE_ID = 'attack-discovery' as const;

View file

@ -21,5 +21,4 @@ export type AssistantFeatureKey = keyof AssistantFeatures;
export const defaultAssistantFeatures = Object.freeze({
assistantModelEvaluation: false,
defendInsights: false,
assistantAttackDiscoverySchedulingEnabled: false,
});

View file

@ -20,5 +20,4 @@ export type GetCapabilitiesResponse = z.infer<typeof GetCapabilitiesResponse>;
export const GetCapabilitiesResponse = z.object({
assistantModelEvaluation: z.boolean(),
defendInsights: z.boolean(),
assistantAttackDiscoverySchedulingEnabled: z.boolean(),
});

View file

@ -24,12 +24,9 @@ paths:
type: boolean
defendInsights:
type: boolean
assistantAttackDiscoverySchedulingEnabled:
type: boolean
required:
- assistantModelEvaluation
- defendInsights
- assistantAttackDiscoverySchedulingEnabled
'400':
description: Generic Error
content:

View file

@ -7,7 +7,10 @@
import { PluginInitializerContext, CoreStart, Plugin, Logger } from '@kbn/core/server';
import { AssistantFeatures } from '@kbn/elastic-assistant-common';
import {
ATTACK_DISCOVERY_SCHEDULES_ENABLED_FEATURE_FLAG,
AssistantFeatures,
} from '@kbn/elastic-assistant-common';
import { ReplaySubject, type Subject } from 'rxjs';
import { MlPluginSetup } from '@kbn/ml-plugin/server';
import { events } from './lib/telemetry/event_based_telemetry';
@ -89,6 +92,25 @@ export class ElasticAssistantPlugin
registerRoutes(router, this.logger, this.getElserId);
// The featureFlags service is not available in the core setup, so we need
// to wait for the start services to be available to read the feature flags.
// This can take a while, but the plugin setup phase cannot run for a long time.
// As a workaround, this promise does not block the setup phase.
core
.getStartServices()
.then(([{ featureFlags }]) => {
// read all feature flags:
void Promise.all([
featureFlags.getBooleanValue(ATTACK_DISCOVERY_SCHEDULES_ENABLED_FEATURE_FLAG, false),
// add more feature flags here
]).then(([assistantAttackDiscoverySchedulingEnabled]) => {
// TODO: use `assistantAttackDiscoverySchedulingEnabled` to conditionally create alerts index
});
})
.catch((error) => {
this.logger.error(`error in security assistant plugin setup: ${error}`);
});
return {
actions: plugins.actions,
getRegisteredFeatures: (pluginName: string) => {

View file

@ -55,7 +55,6 @@ describe('AppContextService', () => {
appContextService.registerFeatures('super', {
assistantModelEvaluation: true,
defendInsights: true,
assistantAttackDiscoverySchedulingEnabled: true,
});
appContextService.stop();
@ -107,7 +106,6 @@ describe('AppContextService', () => {
...defaultAssistantFeatures,
assistantModelEvaluation: true,
defendInsights: true,
assistantAttackDiscoverySchedulingEnabled: true,
};
appContextService.start(mockAppContext);
@ -124,14 +122,12 @@ describe('AppContextService', () => {
...defaultAssistantFeatures,
assistantModelEvaluation: true,
defendInsights: true,
assistantAttackDiscoverySchedulingEnabled: true,
};
const pluginTwo = 'plugin2';
const featuresTwo: AssistantFeatures = {
...defaultAssistantFeatures,
assistantModelEvaluation: false,
defendInsights: false,
assistantAttackDiscoverySchedulingEnabled: false,
};
appContextService.start(mockAppContext);
@ -148,13 +144,11 @@ describe('AppContextService', () => {
...defaultAssistantFeatures,
assistantModelEvaluation: true,
defendInsights: true,
assistantAttackDiscoverySchedulingEnabled: true,
};
const featuresTwo: AssistantFeatures = {
...defaultAssistantFeatures,
assistantModelEvaluation: false,
defendInsights: false,
assistantAttackDiscoverySchedulingEnabled: false,
};
appContextService.start(mockAppContext);
@ -177,7 +171,6 @@ describe('AppContextService', () => {
const featuresSubset: Partial<AssistantFeatures> = {
assistantModelEvaluation: true,
defendInsights: true,
assistantAttackDiscoverySchedulingEnabled: true,
};
appContextService.start(mockAppContext);

View file

@ -114,11 +114,6 @@ export const allowedExperimentalValues = Object.freeze({
*/
assistantModelEvaluation: false,
/**
* Enables the Attack Discovery Scheduling functionality and API endpoint`.
*/
assistantAttackDiscoverySchedulingEnabled: false,
/**
* Enables the Managed User section inside the new user details flyout.
*/

View file

@ -13,7 +13,6 @@ import { DEFAULT_END, DEFAULT_START } from '@kbn/elastic-assistant-common';
import { SettingsFlyout } from '.';
import { ATTACK_DISCOVERY_SETTINGS } from './translations';
import { getDefaultQuery } from '../helpers';
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
import { useKibana } from '../../../common/lib/kibana';
import { TestProviders } from '../../../common/mock';
import { useSourcererDataView } from '../../../sourcerer/containers';
@ -81,15 +80,19 @@ const mockUseKibana = useKibana as jest.MockedFunction<typeof useKibana>;
const mockUseSourcererDataView = useSourcererDataView as jest.MockedFunction<
typeof useSourcererDataView
>;
const getBooleanValueMock = jest.fn();
describe('SettingsFlyout', () => {
beforeEach(() => {
jest.clearAllMocks();
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false);
getBooleanValueMock.mockReturnValue(false);
mockUseKibana.mockReturnValue({
services: {
featureFlags: {
getBooleanValue: getBooleanValueMock,
},
lens: {
EmbeddableComponent: () => <div data-test-subj="mockEmbeddableComponent" />,
},
@ -216,9 +219,9 @@ describe('SettingsFlyout', () => {
});
});
describe('when `assistantAttackDiscoverySchedulingEnabled` feature flag is enabled', () => {
describe('when `securitySolution.assistantAttackDiscoverySchedulingEnabled` feature flag is enabled', () => {
beforeEach(() => {
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true);
getBooleanValueMock.mockReturnValue(true);
render(
<TestProviders>
<SettingsFlyout {...defaultProps} />

View file

@ -17,9 +17,14 @@ import {
import React, { useCallback, useMemo, useState } from 'react';
import { DEFAULT_ATTACK_DISCOVERY_MAX_ALERTS } from '@kbn/elastic-assistant';
import { DEFAULT_END, DEFAULT_START } from '@kbn/elastic-assistant-common';
import {
ATTACK_DISCOVERY_SCHEDULES_ENABLED_FEATURE_FLAG,
DEFAULT_END,
DEFAULT_START,
} from '@kbn/elastic-assistant-common';
import type { Filter, Query } from '@kbn/es-query';
import { useKibana } from '../../../common/lib/kibana';
import { Footer } from './footer';
import * as i18n from './translations';
import { useSettingsView } from './hooks/use_settings_view';
@ -28,7 +33,6 @@ import type { AlertsSelectionSettings } from './types';
import { MIN_FLYOUT_WIDTH } from './constants';
import { getMaxAlerts } from './alert_selection/helpers/get_max_alerts';
import { getDefaultQuery } from '../helpers';
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
export const DEFAULT_STACK_BY_FIELD = 'kibana.alert.rule.name';
@ -59,12 +63,17 @@ const SettingsFlyoutComponent: React.FC<Props> = ({
setStart,
start,
}) => {
const {
services: { featureFlags },
} = useKibana();
const flyoutTitleId = useGeneratedHtmlId({
prefix: 'attackDiscoverySettingsFlyoutTitle',
});
const isAttackDiscoverySchedulingEnabled = useIsExperimentalFeatureEnabled(
'assistantAttackDiscoverySchedulingEnabled'
const isAttackDiscoverySchedulingEnabled = featureFlags.getBooleanValue(
ATTACK_DISCOVERY_SCHEDULES_ENABLED_FEATURE_FLAG,
false
);
const [settings, setSettings] = useState<AlertsSelectionSettings>({

View file

@ -591,8 +591,6 @@ export class Plugin implements ISecuritySolutionPlugin {
plugins.elasticAssistant.registerTools(APP_UI_ID, assistantTools);
const features = {
assistantModelEvaluation: config.experimentalFeatures.assistantModelEvaluation,
assistantAttackDiscoverySchedulingEnabled:
config.experimentalFeatures.assistantAttackDiscoverySchedulingEnabled,
};
plugins.elasticAssistant.registerFeatures(APP_UI_ID, features);
plugins.elasticAssistant.registerFeatures('management', features);