diff --git a/x-pack/solutions/security/packages/features/src/product_features_keys.ts b/x-pack/solutions/security/packages/features/src/product_features_keys.ts
index 5876575feaa82..e6b1c1e5733f0 100644
--- a/x-pack/solutions/security/packages/features/src/product_features_keys.ts
+++ b/x-pack/solutions/security/packages/features/src/product_features_keys.ts
@@ -8,11 +8,15 @@
export enum ProductFeatureSecurityKey {
/** Enables Advanced Insights (Entity Risk, GenAI) */
advancedInsights = 'advanced_insights',
- /** Enables Alerts Summary page for AI SOC */
- alertsSummary = 'alerts_summary',
/** Enables Configurations page for AI SOC */
configurations = 'configurations',
+
+ /** Elastic endpoint detections, includes alerts, rules, investigations */
+ detections = 'detections',
+
+ /** Enables external detections for AI SOC, includes alerts_summary, basic_rules*/
+ externalDetections = 'external_detections',
/**
* Enables Investigation guide in Timeline
*/
diff --git a/x-pack/solutions/security/packages/features/src/security/product_feature_config.ts b/x-pack/solutions/security/packages/features/src/security/product_feature_config.ts
index 42151ab427c99..63d010ce7c274 100644
--- a/x-pack/solutions/security/packages/features/src/security/product_feature_config.ts
+++ b/x-pack/solutions/security/packages/features/src/security/product_feature_config.ts
@@ -19,6 +19,7 @@ import type { DefaultSecurityProductFeaturesConfig } from './types';
* - `subFeatureIds`: the ids of the sub-features that will be added into the Security subFeatures entry.
* - `subFeaturesPrivileges`: the privileges that will be added into the existing Security subFeature with the privilege `id` specified.
*/
+
export const securityDefaultProductFeaturesConfig: DefaultSecurityProductFeaturesConfig = {
[ProductFeatureSecurityKey.advancedInsights]: {
privileges: {
@@ -32,25 +33,45 @@ export const securityDefaultProductFeaturesConfig: DefaultSecurityProductFeature
},
},
},
- [ProductFeatureSecurityKey.investigationGuide]: {
+
+ [ProductFeatureSecurityKey.externalDetections]: {
privileges: {
all: {
- ui: ['investigation-guide'],
+ ui: ['external_detections'],
+ api: [],
},
read: {
- ui: ['investigation-guide'],
+ ui: ['external_detections'],
+ api: [],
+ },
+ },
+ },
+ [ProductFeatureSecurityKey.detections]: {
+ privileges: {
+ all: {
+ ui: ['detections'],
+ api: [
+ 'cloud-security-posture-all',
+ 'cloud-security-posture-read',
+ 'cloud-defend-all',
+ 'cloud-defend-read',
+ 'bulkGetUserProfiles',
+ ],
+ },
+ read: {
+ ui: ['detections'],
+ api: ['cloud-security-posture-read', 'cloud-defend-read', 'bulkGetUserProfiles'],
},
},
},
- [ProductFeatureSecurityKey.alertsSummary]: {
+
+ [ProductFeatureSecurityKey.investigationGuide]: {
privileges: {
all: {
- ui: ['alerts_summary'],
- api: [`${APP_ID}-alert-summary`],
+ ui: ['investigation-guide'],
},
read: {
- ui: ['alerts_summary_read'],
- api: [`${APP_ID}-alert-summary`],
+ ui: ['investigation-guide'],
},
},
},
diff --git a/x-pack/solutions/security/packages/features/src/security/v2_features/kibana_features.ts b/x-pack/solutions/security/packages/features/src/security/v2_features/kibana_features.ts
index 7cc4ebae77ddd..0bfc3f7e79920 100644
--- a/x-pack/solutions/security/packages/features/src/security/v2_features/kibana_features.ts
+++ b/x-pack/solutions/security/packages/features/src/security/v2_features/kibana_features.ts
@@ -76,18 +76,7 @@ export const getSecurityV2BaseKibanaFeature = ({
all: {
app: [APP_ID, CLOUD_POSTURE_APP_ID, 'kibana'],
catalogue: [APP_ID],
- api: [
- APP_ID,
- 'lists-all',
- 'lists-read',
- 'lists-summary',
- 'rac',
- 'cloud-security-posture-all',
- 'cloud-security-posture-read',
- 'cloud-defend-all',
- 'cloud-defend-read',
- 'bulkGetUserProfiles',
- ],
+ api: [APP_ID, 'rac', 'lists-all', 'lists-read', 'lists-summary'],
savedObject: {
all: ['alert', ...savedObjects],
read: [],
@@ -104,14 +93,7 @@ export const getSecurityV2BaseKibanaFeature = ({
read: {
app: [APP_ID, CLOUD_POSTURE_APP_ID, 'kibana'],
catalogue: [APP_ID],
- api: [
- APP_ID,
- 'lists-read',
- 'rac',
- 'cloud-security-posture-read',
- 'cloud-defend-read',
- 'bulkGetUserProfiles',
- ],
+ api: [APP_ID, 'rac', 'lists-read'],
savedObject: {
all: [],
read: [...savedObjects],
diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/security_route_page_wrapper/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/security_route_page_wrapper/index.test.tsx
index 8db6d69faf5ad..e33b8860c2f73 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/common/components/security_route_page_wrapper/index.test.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/security_route_page_wrapper/index.test.tsx
@@ -15,9 +15,13 @@ import { generateHistoryMock } from '../../utils/route/mocks';
import type { LinkInfo } from '../../links';
import { useLinkInfo } from '../../links';
import { useUpsellingPage } from '../../hooks/use_upselling';
+import { SpyRoute } from '../../utils/route/spy_routes';
jest.mock('../../links');
jest.mock('../../hooks/use_upselling');
+jest.mock('../../utils/route/spy_routes', () => ({
+ SpyRoute: jest.fn(() => null),
+}));
const defaultLinkInfo: LinkInfo = {
id: SecurityPageName.exploreLanding,
@@ -147,4 +151,18 @@ describe('SecurityRoutePageWrapper', () => {
expect(getByTestId(TEST_COMPONENT_SUBJ)).toBeInTheDocument();
});
+ it('should not render SpyRoute when omitSpyRoute is set to true', () => {
+ (useLinkInfo as jest.Mock).mockReturnValue(defaultLinkInfo);
+ (useUpsellingPage as jest.Mock).mockReturnValue(undefined);
+
+ render(
+
+
+ ,
+ { wrapper: Wrapper }
+ );
+
+ // SpyRoute was mocked, so if omitSpyRoute worked, it should not have been called
+ expect(SpyRoute).not.toHaveBeenCalled();
+ });
});
diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/security_route_page_wrapper/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/security_route_page_wrapper/index.tsx
index 6d5e33494c55a..3f132a192351b 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/common/components/security_route_page_wrapper/index.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/security_route_page_wrapper/index.tsx
@@ -22,6 +22,8 @@ interface SecurityRoutePageWrapperProps {
* Used primarily in the AI for SOC tier, to allow redirecting to the home page instead of showing the NoPrivileges page.
*/
redirectIfUnauthorized?: boolean;
+ // Used to disable the SpyRoute for the page, if e.g. the page's children have their own SpyRoute specified.
+ omitSpyRoute?: boolean;
}
/**
@@ -46,6 +48,7 @@ export const SecurityRoutePageWrapper: FC {
const link = useLinkInfo(pageName);
@@ -91,7 +94,7 @@ export const SecurityRoutePageWrapper: FC
{children}
-
+ {!omitSpyRoute && }
);
};
@@ -105,7 +108,12 @@ export const withSecurityRoutePageWrapper = (
{
redirectOnMissing,
redirectIfUnauthorized,
- }: { redirectOnMissing?: boolean; redirectIfUnauthorized?: boolean } = {}
+ omitSpyRoute,
+ }: {
+ redirectOnMissing?: boolean;
+ redirectIfUnauthorized?: boolean;
+ omitSpyRoute?: boolean;
+ } = {}
) => {
return function WithSecurityRoutePageWrapper(props: T) {
return (
@@ -113,6 +121,7 @@ export const withSecurityRoutePageWrapper = (
pageName={pageName}
redirectOnMissing={redirectOnMissing}
redirectIfUnauthorized={redirectIfUnauthorized}
+ omitSpyRoute={omitSpyRoute}
>
diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/utils/timeline/use_show_timeline.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/utils/timeline/use_show_timeline.test.tsx
index ce3f28c35b63e..a689bc296db5e 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/common/utils/timeline/use_show_timeline.test.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/common/utils/timeline/use_show_timeline.test.tsx
@@ -60,6 +60,7 @@ describe('use show timeline', () => {
siemV2: {
show: true,
crud: true,
+ detections: true,
},
},
upselling: mockUpselling,
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/links.ts b/x-pack/solutions/security/plugins/security_solution/public/detections/links.ts
index 29679805cd12c..1e00e863f3db1 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detections/links.ts
+++ b/x-pack/solutions/security/plugins/security_solution/public/detections/links.ts
@@ -16,7 +16,7 @@ import { ALERT_SUMMARY, ALERTS } from '../app/translations';
import type { LinkItem } from '../common/links/types';
export const alertsLink: LinkItem = {
- capabilities: [`${SECURITY_FEATURE_ID}.show`],
+ capabilities: [[`${SECURITY_FEATURE_ID}.show`, `${SECURITY_FEATURE_ID}.detections`]],
globalNavPosition: 3,
globalSearchKeywords: [
i18n.translate('xpack.securitySolution.appLinks.alerts', {
@@ -29,7 +29,7 @@ export const alertsLink: LinkItem = {
};
export const alertSummaryLink: LinkItem = {
- capabilities: [[`${SECURITY_FEATURE_ID}.show`, `${SECURITY_FEATURE_ID}.alerts_summary`]],
+ capabilities: [[`${SECURITY_FEATURE_ID}.show`, `${SECURITY_FEATURE_ID}.external_detections`]],
globalNavPosition: 3,
globalSearchKeywords: [
i18n.translate('xpack.securitySolution.appLinks.alertSummary', {
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/routes.tsx
index aa5691593fa9a..349f4a8eff0c6 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detections/routes.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detections/routes.tsx
@@ -9,9 +9,15 @@ import React from 'react';
import type { RouteComponentProps, RouteProps } from 'react-router-dom';
import { Redirect } from 'react-router-dom';
import { AlertSummaryContainer } from './pages/alert_summary';
-import { ALERT_SUMMARY_PATH, ALERTS_PATH, DETECTIONS_PATH } from '../../common/constants';
+import {
+ ALERT_SUMMARY_PATH,
+ ALERTS_PATH,
+ DETECTIONS_PATH,
+ SecurityPageName,
+} from '../../common/constants';
import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper';
import { Alerts } from './pages/alerts';
+import { withSecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper';
const AlertsRoutes = () => (
@@ -29,14 +35,20 @@ const DetectionsRedirects = ({ location }: RouteComponentProps) =>
export const routes: RouteProps[] = [
{
path: DETECTIONS_PATH,
- render: DetectionsRedirects,
+ render: withSecurityRoutePageWrapper(DetectionsRedirects, SecurityPageName.detections, {
+ redirectOnMissing: true,
+ }),
},
{
path: ALERTS_PATH,
- component: AlertsRoutes,
+ component: withSecurityRoutePageWrapper(AlertsRoutes, SecurityPageName.alerts, {
+ redirectOnMissing: true,
+ }),
},
{
path: ALERT_SUMMARY_PATH,
- component: AlertSummaryContainer,
+ component: withSecurityRoutePageWrapper(AlertSummaryContainer, SecurityPageName.alertSummary, {
+ redirectOnMissing: true,
+ }),
},
];
diff --git a/x-pack/solutions/security/plugins/security_solution/public/rules/links.ts b/x-pack/solutions/security/plugins/security_solution/public/rules/links.ts
index 28f44585d3037..2b113abc85212 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/rules/links.ts
+++ b/x-pack/solutions/security/plugins/security_solution/public/rules/links.ts
@@ -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}.detections`]],
links: [
{
id: SecurityPageName.rules,
diff --git a/x-pack/solutions/security/plugins/security_solution/public/rules/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/rules/routes.tsx
index add8a5911df21..a08be19ac327e 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/rules/routes.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/rules/routes.tsx
@@ -30,6 +30,10 @@ import type { SecuritySubPluginRoutes } from '../app/types';
import { RulesLandingPage } from './landing';
import { CoverageOverviewPage } from '../detection_engine/rule_management_ui/pages/coverage_overview';
import { RuleDetailTabs } from '../detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs';
+import {
+ SecurityRoutePageWrapper,
+ withSecurityRoutePageWrapper,
+} from '../common/components/security_route_page_wrapper';
const RulesSubRoutes = [
{
@@ -64,7 +68,7 @@ const RulesContainerComponent: React.FC = () => {
return (
-
+
{
-
+
);
};
@@ -117,7 +121,9 @@ const CoverageOverviewRoutes = () => (
export const routes: SecuritySubPluginRoutes = [
{
path: RULES_LANDING_PATH,
- component: RulesLandingPage,
+ component: withSecurityRoutePageWrapper(RulesLandingPage, SecurityPageName.rulesLanding, {
+ redirectOnMissing: true,
+ }),
},
{
path: RULES_PATH,
@@ -125,6 +131,12 @@ export const routes: SecuritySubPluginRoutes = [
},
{
path: COVERAGE_OVERVIEW_PATH,
- component: CoverageOverviewRoutes,
+ component: withSecurityRoutePageWrapper(
+ CoverageOverviewRoutes,
+ SecurityPageName.coverageOverview,
+ {
+ redirectOnMissing: true,
+ }
+ ),
},
];
diff --git a/x-pack/solutions/security/plugins/security_solution_ess/common/constants.ts b/x-pack/solutions/security/plugins/security_solution_ess/common/constants.ts
index ea539eae7a9d4..0d0bfcd80d70d 100644
--- a/x-pack/solutions/security/plugins/security_solution_ess/common/constants.ts
+++ b/x-pack/solutions/security/plugins/security_solution_ess/common/constants.ts
@@ -13,7 +13,7 @@ import {
// List of product features that are disabled in different offering (eg. Serverless).
const DISABLED_PRODUCT_FEATURES: ProductFeatureKeyType[] = [
- ProductFeatureSecurityKey.alertsSummary,
+ ProductFeatureSecurityKey.externalDetections,
ProductFeatureSecurityKey.configurations,
];
diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/common/pli/pli_config.ts b/x-pack/solutions/security/plugins/security_solution_serverless/common/pli/pli_config.ts
index c822a57cac943..6f774f6b5da31 100644
--- a/x-pack/solutions/security/plugins/security_solution_serverless/common/pli/pli_config.ts
+++ b/x-pack/solutions/security/plugins/security_solution_serverless/common/pli/pli_config.ts
@@ -19,8 +19,8 @@ export const PLI_PRODUCT_FEATURES: PliProductFeatures = {
search_ai_lake: [
ProductFeatureKey.attackDiscovery,
ProductFeatureKey.assistant,
- ProductFeatureKey.alertsSummary,
ProductFeatureKey.configurations,
+ ProductFeatureKey.externalDetections,
],
essentials: [ProductFeatureKey.attackDiscovery, ProductFeatureKey.assistant],
complete: [ProductFeatureKey.attackDiscovery, ProductFeatureKey.assistant],
@@ -28,12 +28,14 @@ export const PLI_PRODUCT_FEATURES: PliProductFeatures = {
[ProductLine.security]: {
search_ai_lake: [],
essentials: [
+ ProductFeatureKey.detections,
ProductFeatureKey.timeline,
ProductFeatureKey.notes,
ProductFeatureKey.endpointHostManagement,
ProductFeatureKey.endpointPolicyManagement,
],
complete: [
+ ProductFeatureKey.detections,
ProductFeatureKey.timeline,
ProductFeatureKey.notes,
ProductFeatureKey.endpointHostManagement,
diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/__snapshots__/side_navigation.test.tsx.snap b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/__snapshots__/side_navigation.test.tsx.snap
index 49707cd579fe6..4cb59b8e617bc 100644
--- a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/__snapshots__/side_navigation.test.tsx.snap
+++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/__snapshots__/side_navigation.test.tsx.snap
@@ -655,8 +655,9 @@ Object {
"breadcrumbStatus": "hidden",
"children": Array [
Object {
- "id": "discover:",
- "link": "discover",
+ "id": "alert_summary",
+ "link": "securitySolutionUI:alert_summary",
+ "spaceBefore": "s",
},
Object {
"id": "attack_discovery",
@@ -678,90 +679,7 @@ Object {
"id": "cases",
"link": "securitySolutionUI:cases",
"renderAs": "panelOpener",
- },
- Object {
- "children": Array [
- Object {
- "breadcrumbStatus": "hidden",
- "children": Array [
- Object {
- "id": "ml:overview",
- "link": "ml:overview",
- "title": "Overview",
- },
- Object {
- "id": "ml:data_visualizer",
- "link": "ml:dataVisualizer",
- "title": "Data visualizer",
- },
- ],
- },
- Object {
- "breadcrumbStatus": "hidden",
- "children": Array [
- Object {
- "id": "ml:anomalyExplorer",
- "link": "ml:anomalyExplorer",
- "title": "Anomaly explorer",
- },
- Object {
- "id": "ml:singleMetricViewer",
- "link": "ml:singleMetricViewer",
- "title": "Single metric viewer",
- },
- ],
- "id": "category-anomaly_detection",
- "title": "Anomaly detection",
- },
- Object {
- "breadcrumbStatus": "hidden",
- "children": Array [
- Object {
- "id": "ml:resultExplorer",
- "link": "ml:resultExplorer",
- "title": "Result explorer",
- },
- Object {
- "id": "ml:analyticsMap",
- "link": "ml:analyticsMap",
- "title": "Analytics map",
- },
- ],
- "id": "category-data_frame analytics",
- "title": "Data frame analytics",
- },
- Object {
- "breadcrumbStatus": "hidden",
- "children": Array [
- Object {
- "id": "ml:logRateAnalysis",
- "link": "ml:logRateAnalysis",
- "title": "Log rate analysis",
- },
- Object {
- "id": "ml:logPatternAnalysis",
- "link": "ml:logPatternAnalysis",
- "title": "Log pattern analysis",
- },
- Object {
- "id": "ml:changePointDetections",
- "link": "ml:changePointDetections",
- "title": "Change point detection",
- },
- ],
- "id": "category-aiops_labs",
- "title": "Aiops labs",
- },
- ],
- "id": "machine_learning-landing",
- "link": "securitySolutionUI:machine_learning-landing",
- "renderAs": "panelOpener",
- "title": "Machine learning",
- "type": "navGroup",
- },
- Object {
- "id": "alert_summary",
- "link": "securitySolutionUI:alert_summary",
+ "spaceBefore": "m",
},
Object {
"children": Array [
@@ -778,6 +696,12 @@ Object {
"id": "configurations",
"link": "securitySolutionUI:configurations",
"renderAs": "panelOpener",
+ "spaceBefore": null,
+ },
+ Object {
+ "id": "discover:",
+ "link": "discover",
+ "spaceBefore": "m",
},
],
"defaultIsCollapsed": false,
diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.ts
index c7a8fe6d39323..abc10708c0a5d 100644
--- a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.ts
+++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.ts
@@ -15,7 +15,6 @@ import { i18nStrings, securityLink } from '@kbn/security-solution-navigation/lin
import { type SecurityProductTypes } from '../../../common/config';
import { ProductLine } from '../../../common/product';
-import { createMachineLearningNavigationTree } from '../ml_navigation';
import { createStackManagementNavigationTree } from '../stack_management_navigation';
import { AiForTheSocIcon } from './icons';
@@ -40,15 +39,18 @@ export const createAiSocNavigationTree$ = (): Rx.Observable {
+ it('should show page or redirect depending on capabilities', () => {
+ visit(ALERT_SUMMARY_URL);
+ cy.get(ALERTS_SUMMARY_PROMPT).should('exist');
+
+ // should redirect out from alerts to get started page
+ visit(ALERTS_URL);
+ cy.get(GET_STARTED_PAGE).should('exist');
+
+ // should redirect out from rules to get started page
+ visit(RULES_LANDING_URL);
+ cy.get(GET_STARTED_PAGE).should('exist');
+ });
+};
+
+describe('Capabilities', { tags: '@serverless' }, () => {
+ describe('Admin user capabilities', () => {
+ beforeEach(() => {
+ login('admin');
+ });
+
+ testPageAccess();
+ });
+
+ describe('User with siem v1 role', () => {
+ const roleDescriptor = {
+ elasticsearch: {
+ indices: [
+ {
+ names: ['*'],
+ privileges: ['all'],
+ },
+ ],
+ },
+ kibana: [
+ {
+ feature: {
+ siem: ['all'],
+ fleet: ['all'],
+ },
+ spaces: ['*'],
+ },
+ ],
+ };
+
+ before(() => {
+ cy.task('createServerlessCustomRole', {
+ roleDescriptor,
+ roleName: 'siemv1',
+ });
+ });
+
+ beforeEach(() => {
+ login('siemv1');
+ });
+
+ after(() => {
+ cy.task('deleteServerlessCustomRole', 'siemv1');
+ });
+
+ testPageAccess();
+ });
+
+ describe('User with siem v2 role', () => {
+ const roleDescriptor = {
+ elasticsearch: {
+ indices: [
+ {
+ names: ['*'],
+ privileges: ['all'],
+ },
+ ],
+ },
+ kibana: [
+ {
+ feature: {
+ siemV2: ['all'],
+ fleet: ['all'],
+ },
+ spaces: ['*'],
+ },
+ ],
+ };
+
+ before(() => {
+ cy.task('createServerlessCustomRole', {
+ roleDescriptor,
+ roleName: 'siemV2',
+ });
+ });
+
+ beforeEach(() => {
+ login('siemV2');
+ });
+
+ after(() => {
+ cy.task('deleteServerlessCustomRole', 'siemV2');
+ });
+
+ testPageAccess();
+ });
+});
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/ai4dsoc/constants.ts b/x-pack/test/security_solution_cypress/cypress/e2e/ai4dsoc/constants.ts
new file mode 100644
index 0000000000000..1a270e381dbee
--- /dev/null
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/ai4dsoc/constants.ts
@@ -0,0 +1,11 @@
+/*
+ * 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.
+ */
+
+export const ALERTS_SUMMARY_PROMPT = '[data-test-subj="alert-summary-landing-page-prompt"]';
+export const GET_STARTED_PAGE = '[data-test-subj="onboarding-hub-page"]';
+export const AI_SOC_NAVIGATION =
+ '[data-test-subj="nav-item nav-item-security_solution_ai_nav nav-item-id-security_solution_ai_nav"]';
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/ai4dsoc/navigation/dummy_test.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/ai4dsoc/navigation/dummy_test.cy.ts
deleted file mode 100644
index 82a9f63026b57..0000000000000
--- a/x-pack/test/security_solution_cypress/cypress/e2e/ai4dsoc/navigation/dummy_test.cy.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * 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 { login } from '../../../tasks/login';
-import { visit } from '../../../tasks/navigation';
-import { GET_STARTED_URL } from '../../../urls/navigation';
-
-describe('Dummy Test ', { tags: '@serverless' }, () => {
- beforeEach(() => {
- login();
- visit(GET_STARTED_URL);
- });
-});
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/ai4dsoc/navigation/navigation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/ai4dsoc/navigation/navigation.cy.ts
new file mode 100644
index 0000000000000..ee21c38ba03ff
--- /dev/null
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/ai4dsoc/navigation/navigation.cy.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 { login } from '../../../tasks/login';
+import { visit } from '../../../tasks/navigation';
+import { GET_STARTED_URL } from '../../../urls/navigation';
+import { AI_SOC_NAVIGATION } from '../constants';
+
+const visibleLinks = ['discover', 'attack_discovery', 'case', 'alert_summary', 'configurations'];
+
+const notVisibleLinks = [
+ // 'machine_learning-landing', -- TODO comment out when ML is turned off
+ 'alerts',
+ 'rules',
+];
+
+describe('AI$DSOC Navigation', { tags: '@serverless' }, () => {
+ beforeEach(() => {
+ login('admin');
+ visit(GET_STARTED_URL);
+ });
+ describe('renders links correctly', () => {
+ it('should contain the specified links', () => {
+ cy.get(AI_SOC_NAVIGATION)
+ .should('exist')
+ .within(() => {
+ visibleLinks.map((link) => {
+ cy.getByTestSubjContains(`nav-item-id-${link}`).should('exist');
+ });
+
+ notVisibleLinks.map((link) => {
+ cy.getByTestSubjContains(`nav-item-id-${link}`).should('not.exist');
+ });
+ });
+ });
+ });
+});
diff --git a/x-pack/test/security_solution_cypress/cypress/support/commands.js b/x-pack/test/security_solution_cypress/cypress/support/commands.js
index 413473f29e6d6..002f05b5b3dfa 100644
--- a/x-pack/test/security_solution_cypress/cypress/support/commands.js
+++ b/x-pack/test/security_solution_cypress/cypress/support/commands.js
@@ -89,3 +89,8 @@ Cypress.Commands.add('waitUntil', { prevSubject: 'optional' }, waitUntil);
Cypress.Commands.add('setCurrentSpace', (spaceId) => cy.state('currentSpaceId', spaceId));
// Reads non-default space id
Cypress.Commands.add('currentSpace', () => cy.state('currentSpaceId'));
+
+// finds elements that contain the given selector
+Cypress.Commands.add('getByTestSubjContains', (selector, ...args) =>
+ cy.get(`[data-test-subj*="${selector}"]`, ...args)
+);
diff --git a/x-pack/test/security_solution_cypress/cypress/support/index.d.ts b/x-pack/test/security_solution_cypress/cypress/support/index.d.ts
index 5473e3ac7132d..d57f040fcc4f1 100644
--- a/x-pack/test/security_solution_cypress/cypress/support/index.d.ts
+++ b/x-pack/test/security_solution_cypress/cypress/support/index.d.ts
@@ -24,6 +24,10 @@ declare namespace Cypress {
* Reads current space id value. `undefined` is returned for default space.
*/
currentSpace(): Chainable;
+
+ getByTestSubjContains(
+ ...args: Parameters
+ ): Chainable>;
}
}
diff --git a/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts b/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts
index a6b1900f94070..79cb498eb1374 100644
--- a/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts
+++ b/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts
@@ -65,6 +65,7 @@ export const MACHINE_LEARNING_LANDING_URL = '/app/security/ml';
// Detection and Response
export const DETECTION_AND_RESPONSE_URL = '/app/security/detection_response';
export const ALERTS_URL = '/app/security/alerts';
+export const ALERT_SUMMARY_URL = '/app/security/alert_summary';
export const EXCEPTIONS_URL = '/app/security/exceptions';
export const CREATE_RULE_URL = '/app/security/rules/create';
export const ENTITY_ANALYTICS_MANAGEMENT_URL = '/app/security/entity_analytics_management';
diff --git a/x-pack/test_serverless/api_integration/test_suites/security/platform_security/authorization.ts b/x-pack/test_serverless/api_integration/test_suites/security/platform_security/authorization.ts
index bbbb22a4e51ed..182871e2e9163 100644
--- a/x-pack/test_serverless/api_integration/test_suites/security/platform_security/authorization.ts
+++ b/x-pack/test_serverless/api_integration/test_suites/security/platform_security/authorization.ts
@@ -221,16 +221,16 @@ export default function ({ getService }: FtrProviderContext) {
"all": Array [
"login:",
"api:securitySolution",
+ "api:rac",
"api:lists-all",
"api:lists-read",
"api:lists-summary",
- "api:rac",
+ "api:securitySolution-entity-analytics",
"api:cloud-security-posture-all",
"api:cloud-security-posture-read",
"api:cloud-defend-all",
"api:cloud-defend-read",
"api:bulkGetUserProfiles",
- "api:securitySolution-entity-analytics",
"api:securitySolution-threat-intelligence",
"api:securitySolution-showEndpointExceptions",
"api:securitySolution-crudEndpointExceptions",
@@ -474,6 +474,7 @@ export default function ({ getService }: FtrProviderContext) {
"ui:siemV2/show",
"ui:siemV2/crud",
"ui:siemV2/entity-analytics",
+ "ui:siemV2/detections",
"ui:siemV2/investigation-guide",
"ui:siemV2/investigation-guide-interactions",
"ui:siemV2/threat-intelligence",
@@ -1066,16 +1067,16 @@ export default function ({ getService }: FtrProviderContext) {
"minimal_all": Array [
"login:",
"api:securitySolution",
+ "api:rac",
"api:lists-all",
"api:lists-read",
"api:lists-summary",
- "api:rac",
+ "api:securitySolution-entity-analytics",
"api:cloud-security-posture-all",
"api:cloud-security-posture-read",
"api:cloud-defend-all",
"api:cloud-defend-read",
"api:bulkGetUserProfiles",
- "api:securitySolution-entity-analytics",
"api:securitySolution-threat-intelligence",
"app:securitySolution",
"app:csp",
@@ -1317,6 +1318,7 @@ export default function ({ getService }: FtrProviderContext) {
"ui:siemV2/show",
"ui:siemV2/crud",
"ui:siemV2/entity-analytics",
+ "ui:siemV2/detections",
"ui:siemV2/investigation-guide",
"ui:siemV2/investigation-guide-interactions",
"ui:siemV2/threat-intelligence",
@@ -1773,12 +1775,12 @@ export default function ({ getService }: FtrProviderContext) {
"minimal_read": Array [
"login:",
"api:securitySolution",
- "api:lists-read",
"api:rac",
+ "api:lists-read",
+ "api:securitySolution-entity-analytics",
"api:cloud-security-posture-read",
"api:cloud-defend-read",
"api:bulkGetUserProfiles",
- "api:securitySolution-entity-analytics",
"api:securitySolution-threat-intelligence",
"app:securitySolution",
"app:csp",
@@ -1895,6 +1897,7 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:cloud/close_point_in_time",
"ui:siemV2/show",
"ui:siemV2/entity-analytics",
+ "ui:siemV2/detections",
"ui:siemV2/investigation-guide",
"ui:siemV2/investigation-guide-interactions",
"ui:siemV2/threat-intelligence",
@@ -2140,12 +2143,12 @@ export default function ({ getService }: FtrProviderContext) {
"read": Array [
"login:",
"api:securitySolution",
- "api:lists-read",
"api:rac",
+ "api:lists-read",
+ "api:securitySolution-entity-analytics",
"api:cloud-security-posture-read",
"api:cloud-defend-read",
"api:bulkGetUserProfiles",
- "api:securitySolution-entity-analytics",
"api:securitySolution-threat-intelligence",
"api:securitySolution-showEndpointExceptions",
"app:securitySolution",
@@ -2263,6 +2266,7 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:cloud/close_point_in_time",
"ui:siemV2/show",
"ui:siemV2/entity-analytics",
+ "ui:siemV2/detections",
"ui:siemV2/investigation-guide",
"ui:siemV2/investigation-guide-interactions",
"ui:siemV2/threat-intelligence",
diff --git a/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.basic.ts b/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.basic.ts
index ee788c7117f6f..3f6cc68e164b1 100644
--- a/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.basic.ts
+++ b/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.basic.ts
@@ -18,7 +18,9 @@ export default createTestConfig({
`--xpack.fleet.packages.0.name=cloud_security_posture`,
`--xpack.fleet.packages.0.version=${CLOUD_SECURITY_PLUGIN_VERSION}`,
// configs the environment to run on the basic product tier, which may include PLI block components or messages
- `--xpack.securitySolutionServerless.productTypes=${JSON.stringify([])}`,
+ `--xpack.securitySolutionServerless.productTypes=${JSON.stringify([
+ { product_line: 'security', product_tier: 'essentials' },
+ ])}`,
],
// load tests in the index file
testFiles: [require.resolve('./ftr/cloud_security_posture')],