diff --git a/x-pack/solutions/security/plugins/security_solution/common/constants.ts b/x-pack/solutions/security/plugins/security_solution/common/constants.ts index eda49eae164d0..c4bb9290ddb64 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/constants.ts @@ -101,7 +101,6 @@ export const RULES_LANDING_PATH = `${RULES_PATH}/landing` as const; export const RULES_ADD_PATH = `${RULES_PATH}/add_rules` as const; export const RULES_UPDATES = `${RULES_PATH}/updates` as const; export const RULES_CREATE_PATH = `${RULES_PATH}/create` as const; -export const RULES_MANAGEMENT_PATH = `${RULES_PATH}/management` as const; export const EXCEPTIONS_PATH = '/exceptions' as const; export const EXCEPTION_LIST_DETAIL_PATH = `${EXCEPTIONS_PATH}/details/:detailName` as const; export const HOSTS_PATH = '/hosts' as const; diff --git a/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/links.ts b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/links.ts index 27970e81abe64..5b9c3afed1124 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/links.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/links.ts @@ -17,7 +17,7 @@ import { import type { LinkItem } from '../common/links/types'; export const links: LinkItem = { - capabilities: [`${SECURITY_FEATURE_ID}.show`], + capabilities: [[`${SECURITY_FEATURE_ID}.show`, `${SECURITY_FEATURE_ID}.detections`]], globalNavPosition: 11, globalSearchKeywords: [ i18n.translate('xpack.securitySolution.appLinks.inventory', { diff --git a/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/routes.tsx index a3775a516ab81..02ed4e6631da8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/routes.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/routes.tsx @@ -12,7 +12,7 @@ import { SecurityPageName } from '../app/types'; import { ASSET_INVENTORY_PATH } from '../../common/constants'; import { SecuritySolutionPageWrapper } from '../common/components/page_wrapper'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; -import { SecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; +import { withSecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; import { AssetInventoryLoading } from './components/asset_inventory_loading'; const AssetsPageLazy = lazy(() => import('./pages')); @@ -32,13 +32,11 @@ export const AssetInventoryRoutes = () => { return ( - - - }> - - - - + + }> + + + ); @@ -47,6 +45,8 @@ export const AssetInventoryRoutes = () => { export const routes: SecuritySubPluginRoutes = [ { path: ASSET_INVENTORY_PATH, - component: AssetInventoryRoutes, + component: withSecurityRoutePageWrapper(AssetInventoryRoutes, SecurityPageName.assetInventory, { + redirectOnMissing: true, + }), }, ]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/cloud_security_posture/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/cloud_security_posture/routes.tsx index ffa266d938087..ed4c712e18801 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/cloud_security_posture/routes.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/cloud_security_posture/routes.tsx @@ -9,15 +9,15 @@ import React from 'react'; import { CLOUD_SECURITY_POSTURE_BASE_PATH } from '@kbn/cloud-security-posture-common'; import type { CloudSecurityPosturePageId } from '@kbn/cloud-security-posture-plugin/public'; import { type CspSecuritySolutionContext } from '@kbn/cloud-security-posture-plugin/public'; -import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import type { SecurityPageName, SecuritySubPluginRoutes } from '../app/types'; +import { SecurityPageName } from '../app/types'; +import type { SecuritySubPluginRoutes } from '../app/types'; import { useKibana } from '../common/lib/kibana'; -import { SecuritySolutionPageWrapper } from '../common/components/page_wrapper'; import { SpyRoute } from '../common/utils/route/spy_routes'; import { FiltersGlobal } from '../common/components/filters_global'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; import { useOnExpandableFlyoutClose } from '../flyout/shared/hooks/use_on_expandable_flyout_close'; +import { withSecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; // This exists only for the type signature cast const CloudPostureSpyRoute = ({ pageName, ...rest }: { pageName?: CloudSecurityPosturePageId }) => ( @@ -37,11 +37,7 @@ const CloudSecurityPosture = () => { return ( - - - - - + ); }; @@ -51,6 +47,13 @@ CloudSecurityPosture.displayName = 'CloudSecurityPosture'; export const routes: SecuritySubPluginRoutes = [ { path: CLOUD_SECURITY_POSTURE_BASE_PATH, - component: CloudSecurityPosture, + component: withSecurityRoutePageWrapper( + CloudSecurityPosture, + SecurityPageName.cloudSecurityPostureDashboard, + { + redirectOnMissing: true, + omitSpyRoute: true, + } + ), }, ]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/dashboards/links.ts b/x-pack/solutions/security/plugins/security_solution/public/dashboards/links.ts index 7feecbd1742c9..7ffb6463f42e5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/dashboards/links.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/dashboards/links.ts @@ -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}.detections`]], globalSearchKeywords: [ i18n.translate('xpack.securitySolution.appLinks.dashboards', { defaultMessage: 'Dashboards', diff --git a/x-pack/solutions/security/plugins/security_solution/public/dashboards/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/dashboards/routes.tsx index b9e854dfdbbdf..96de49d4a693b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/dashboards/routes.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/dashboards/routes.tsx @@ -5,24 +5,24 @@ * 2.0. */ import React from 'react'; -import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; import { DASHBOARDS_PATH, SecurityPageName } from '../../common/constants'; import type { SecuritySubPluginRoutes } from '../app/types'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; import { DashboardsContainer } from './pages'; +import { withSecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; export const DashboardRoutes = () => ( - - - + ); export const routes: SecuritySubPluginRoutes = [ { path: DASHBOARDS_PATH, - component: DashboardRoutes, + component: withSecurityRoutePageWrapper(DashboardRoutes, SecurityPageName.dashboards, { + redirectOnMissing: true, + }), }, ]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/exceptions/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/exceptions/routes.tsx index e6faf794dcdbf..2fdcfb578821b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/exceptions/routes.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/exceptions/routes.tsx @@ -20,7 +20,10 @@ import { SpyRoute } from '../common/utils/route/spy_routes'; import { NotFoundPage } from '../app/404'; import { useReadonlyHeader } from '../use_readonly_header'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; -import { SecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; +import { + SecurityRoutePageWrapper, + withSecurityRoutePageWrapper, +} from '../common/components/security_route_page_wrapper'; const ExceptionsRoutes = () => ( @@ -53,11 +56,11 @@ const ExceptionsContainerComponent: React.FC = () => { const Exceptions = React.memo(ExceptionsContainerComponent); -const renderExceptionsRoutes = () => ; - export const routes = [ { path: EXCEPTIONS_PATH, - render: renderExceptionsRoutes, + component: withSecurityRoutePageWrapper(Exceptions, SecurityPageName.exceptions, { + redirectOnMissing: true, + }), }, ]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/links.ts b/x-pack/solutions/security/plugins/security_solution/public/explore/links.ts index 18f176494fffe..920b9a4ba2614 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/links.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/links.ts @@ -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}.detections`]], globalSearchKeywords: [ i18n.translate('xpack.securitySolution.appLinks.explore', { defaultMessage: 'Explore', diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/routes.tsx index 3da94b7dc82f9..fedb7b91c83e6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/routes.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/routes.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; import { UsersContainer } from './users/pages'; import { HostsContainer } from './hosts/pages'; import { NetworkContainer } from './network/pages'; @@ -16,37 +15,29 @@ import { SecurityPageName } from '../app/types'; import { EXPLORE_PATH, HOSTS_PATH, NETWORK_PATH, USERS_PATH } from '../../common/constants'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; import { ExploreLandingPage } from './landing'; -import { SecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; +import { withSecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; const ExploreLanding = () => ( - - - + ); const NetworkRoutes = () => ( - - - + ); const UsersRoutes = () => ( - - - + ); const HostsRoutes = () => ( - - - + ); @@ -54,18 +45,30 @@ export const routes: SecuritySubPluginRoutes = [ { path: EXPLORE_PATH, exact: true, - component: ExploreLanding, + component: withSecurityRoutePageWrapper(ExploreLanding, SecurityPageName.exploreLanding, { + redirectOnMissing: true, + omitSpyRoute: true, + }), }, { path: NETWORK_PATH, - component: NetworkRoutes, + component: withSecurityRoutePageWrapper(NetworkRoutes, SecurityPageName.network, { + redirectOnMissing: true, + omitSpyRoute: true, + }), }, { path: USERS_PATH, - component: UsersRoutes, + component: withSecurityRoutePageWrapper(UsersRoutes, SecurityPageName.users, { + redirectOnMissing: true, + omitSpyRoute: true, + }), }, { path: HOSTS_PATH, - component: HostsRoutes, + component: withSecurityRoutePageWrapper(HostsRoutes, SecurityPageName.hosts, { + redirectOnMissing: true, + omitSpyRoute: true, + }), }, ]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/pages/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/management/pages/index.tsx index d558b1271dc6b..613447bd44431 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/pages/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/management/pages/index.tsx @@ -37,6 +37,7 @@ import { HostIsolationExceptionsContainer } from './host_isolation_exceptions'; import { BlocklistContainer } from './blocklist'; import { ResponseActionsContainer } from './response_actions'; import { PrivilegedRoute } from '../components/privileged_route'; +import { SecurityRoutePageWrapper } from '../../common/components/security_route_page_wrapper'; const EndpointTelemetry = () => ( @@ -80,11 +81,10 @@ const ResponseActionsTelemetry = () => ( ); -const NotesTelemetry = () => ( - +const Notes = () => ( + - - + ); export const ManagementContainer = memo(() => { @@ -163,7 +163,7 @@ export const ManagementContainer = memo(() => { /> {!securitySolutionNotesDisabled && ( - + )} {canReadEndpointList && ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/notes/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/notes/routes.tsx index c49f54f9c9a93..43c6be374c94e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/notes/routes.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/notes/routes.tsx @@ -7,26 +7,22 @@ import React from 'react'; import { Route, Routes } from '@kbn/shared-ux-router'; -import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; import { NoteManagementPage } from './pages/note_management_page'; -import { SpyRoute } from '../common/utils/route/spy_routes'; import { NotFoundPage } from '../app/404'; import { NOTES_PATH, SecurityPageName } from '../../common/constants'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; +import { withSecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; -const NotesManagementTelemetry = () => ( +const NotesManagementWrapper = () => ( - - - - + ); const NotesManagementContainer: React.FC = React.memo(() => { return ( - + ); @@ -36,6 +32,8 @@ NotesManagementContainer.displayName = 'NotesManagementContainer'; export const routes = [ { path: NOTES_PATH, - component: NotesManagementContainer, + component: withSecurityRoutePageWrapper(NotesManagementContainer, SecurityPageName.notes, { + redirectOnMissing: true, + }), }, ]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/overview/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/overview/routes.tsx index 3b1e9ca0e8046..5964adca240e6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/overview/routes.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/overview/routes.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; import { OVERVIEW_PATH, DATA_QUALITY_PATH, @@ -21,55 +20,63 @@ import { DataQuality } from './pages/data_quality'; import { DetectionResponse } from './pages/detection_response'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; import { EntityAnalyticsPage } from '../entity_analytics/pages/entity_analytics_dashboard'; -import { SecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; +import { withSecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; const OverviewRoutes = () => ( - - - + ); const DetectionResponseRoutes = () => ( - - - + ); const EntityAnalyticsRoutes = () => ( - - - + ); const DataQualityRoutes = () => ( - - - + ); export const routes: SecuritySubPluginRoutes = [ { path: OVERVIEW_PATH, - component: OverviewRoutes, + component: withSecurityRoutePageWrapper(OverviewRoutes, SecurityPageName.overview, { + redirectOnMissing: true, + }), }, { path: DETECTION_RESPONSE_PATH, - component: DetectionResponseRoutes, + component: withSecurityRoutePageWrapper( + DetectionResponseRoutes, + SecurityPageName.detectionAndResponse, + { + redirectOnMissing: true, + } + ), }, { path: ENTITY_ANALYTICS_PATH, - render: EntityAnalyticsRoutes, + component: withSecurityRoutePageWrapper( + EntityAnalyticsRoutes, + SecurityPageName.entityAnalytics, + { + redirectOnMissing: true, + } + ), }, { path: DATA_QUALITY_PATH, - component: DataQualityRoutes, + component: withSecurityRoutePageWrapper(DataQualityRoutes, SecurityPageName.dataQuality, { + 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 43b9842aca6cb..9b687e89da655 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 @@ -12,7 +12,6 @@ import { RULES_ADD_PATH, RULES_CREATE_PATH, RULES_LANDING_PATH, - RULES_MANAGEMENT_PATH, RULES_PATH, SECURITY_FEATURE_ID, } from '../../common/constants'; @@ -56,15 +55,6 @@ export const links: LinkItem = { ], capabilities: `${SECURITY_FEATURE_ID}.show`, links: [ - { - id: SecurityPageName.rulesManagement, - title: SIEM_RULES, - path: RULES_MANAGEMENT_PATH, - globalSearchDisabled: true, - skipUrlState: true, - hideTimeline: true, - capabilities: `${SECURITY_FEATURE_ID}.detections`, - }, { id: SecurityPageName.rulesAdd, title: ADD_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 557d4d58e31ed..6aa039b2a16a4 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 @@ -43,6 +43,11 @@ const getRulesSubRoutes = (capabilities: Capabilities) => [ main: EditRulePage, exact: true, }, + { + path: `/rules/:tabName(${AllRulesTabs.management}|${AllRulesTabs.monitoring}|${AllRulesTabs.updates})`, + main: RulesPage, + exact: true, + }, ] : []), ...(hasCapabilities(capabilities, [ @@ -65,14 +70,6 @@ const getRulesSubRoutes = (capabilities: Capabilities) => [ }), exact: true, }, - { - path: `/rules/:tabName(${AllRulesTabs.management}|${AllRulesTabs.monitoring}|${AllRulesTabs.updates})`, - main: withSecurityRoutePageWrapper(RulesPage, SecurityPageName.rulesManagement, { - redirectOnMissing: true, - omitSpyRoute: true, - }), - exact: true, - }, { path: '/rules/add_rules', main: withSecurityRoutePageWrapper(AddRulesPage, SecurityPageName.rulesAdd, { diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/routes.tsx index e7f28eb9d71e3..e321507799df1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/routes.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/routes.tsx @@ -6,8 +6,8 @@ */ import React from 'react'; -import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; +import { withSecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; import { SecurityPageName } from '../app/types'; import type { SecuritySubPluginRoutes } from '../app/types'; @@ -16,15 +16,15 @@ import { Timelines } from './pages'; const TimelinesRoutes = () => ( - - - + ); export const routes: SecuritySubPluginRoutes = [ { path: TIMELINES_PATH, - component: TimelinesRoutes, + component: withSecurityRoutePageWrapper(TimelinesRoutes, SecurityPageName.timelines, { + redirectOnMissing: true, + }), }, ]; 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 index ee0795aa2a003..c86b0da2fc061 100644 --- 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 @@ -7,18 +7,125 @@ import { login } from '../../../tasks/login'; import { visit } from '../../../tasks/navigation'; -import { GET_STARTED_URL } from '../../../urls/navigation'; +import { + ASSETS_URL, + ALERTS_URL, + ASSET_INVENTORY_URL, + BLOCKLIST_URL, + CREATE_RULE_URL, + CSP_DASHBOARD_URL, + CSP_BENCHMARKS_URL, + CSP_FINDINGS_URL, + CSP_VULNERABILITIES_URL, + DASHBOARDS_URL, + ENDPOINTS_URL, + ENTITY_ANALYTICS_MANAGEMENT_URL, + ENTITY_ANALYTICS_ENTITY_STORE_URL, + EVENT_FILTERS_URL, + EXCEPTIONS_URL, + EXPLORE_URL, + GET_STARTED_URL, + HOST_ISOLATION_EXCEPTIONS_URL, + INVESTIGATIONS_URL, + HOSTS_URL, + MACHINE_LEARNING_EXPLORER, + MACHINE_LEARNING_TIME_SERIES_EXPLORER, + MACHINE_LEARNING_DATA_FRAME_ANALYTICS_EXPLORATION, + MACHINE_LEARNING_DATA_FRAME_ANALYTICS_MAP, + NETWORK_URL, + NOTES_URL, + OVERVIEW_URL, + POLICIES_URL, + RESPONSE_ACTIONS_HISTORY, + THREAT_INTELLIGENCE_URL, + TIMELINES_URL, + TRUSTED_APPS_URL, + USERS_URL, +} from '../../../urls/navigation'; import { AI_SOC_NAVIGATION } from '../../../screens/ai_soc'; -const visibleLinks = ['discover', 'attack_discovery', 'case', 'alert_summary', 'configurations']; +const visibleLinks = ['alert_summary', 'attack_discovery', 'cases', 'configurations', 'discover']; +const notVisibleLinks = [ + 'securityGroup:rules', + 'alerts', + 'cloud_security_posture-findings', + 'threat_intelligence', + 'securityGroup:explore', + 'securityGroup:assets', + 'securityGroup:machine_learning', + 'alerts', + 'rules', +]; -const notVisibleLinks = ['machine_learning-landing', 'alerts', 'rules']; +const redirectedLinks = [ + ALERTS_URL, + ASSETS_URL, + ASSET_INVENTORY_URL, + CREATE_RULE_URL, + CSP_DASHBOARD_URL, + CSP_FINDINGS_URL, + CSP_VULNERABILITIES_URL, + CSP_BENCHMARKS_URL, + DASHBOARDS_URL, + ENTITY_ANALYTICS_MANAGEMENT_URL, + ENTITY_ANALYTICS_ENTITY_STORE_URL, + EXPLORE_URL, + HOSTS_URL, + INVESTIGATIONS_URL, + NETWORK_URL, + NOTES_URL, + OVERVIEW_URL, + TIMELINES_URL, + USERS_URL, +]; +const upSellLinks = [EXCEPTIONS_URL, THREAT_INTELLIGENCE_URL]; +const privilegeRequiredLinks = [ + ENDPOINTS_URL, + POLICIES_URL, + TRUSTED_APPS_URL, + EVENT_FILTERS_URL, + BLOCKLIST_URL, + HOST_ISOLATION_EXCEPTIONS_URL, + RESPONSE_ACTIONS_HISTORY, +]; +const mlLinks = [ + MACHINE_LEARNING_EXPLORER, + MACHINE_LEARNING_TIME_SERIES_EXPLORER, + MACHINE_LEARNING_DATA_FRAME_ANALYTICS_EXPLORATION, + MACHINE_LEARNING_DATA_FRAME_ANALYTICS_MAP, +]; -describe('AI$DSOC Navigation', { tags: '@serverless' }, () => { +const linkedPagesAssertions: Record void> = { + alert_summary: () => { + cy.getByTestSubjContains('alert-summary-landing-page-prompt').should('exist'); + }, + attack_discovery: () => { + cy.getByTestSubjContains('attackDiscoveryPageTitle').should('contain', 'Attack discovery'); + }, + cases: () => { + cy.getByTestSubjContains('header-page-title').should('contain', 'Cases'); + }, + configurations: () => { + cy.url().should('include', `/configurations/integrations`); + cy.get('.euiTab').then((tabs) => { + const tabNames = Array.from(tabs).map((tab) => tab.innerText); + expect(tabNames).to.deep.equal(['Integrations', 'Rules', 'AI settings']); + }); + }, + discover: () => { + cy.getByTestSubjContains('discoverSavedSearchTitle').should( + 'contain', + 'Discover - Search not yet saved' + ); + }, +}; + +describe('AI4dSoC 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) @@ -34,4 +141,55 @@ describe('AI$DSOC Navigation', { tags: '@serverless' }, () => { }); }); }); + + describe('renders pages within links correctly', () => { + it('should show the correct page for visible links when navigating', () => { + cy.get(AI_SOC_NAVIGATION).should('exist'); + + visibleLinks.forEach((link) => { + cy.getByTestSubjContains(`nav-item-id-${link}`).click(); + cy.url().should('include', `/${link}`); + cy.getByTestSubjContains(`nav-item-id-${link}`).click(); + + // Assert that the page contains the expected content + linkedPagesAssertions[link](); + }); + }); + }); + + describe('Redirected pages', () => { + it('should redirect to the "get started page"', () => { + redirectedLinks.forEach((link) => { + cy.visit(link); + cy.url().should('include', GET_STARTED_URL); + }); + }); + }); + + // TODO: Undecided if these pages should be redirected as well. + describe('Non-redirected pages ', () => { + it('shows `up-sell callout` for a set of pages', () => { + upSellLinks.forEach((link) => { + cy.visit(link); + cy.url().should('include', link); + cy.get('.euiTitle').should('contain', 'Do more with Security'); + }); + }); + + it('shows `privilege required` callout for `endpoint` related pages', () => { + privilegeRequiredLinks.forEach((link) => { + cy.visit(link); + cy.url().should('include', link); + cy.getByTestSubjContains('noPrivilegesPage').should('exist'); + }); + }); + + it('shows access denied callout for a set of `ml` links', () => { + mlLinks.forEach((link) => { + cy.visit(link); + cy.url().should('include', link); + cy.getByTestSubjContains('mlAccessDenied').should('exist'); + }); + }); + }); }); 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 3025d7de7e325..bf47b7613acab 100644 --- a/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts +++ b/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts @@ -19,9 +19,14 @@ export const POLICIES_URL = '/app/security/administration/policy'; export const TRUSTED_APPS_URL = '/app/security/administration/trusted_apps'; export const EVENT_FILTERS_URL = '/app/security/administration/event_filters'; export const BLOCKLIST_URL = '/app/security/administration/blocklist'; +export const HOST_ISOLATION_EXCEPTIONS_URL = `app/security/administration/host_isolation_exceptions`; +export const RESPONSE_ACTIONS_HISTORY = `app/security/administration/response_actions_history`; + export const CSP_BENCHMARKS_URL = '/app/security/cloud_security_posture/benchmarks'; export const CSP_DASHBOARD_URL = '/app/security/cloud_security_posture/dashboard'; export const CSP_FINDINGS_URL = '/app/security/cloud_security_posture/findings/configurations'; +export const CSP_VULNERABILITIES_URL = + '/app/security/cloud_security_posture/findings/vulnerabilities'; export const RULES_URL = '/app/security/rules'; export const RULES_COVERAGE_URL = '/app/security/rules_coverage_overview'; @@ -34,6 +39,7 @@ export const OVERVIEW_URL = '/app/security/overview'; export const ENTITY_ANALYTICS_URL = '/app/security/entity_analytics'; export const KUBERNETES_URL = '/app/security/kubernetes'; +export const THREAT_INTELLIGENCE_URL = '/app/security/threat_intelligence'; export const INDICATORS_URL = '/app/security/threat_intelligence/indicators'; export const EXPLORE_URL = '/app/security/explore'; export const userDetailsUrl = (userName: string) => @@ -43,6 +49,7 @@ export const INVESTIGATIONS_URL = '/app/security/investigations'; export const TIMELINES_URL = '/app/security/timelines/default'; export const TIMELINE_TEMPLATES_URL = '/app/security/timelines/template'; export const CASES_URL = '/app/security/cases'; +export const NOTES_URL = '/app/security/administration/notes'; export const hostsUrl = (tab: 'allHosts' | 'anomalies' | 'events' | 'uncommonProcesses'): string => `/app/security/hosts/${tab}`; @@ -60,7 +67,11 @@ export const DISCOVER_WITH_PINNED_FILTER_URL = export const hostDetailsUrl = (hostName: string) => `/app/security/hosts/${hostName}/authentications`; -export const MACHINE_LEARNING_LANDING_URL = '/app/security/ml'; +export const MACHINE_LEARNING_EXPLORER = '/app/ml/explorer'; +export const MACHINE_LEARNING_TIME_SERIES_EXPLORER = '/app/ml/timeseriesexplorer'; +export const MACHINE_LEARNING_DATA_FRAME_ANALYTICS_EXPLORATION = + 'app/ml/data_frame_analytics/exploration'; +export const MACHINE_LEARNING_DATA_FRAME_ANALYTICS_MAP = 'app/ml/data_frame_analytics/map'; // Detection and Response export const DETECTION_AND_RESPONSE_URL = '/app/security/detection_response'; @@ -69,6 +80,7 @@ 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'; +export const ENTITY_ANALYTICS_ENTITY_STORE_URL = '/app/security/entity_analytics_entity_store'; export const ENTITY_ANALYTICS_ASSET_CRITICALITY_URL = '/app/security/entity_analytics_asset_criticality';