[AI_SOC] Add tier/add-on configuration (#213425)

This commit is contained in:
Tomasz Ciecierski 2025-03-07 11:46:42 +01:00 committed by GitHub
parent e62cb6a37a
commit 81db1a127a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 44 additions and 42 deletions

View file

@ -12,11 +12,13 @@ export const productLine = schema.oneOf([
schema.literal(ProductLine.security),
schema.literal(ProductLine.endpoint),
schema.literal(ProductLine.cloud),
schema.literal(ProductLine.aiSoc),
]);
export type SecurityProductLine = TypeOf<typeof productLine>;
export const productTier = schema.oneOf([
schema.literal(ProductTier.searchAiLake),
schema.literal(ProductTier.essentials),
schema.literal(ProductTier.complete),
]);

View file

@ -8,18 +8,27 @@
import type { ProductFeatureKeys } from '@kbn/security-solution-features';
import { ProductFeatureKey } from '@kbn/security-solution-features/keys';
import type { SecurityProductLine, SecurityProductTier } from '../config';
import { ProductLine } from '../product';
type PliProductFeatures = Readonly<
Record<SecurityProductLine, Readonly<Record<SecurityProductTier, Readonly<ProductFeatureKeys>>>>
>;
export const PLI_PRODUCT_FEATURES: PliProductFeatures = {
security: {
[ProductLine.aiSoc]: {
search_ai_lake: [ProductFeatureKey.attackDiscovery, ProductFeatureKey.assistant],
essentials: [ProductFeatureKey.attackDiscovery, ProductFeatureKey.assistant],
complete: [ProductFeatureKey.attackDiscovery, ProductFeatureKey.assistant],
},
[ProductLine.security]: {
search_ai_lake: [],
essentials: [
ProductFeatureKey.endpointHostManagement,
ProductFeatureKey.endpointPolicyManagement,
],
complete: [
ProductFeatureKey.endpointHostManagement,
ProductFeatureKey.endpointPolicyManagement,
ProductFeatureKey.advancedInsights,
ProductFeatureKey.assistant,
ProductFeatureKey.attackDiscovery,
@ -33,13 +42,17 @@ export const PLI_PRODUCT_FEATURES: PliProductFeatures = {
ProductFeatureKey.siemMigrations,
],
},
endpoint: {
[ProductLine.endpoint]: {
search_ai_lake: [], // endpoint add-on not available in search_ai_lake tier
essentials: [
ProductFeatureKey.endpointPolicyProtections,
ProductFeatureKey.endpointArtifactManagement,
ProductFeatureKey.endpointExceptions,
],
complete: [
ProductFeatureKey.endpointPolicyProtections,
ProductFeatureKey.endpointArtifactManagement,
ProductFeatureKey.endpointExceptions,
ProductFeatureKey.endpointHostIsolationExceptions,
ProductFeatureKey.endpointResponseActions,
ProductFeatureKey.osqueryAutomatedResponseActions,
@ -49,8 +62,9 @@ export const PLI_PRODUCT_FEATURES: PliProductFeatures = {
ProductFeatureKey.securityWorkflowInsights,
],
},
cloud: {
[ProductLine.cloud]: {
search_ai_lake: [], // cloud add-on not available in search_ai_lake tier
essentials: [ProductFeatureKey.cloudSecurityPosture],
complete: [],
complete: [ProductFeatureKey.cloudSecurityPosture],
},
} as const;

View file

@ -4,44 +4,33 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { getProductProductFeatures } from './pli_features';
import { getEnabledProductFeatures } from './pli_features';
import * as pliConfig from './pli_config';
import { ProductLine, ProductTier } from '../product';
describe('getProductProductFeatures', () => {
it('should return the essentials PLIs features', () => {
// @ts-ignore reassigning readonly value for testing
it('returns an empty array if no product types are provided', () => {
expect(getEnabledProductFeatures([])).toEqual([]);
});
it('returns features for a single product type', () => {
// @ts-ignore- reassigning readonly value for testing
pliConfig.PLI_PRODUCT_FEATURES = {
security: {
search_ai_lake: [],
essentials: ['foo'],
complete: ['baz'],
},
};
const productFeatureKeys = getProductProductFeatures([
const productFeatureKeys = getEnabledProductFeatures([
{ product_line: ProductLine.security, product_tier: ProductTier.essentials },
]);
expect(productFeatureKeys).toEqual(['foo']);
});
it('should return the complete PLIs features, which includes essentials', () => {
// @ts-ignore reassigning readonly value for testing
pliConfig.PLI_PRODUCT_FEATURES = {
security: {
essentials: ['foo'],
complete: ['baz'],
},
};
const productFeatureKeys = getProductProductFeatures([
{ product_line: ProductLine.security, product_tier: ProductTier.complete },
]);
expect(productFeatureKeys).toEqual(['foo', 'baz']);
});
it('returns an empty object if no PLIs are enabled', () => {
expect(getProductProductFeatures([])).toEqual([]);
expect(getEnabledProductFeatures([])).toEqual([]);
});
});

View file

@ -7,24 +7,19 @@
import type { ProductFeatureKeys } from '@kbn/security-solution-features';
import type { SecurityProductTypes } from '../config';
import { ProductTier } from '../product';
import { PLI_PRODUCT_FEATURES } from './pli_config';
/**
* Returns the U (union) of all PLIs from the enabled productTypes in a single array.
*/
export const getProductProductFeatures = (
export const getEnabledProductFeatures = (
productTypes: SecurityProductTypes
): ProductFeatureKeys => {
const productFeatureKeys = productTypes.reduce<ProductFeatureKeys>(
return productTypes.reduce<ProductFeatureKeys>(
(productFeatures, { product_line: line, product_tier: tier }) => {
if (tier === ProductTier.complete) {
productFeatures.push(...PLI_PRODUCT_FEATURES[line][ProductTier.essentials]);
}
productFeatures.push(...PLI_PRODUCT_FEATURES[line][tier]);
return productFeatures;
},
[]
);
return productFeatureKeys;
};

View file

@ -9,9 +9,11 @@ export enum ProductLine {
security = 'security',
endpoint = 'endpoint',
cloud = 'cloud',
aiSoc = 'ai_soc',
}
export enum ProductTier {
searchAiLake = 'search_ai_lake',
essentials = 'essentials',
complete = 'complete',
}

View file

@ -24,7 +24,7 @@ import {
} from '../common/experimental_features';
import { setOnboardingSettings } from './onboarding';
import { getAdditionalChargesMessage } from './components/additional_charges_message';
import { getProductProductFeatures } from '../common/pli/pli_features';
import { getEnabledProductFeatures } from '../common/pli/pli_features';
export class SecuritySolutionServerlessPlugin
implements
@ -55,7 +55,7 @@ export class SecuritySolutionServerlessPlugin
securitySolution.experimentalFeatures
).features;
securitySolution.setProductFeatureKeys(getProductProductFeatures(productTypes));
securitySolution.setProductFeatureKeys(getEnabledProductFeatures(productTypes));
return {};
}

View file

@ -14,9 +14,9 @@ import type { UpsellingService } from '@kbn/security-solution-upselling/service'
import { mockServices } from '../common/services/__mocks__/services.mock';
import { of } from 'rxjs';
const mockGetProductProductFeatures = jest.fn();
const mockGetEnabledProductFeatures = jest.fn();
jest.mock('../../common/pli/pli_features', () => ({
getProductProductFeatures: () => mockGetProductProductFeatures(),
getEnabledProductFeatures: () => mockGetEnabledProductFeatures(),
}));
const setPages = jest.fn();
@ -42,7 +42,7 @@ describe('registerUpsellings', () => {
});
it('should not register anything when all PLIs features are enabled', () => {
mockGetProductProductFeatures.mockReturnValue(ALL_PRODUCT_FEATURE_KEYS);
mockGetEnabledProductFeatures.mockReturnValue(ALL_PRODUCT_FEATURE_KEYS);
registerUpsellings(allProductTypes, mockServices);
@ -57,7 +57,7 @@ describe('registerUpsellings', () => {
});
it('should register all upsellings pages, sections and messages when PLIs features are disabled', () => {
mockGetProductProductFeatures.mockReturnValue([]);
mockGetEnabledProductFeatures.mockReturnValue([]);
registerUpsellings(allProductTypes, mockServices);

View file

@ -11,7 +11,7 @@ import type {
SectionUpsellings,
} from '@kbn/security-solution-upselling/service/types';
import type { SecurityProductTypes } from '../../common/config';
import { getProductProductFeatures } from '../../common/pli/pli_features';
import { getEnabledProductFeatures } from '../../common/pli/pli_features';
import type { Services } from '../common/services';
import { withServicesProvider } from '../common/services';
import { upsellingPages, upsellingSections, upsellingMessages } from './upsellings';
@ -30,7 +30,7 @@ const registerSecuritySolutionUpsellings = (
): UpsellingService => {
const upsellingService = services.securitySolution.getUpselling();
const enabledPLIsSet = new Set(getProductProductFeatures(productTypes));
const enabledPLIsSet = new Set(getEnabledProductFeatures(productTypes));
const upsellingPagesToRegister = upsellingPages.reduce<PageUpsellings>(
(pageUpsellings, { pageName, pli, component }) => {

View file

@ -14,7 +14,7 @@ import type {
} from '@kbn/core/server';
import { SECURITY_PROJECT_SETTINGS } from '@kbn/serverless-security-settings';
import { getProductProductFeatures } from '../common/pli/pli_features';
import { getEnabledProductFeatures } from '../common/pli/pli_features';
import type { ServerlessSecurityConfig } from './config';
import { createConfig } from './config';
@ -71,7 +71,7 @@ export class SecuritySolutionServerlessPlugin
this.config = createConfig(this.initializerContext, pluginsSetup.securitySolution);
// Register product features
const enabledProductFeatures = getProductProductFeatures(this.config.productTypes);
const enabledProductFeatures = getEnabledProductFeatures(this.config.productTypes);
registerProductFeatures(pluginsSetup, enabledProductFeatures, this.config);