Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution][PoC] AI 4 SOC navigation #212128

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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 @@ -36,8 +36,8 @@ export const getNotesBaseKibanaFeature = (
all: params.savedObjects,
read: params.savedObjects,
},
ui: ['read', 'crud'],
api: ['notes_read', 'notes_write'],
ui: [],
api: [],
},
read: {
app: [NOTES_FEATURE_ID, 'kibana'],
Expand All @@ -46,8 +46,8 @@ export const getNotesBaseKibanaFeature = (
all: [],
read: params.savedObjects,
},
ui: ['read'],
api: ['notes_read'],
ui: [],
api: [],
},
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
*/

export enum ProductFeatureSecurityKey {
/** Enables Detections workflows, with rules and alerts management */
detections = 'detections',
/** Enables Security dashboards */
dashboards = 'dashboards',
/** Enables Advanced Insights (Entity Risk, GenAI) */
advancedInsights = 'advanced_insights',
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ import type { DefaultSecurityProductFeaturesConfig } from './types';
* - `subFeaturesPrivileges`: the privileges that will be added into the existing Security subFeature with the privilege `id` specified.
*/
export const securityDefaultProductFeaturesConfig: DefaultSecurityProductFeaturesConfig = {
[ProductFeatureSecurityKey.dashboards]: {
privileges: {
all: { ui: ['dashboards'] },
read: { ui: ['dashboards'] },
},
},
[ProductFeatureSecurityKey.detections]: {
privileges: {
all: {
ui: ['rules', 'alerts', 'explore'],
api: [`${APP_ID}-detections`], // TODO: add detections API action `authz`
},
read: {
ui: ['rules', 'alerts', 'explore'],
api: [`${APP_ID}-detections`], // TODO: add detections API action `authz`
},
},
},
[ProductFeatureSecurityKey.advancedInsights]: {
privileges: {
all: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export const getTimelineBaseKibanaFeature = (
all: params.savedObjects,
read: params.savedObjects,
},
ui: ['read', 'crud'],
api: ['timeline_read', 'timeline_write'],
ui: [],
api: [],
},
read: {
app: [TIMELINE_FEATURE_ID, 'kibana'],
Expand All @@ -46,8 +46,8 @@ export const getTimelineBaseKibanaFeature = (
all: [],
read: params.savedObjects,
},
ui: ['read'],
api: ['timeline_read'],
ui: [],
api: [],
},
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
*/

import { ExternalPageName, SecurityPageName } from '@kbn/security-solution-navigation';
import { INVESTIGATIONS_PATH } from '../../../../../common/constants';
import { SECURITY_FEATURE_ID } from '../../../../../common';
import {
INVESTIGATIONS_PATH,
NOTES_FEATURE_ID,
TIMELINE_FEATURE_ID,
} from '../../../../../common/constants';
import type { LinkItem } from '../../../../common/links/types';
import type { SolutionNavLink } from '../../../../common/links';
import { IconOsqueryLazy, IconTimelineLazy } from './lazy_icons';
Expand All @@ -18,7 +21,7 @@ const investigationsAppLink: LinkItem = {
id: SecurityPageName.investigations,
title: i18n.INVESTIGATIONS_TITLE,
path: INVESTIGATIONS_PATH,
capabilities: [`${SECURITY_FEATURE_ID}.show`],
capabilities: [`${TIMELINE_FEATURE_ID}.read`, `${NOTES_FEATURE_ID}.read`],
hideTimeline: true,
skipUrlState: true,
links: [], // timeline and note links are added via the methods below
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const dashboardsLinks: LinkItem = {
title: DASHBOARDS,
path: DASHBOARDS_PATH,
globalNavPosition: 1,
capabilities: [`${SECURITY_FEATURE_ID}.show`],
capabilities: [[`${SECURITY_FEATURE_ID}.show`, `${SECURITY_FEATURE_ID}.dashboards`]],
globalSearchKeywords: [
i18n.translate('xpack.securitySolution.appLinks.dashboards', {
defaultMessage: 'Dashboards',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const links: LinkItem = {
id: SecurityPageName.alerts,
title: ALERTS,
path: ALERTS_PATH,
capabilities: [`${SECURITY_FEATURE_ID}.show`],
capabilities: [[`${SECURITY_FEATURE_ID}.show`, `${SECURITY_FEATURE_ID}.alerts`]],
globalNavPosition: 3,
globalSearchKeywords: [
i18n.translate('xpack.securitySolution.appLinks.alerts', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export const exploreLinks: LinkItem = {
title: EXPLORE,
path: EXPLORE_PATH,
globalNavPosition: 9,
capabilities: [`${SECURITY_FEATURE_ID}.show`],
capabilities: [[`${SECURITY_FEATURE_ID}.show`, `${SECURITY_FEATURE_ID}.explore`]],
globalSearchKeywords: [
i18n.translate('xpack.securitySolution.appLinks.explore', {
defaultMessage: 'Explore',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const links: LinkItem = {
hideTimeline: true,
skipUrlState: true,
globalNavPosition: 2,
capabilities: [`${SECURITY_FEATURE_ID}.show`],
capabilities: [[`${SECURITY_FEATURE_ID}.show`, `${SECURITY_FEATURE_ID}.rules`]],
links: [
{
id: SecurityPageName.rules,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ProductLine, ProductTier } from './product';

export const productLine = schema.oneOf([
schema.literal(ProductLine.security),
schema.literal(ProductLine.ai),
schema.literal(ProductLine.endpoint),
schema.literal(ProductLine.cloud),
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ type PliProductFeatures = Readonly<
export const PLI_PRODUCT_FEATURES: PliProductFeatures = {
security: {
essentials: [
ProductFeatureKey.dashboards,
ProductFeatureKey.detections,
ProductFeatureKey.timeline,
ProductFeatureKey.notes,
ProductFeatureKey.endpointHostManagement,
ProductFeatureKey.endpointPolicyManagement,
],
Expand Down Expand Up @@ -53,4 +57,14 @@ export const PLI_PRODUCT_FEATURES: PliProductFeatures = {
essentials: [ProductFeatureKey.cloudSecurityPosture],
complete: [],
},
ai: {
// Not split into essentials and complete, using essentials for now
essentials: [
// I am guessing here
ProductFeatureKey.attackDiscovery,
ProductFeatureKey.assistant,
ProductFeatureKey.threatIntelligence,
],
complete: [],
},
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

export enum ProductLine {
security = 'security',
ai = 'ai',
endpoint = 'endpoint',
cloud = 'cloud',
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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 type {
AppDeepLinkId,
GroupDefinition,
NavigationTreeDefinition,
NodeDefinition,
} from '@kbn/core-chrome-browser';

import type { WritableDraft } from 'immer/dist/internal';
import { AssistantIcon } from '@kbn/ai-assistant-icon';
import { remove } from 'lodash';
import { SecurityPageName } from '@kbn/deeplinks-security';
import { ProductLine } from '../../common/product';
import type { SecurityProductTypes } from '../../common/config';

export const shouldUseAINavigation = (productTypes: SecurityProductTypes) => {
return productTypes.some((productType) => productType.product_line === ProductLine.ai);
};

// Apply AI for SOC navigation tree changes.
// The navigation tree received by parameter is generated at: x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/navigation_tree.ts
// An example of static navigation tree: x-pack/solutions/observability/plugins/observability/public/navigation_tree.ts
// This is a temporary solution until the "classic" navigation is deprecated and the "generated" navigationTree is replaced by a static navigationTree (probably multiple of them).
export const applyAiSocNavigation = (
draft: WritableDraft<NavigationTreeDefinition<AppDeepLinkId>>
): void => {
const group = draft.body[0] as WritableDraft<GroupDefinition<AppDeepLinkId, string, string>>;
const [attachDiscovery] = group.children.reduce<Array<NodeDefinition<AppDeepLinkId>>>(
(nodes, category) => {
const [attachDiscoveryNode] = remove(category.children ?? [], {
id: SecurityPageName.attackDiscovery,
});
if (attachDiscoveryNode) {
nodes.push(attachDiscoveryNode);
}
return nodes;
},
[]
);

if (attachDiscovery) {
group.appendHorizontalRule = true; // does not seem to work :( talk with sharedUx team

const aiGroup: GroupDefinition<AppDeepLinkId, string, string> = {
type: 'navGroup',
id: 'security_solution_ai_nav',
title: 'AI for SOC',
icon: AssistantIcon,
children: [attachDiscovery],
breadcrumbStatus: 'hidden',
defaultIsCollapsed: false,
isCollapsible: false,
};
draft.body.push(aiGroup);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
*/

import { APP_PATH } from '@kbn/security-solution-plugin/common';
import type { SecurityProductTypes } from '../../common/config';
import type { Services } from '../common/services';
import { subscribeBreadcrumbs } from './breadcrumbs';
import { initSideNavigation } from './side_navigation';
import { enableManagementCardsLanding } from './management_cards';

export const startNavigation = (services: Services) => {
export const startNavigation = (services: Services, productTypes: SecurityProductTypes) => {
services.serverless.setProjectHome(APP_PATH);

initSideNavigation(services);
initSideNavigation(services, productTypes);
enableManagementCardsLanding(services);
subscribeBreadcrumbs(services);
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@ import { i18n } from '@kbn/i18n';
import type { AppDeepLinkId, GroupDefinition, NodeDefinition } from '@kbn/core-chrome-browser';
import produce from 'immer';
import { map } from 'rxjs';
import type { SecurityProductTypes } from '../../common/config';
import { type Services } from '../common/services';
import { applyAiSocNavigation, shouldUseAINavigation } from './ai_soc_navigation';

const PROJECT_SETTINGS_TITLE = i18n.translate(
'xpack.securitySolutionServerless.navLinks.projectSettings.title',
{ defaultMessage: 'Project Settings' }
);

export const initSideNavigation = async (services: Services) => {
export const initSideNavigation = async (
services: Services,
productTypes: SecurityProductTypes
) => {
services.securitySolution.setIsSolutionNavigationEnabled(true);
const showAINavigation = shouldUseAINavigation(productTypes);

const { navigationTree$, panelContentProvider } =
await services.securitySolution.getSolutionNavigation();
Expand All @@ -41,6 +47,10 @@ export const initSideNavigation = async (services: Services) => {
footerGroup.title = PROJECT_SETTINGS_TITLE;
footerGroup.children.push({ cloudLink: 'billingAndSub', openInNewTab: true });
}

if (showAINavigation) {
applyAiSocNavigation(draft);
}
})
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class SecuritySolutionServerlessPlugin
});

setOnboardingSettings(services);
startNavigation(services);
startNavigation(services, productTypes);

return {};
}
Expand Down