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')],