diff --git a/src/plugins/ui_actions/public/types.ts b/src/plugins/ui_actions/public/types.ts index e8ee3f39996a3..6d689f6776d96 100644 --- a/src/plugins/ui_actions/public/types.ts +++ b/src/plugins/ui_actions/public/types.ts @@ -27,7 +27,7 @@ export interface VisualizeFieldContext { export interface CategorizeFieldContext { field: DataViewField; dataView: DataView; - originatingApp?: string; + originatingApp: string; } export const ACTION_VISUALIZE_FIELD = 'ACTION_VISUALIZE_FIELD'; diff --git a/x-pack/packages/ml/response_stream/client/fetch_stream.ts b/x-pack/packages/ml/response_stream/client/fetch_stream.ts index da262f423d47d..7384b5f2311e2 100644 --- a/x-pack/packages/ml/response_stream/client/fetch_stream.ts +++ b/x-pack/packages/ml/response_stream/client/fetch_stream.ts @@ -8,7 +8,7 @@ import startsWith from 'lodash/startsWith'; import type { Reducer, ReducerAction } from 'react'; -import type { HttpSetup } from '@kbn/core/public'; +import type { HttpSetup, HttpFetchOptions } from '@kbn/core/public'; type GeneratorError = string | null; @@ -42,7 +42,8 @@ export async function* fetchStream apiVersion: string | undefined, abortCtrl: React.MutableRefObject, body?: B, - ndjson = true + ndjson = true, + headers?: HttpFetchOptions['headers'] ): AsyncGenerator<[GeneratorError, ReducerAction | Array> | undefined]> { let stream: Readonly | undefined; @@ -52,6 +53,7 @@ export async function* fetchStream version: apiVersion, asResponse: true, rawResponse: true, + headers, ...(body && Object.keys(body).length > 0 ? { body: JSON.stringify(body) } : {}), }); diff --git a/x-pack/packages/ml/response_stream/client/use_fetch_stream.ts b/x-pack/packages/ml/response_stream/client/use_fetch_stream.ts index d2d140f80ee41..309d53e8dd4bd 100644 --- a/x-pack/packages/ml/response_stream/client/use_fetch_stream.ts +++ b/x-pack/packages/ml/response_stream/client/use_fetch_stream.ts @@ -16,7 +16,7 @@ import { } from 'react'; import useThrottle from 'react-use/lib/useThrottle'; -import type { HttpSetup } from '@kbn/core/public'; +import type { HttpSetup, HttpFetchOptions } from '@kbn/core/public'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { fetchStream } from './fetch_stream'; @@ -64,7 +64,8 @@ export function useFetchStream>( endpoint: string, apiVersion?: string, body?: B, - customReducer?: FetchStreamCustomReducer + customReducer?: FetchStreamCustomReducer, + headers?: HttpFetchOptions['headers'] ) { const [errors, setErrors] = useState([]); const [isCancelled, setIsCancelled] = useState(false); @@ -104,7 +105,8 @@ export function useFetchStream>( apiVersion, abortCtrl, body, - customReducer !== undefined + customReducer !== undefined, + headers )) { if (fetchStreamError !== null) { addError(fetchStreamError); diff --git a/x-pack/plugins/aiops/common/constants.ts b/x-pack/plugins/aiops/common/constants.ts index c8831aa06b330..226082e6041b9 100644 --- a/x-pack/plugins/aiops/common/constants.ts +++ b/x-pack/plugins/aiops/common/constants.ts @@ -19,3 +19,8 @@ export const RANDOM_SAMPLER_SEED = 3867412; export const CASES_ATTACHMENT_CHANGE_POINT_CHART = 'aiopsChangePointChart'; export const EMBEDDABLE_CHANGE_POINT_CHART_TYPE = 'aiopsChangePointChart' as const; + +export const AIOPS_TELEMETRY_ID = { + AIOPS_DEFAULT_SOURCE: 'ml_aiops_labs', + AIOPS_ANALYSIS_RUN_ORIGIN: 'aiops-analysis-run-origin', +} as const; diff --git a/x-pack/plugins/aiops/kibana.jsonc b/x-pack/plugins/aiops/kibana.jsonc index 9b787992c7c54..192fa65cd9a2b 100644 --- a/x-pack/plugins/aiops/kibana.jsonc +++ b/x-pack/plugins/aiops/kibana.jsonc @@ -20,7 +20,8 @@ "unifiedSearch" ], "optionalPlugins": [ - "cases" + "cases", + "usageCollection" ], "requiredBundles": [ "fieldFormats", diff --git a/x-pack/plugins/aiops/public/components/log_categorization/categorize_field_actions.ts b/x-pack/plugins/aiops/public/components/log_categorization/categorize_field_actions.ts index b915626ade72c..4d03465605463 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/categorize_field_actions.ts +++ b/x-pack/plugins/aiops/public/components/log_categorization/categorize_field_actions.ts @@ -27,7 +27,7 @@ export const categorizeFieldAction = (coreStart: CoreStart, plugins: AiopsPlugin return field.esTypes?.includes('text') === true; }, execute: async (context: CategorizeFieldContext) => { - const { field, dataView } = context; - showCategorizeFlyout(field, dataView, coreStart, plugins); + const { field, dataView, originatingApp } = context; + showCategorizeFlyout(field, dataView, coreStart, plugins, originatingApp); }, }); diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx index c6e2600b7e4f4..46e3de8b01b67 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx @@ -15,6 +15,7 @@ import { Storage } from '@kbn/kibana-utils-plugin/public'; import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; +import { AIOPS_TELEMETRY_ID } from '../../../common/constants'; import { DataSourceContext } from '../../hooks/use_data_source'; import type { AiopsAppDependencies } from '../../hooks/use_aiops_app_context'; import { AIOPS_STORAGE_KEYS } from '../../types/storage'; @@ -65,7 +66,7 @@ export const LogCategorizationAppState: FC = ({ - + diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx index 28c1350a88141..a5262393e0eec 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx @@ -22,6 +22,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { buildEmptyFilter, Filter } from '@kbn/es-query'; import { usePageUrlState } from '@kbn/ml-url-state'; import type { FieldValidationResults } from '@kbn/ml-category-validator'; +import { AIOPS_TELEMETRY_ID } from '../../../common/constants'; import type { Category, SparkLinesPerCategory } from '../../../common/api/log_categorization/types'; @@ -49,6 +50,8 @@ export interface LogCategorizationPageProps { savedSearch: SavedSearch | null; selectedField: DataViewField; onClose: () => void; + /** Identifier to indicate the plugin utilizing the component */ + embeddingOrigin: string; } const BAR_TARGET = 20; @@ -58,6 +61,7 @@ export const LogCategorizationFlyout: FC = ({ savedSearch, selectedField, onClose, + embeddingOrigin, }) => { const { notifications: { toasts }, @@ -151,7 +155,8 @@ export const LogCategorizationFlyout: FC = ({ timeField, earliest, latest, - searchQuery + searchQuery, + { [AIOPS_TELEMETRY_ID.AIOPS_ANALYSIS_RUN_ORIGIN]: embeddingOrigin } ), runCategorizeRequest( index, @@ -193,6 +198,7 @@ export const LogCategorizationFlyout: FC = ({ runCategorizeRequest, intervalMs, toasts, + embeddingOrigin, ]); const onAddFilter = useCallback( diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx index bfa609bb5dd21..af3a636be27e8 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx @@ -26,6 +26,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { usePageUrlState, useUrlState } from '@kbn/ml-url-state'; import type { FieldValidationResults } from '@kbn/ml-category-validator'; import type { SearchQueryLanguage } from '@kbn/ml-query-utils'; +import { AIOPS_TELEMETRY_ID } from '../../../common/constants'; import type { Category, SparkLinesPerCategory } from '../../../common/api/log_categorization/types'; @@ -53,7 +54,12 @@ import { FieldValidationCallout } from './category_validation_callout'; const BAR_TARGET = 20; const DEFAULT_SELECTED_FIELD = 'message'; -export const LogCategorizationPage: FC = () => { +interface LogCategorizationPageProps { + /** Identifier to indicate the plugin utilizing the component */ + embeddingOrigin: string; +} + +export const LogCategorizationPage: FC = ({ embeddingOrigin }) => { const { notifications: { toasts }, } = useAiopsAppContext(); @@ -208,7 +214,10 @@ export const LogCategorizationPage: FC = () => { try { const [validationResult, categorizationResult] = await Promise.all([ - runValidateFieldRequest(index, selectedField, timeField, earliest, latest, searchQuery), + runValidateFieldRequest(index, selectedField, timeField, earliest, latest, searchQuery, { + [AIOPS_TELEMETRY_ID.AIOPS_ANALYSIS_RUN_ORIGIN]: embeddingOrigin, + }), + runCategorizeRequest( index, selectedField, @@ -245,6 +254,7 @@ export const LogCategorizationPage: FC = () => { runCategorizeRequest, intervalMs, toasts, + embeddingOrigin, ]); useEffect( diff --git a/x-pack/plugins/aiops/public/components/log_categorization/show_flyout.tsx b/x-pack/plugins/aiops/public/components/log_categorization/show_flyout.tsx index 5890bd8a2f74d..36606b85a55a7 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/show_flyout.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/show_flyout.tsx @@ -29,7 +29,8 @@ export async function showCategorizeFlyout( field: DataViewField, dataView: DataView, coreStart: CoreStart, - plugins: AiopsPluginStartDeps + plugins: AiopsPluginStartDeps, + originatingApp: string ): Promise { const { http, theme, overlays, application, notifications, uiSettings, i18n } = coreStart; @@ -70,6 +71,7 @@ export async function showCategorizeFlyout( savedSearch={null} selectedField={field} onClose={onFlyoutClose} + embeddingOrigin={originatingApp} /> diff --git a/x-pack/plugins/aiops/public/components/log_categorization/use_validate_category_field.ts b/x-pack/plugins/aiops/public/components/log_categorization/use_validate_category_field.ts index 8e0850aa1daa8..e9587e97b2eca 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/use_validate_category_field.ts +++ b/x-pack/plugins/aiops/public/components/log_categorization/use_validate_category_field.ts @@ -11,6 +11,8 @@ import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/type import type { FieldValidationResults } from '@kbn/ml-category-validator'; +import type { HttpFetchOptions } from '@kbn/core/public'; + import { AIOPS_API_ENDPOINT } from '../../../common/api'; import { createCategorizeQuery } from '../../../common/api/log_categorization/create_categorize_query'; @@ -27,7 +29,8 @@ export function useValidateFieldRequest() { timeField: string, start: number | undefined, end: number | undefined, - queryIn: QueryDslQueryContainer + queryIn: QueryDslQueryContainer, + headers?: HttpFetchOptions['headers'] ) => { const query = createCategorizeQuery(queryIn, timeField, start, end); const resp = await http.post( @@ -48,6 +51,7 @@ export function useValidateFieldRequest() { indicesOptions: undefined, includeExamples: false, }), + headers, version: '1', } ); diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx index e27d3af3aefa7..5e2af3d4cb917 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx @@ -64,6 +64,8 @@ export interface LogRateAnalysisContentProps { barHighlightColorOverride?: string; /** Optional callback that exposes data of the completed analysis */ onAnalysisCompleted?: (d: LogRateAnalysisResultsData) => void; + /** Identifier to indicate the plugin utilizing the component */ + embeddingOrigin: string; } export const LogRateAnalysisContent: FC = ({ @@ -76,6 +78,7 @@ export const LogRateAnalysisContent: FC = ({ barColorOverride, barHighlightColorOverride, onAnalysisCompleted, + embeddingOrigin, }) => { const [windowParameters, setWindowParameters] = useState(); const [initialAnalysisStart, setInitialAnalysisStart] = useState< @@ -172,6 +175,7 @@ export const LogRateAnalysisContent: FC = ({ barColorOverride={barColorOverride} barHighlightColorOverride={barHighlightColorOverride} onAnalysisCompleted={onAnalysisCompleted} + embeddingOrigin={embeddingOrigin} /> )} {windowParameters === undefined && ( diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx index 806dc7f0e2cb2..62fac2312ebfd 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx @@ -59,6 +59,8 @@ export interface LogRateAnalysisContentWrapperProps { onAnalysisCompleted?: (d: LogRateAnalysisResultsData) => void; /** Optional flag to indicate whether kibana is running in serverless */ showFrozenDataTierChoice?: boolean; + /** Identifier to indicate the plugin utilizing the component */ + embeddingOrigin: string; } export const LogRateAnalysisContentWrapper: FC = ({ @@ -73,6 +75,7 @@ export const LogRateAnalysisContentWrapper: FC { if (!dataView) return null; @@ -105,6 +108,7 @@ export const LogRateAnalysisContentWrapper: FC diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx index 3c092f5e91f67..c3d53fb999023 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx @@ -22,6 +22,7 @@ import { getDefaultAiOpsListState, type AiOpsPageUrlState, } from '../../application/utils/url_state'; +import { AIOPS_TELEMETRY_ID } from '../../../common/constants'; import { SearchPanel } from '../search_panel'; import { useLogRateAnalysisResultsTableRowContext } from '../log_rate_analysis_results_table/log_rate_analysis_results_table_row_provider'; @@ -151,6 +152,7 @@ export const LogRateAnalysisPage: FC = ({ stickyHistogram }) => { setGlobalState={setGlobalState} esSearchQuery={searchQuery} stickyHistogram={stickyHistogram} + embeddingOrigin={AIOPS_TELEMETRY_ID.AIOPS_DEFAULT_SOURCE} /> diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx index a62db054d4d52..40ee98f3234dc 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx @@ -36,6 +36,7 @@ import type { SignificantTerm, SignificantTermGroup } from '@kbn/ml-agg-utils'; import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; import { initialState, streamReducer } from '../../../common/api/stream_reducer'; import type { AiopsApiLogRateAnalysis } from '../../../common/api'; +import { AIOPS_TELEMETRY_ID } from '../../../common/constants'; import { getGroupTableItems, LogRateAnalysisResultsTable, @@ -113,6 +114,8 @@ interface LogRateAnalysisResultsProps { barHighlightColorOverride?: string; /** Optional callback that exposes data of the completed analysis */ onAnalysisCompleted?: (d: LogRateAnalysisResultsData) => void; + /** Identifier to indicate the plugin utilizing the component */ + embeddingOrigin: string; } export const LogRateAnalysisResults: FC = ({ @@ -129,6 +132,7 @@ export const LogRateAnalysisResults: FC = ({ barColorOverride, barHighlightColorOverride, onAnalysisCompleted, + embeddingOrigin, }) => { const { http } = useAiopsAppContext(); @@ -198,7 +202,8 @@ export const LogRateAnalysisResults: FC = ({ overrides, sampleProbability, }, - { reducer: streamReducer, initialState } + { reducer: streamReducer, initialState }, + { [AIOPS_TELEMETRY_ID.AIOPS_ANALYSIS_RUN_ORIGIN]: embeddingOrigin } ); const { significantTerms } = data; diff --git a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_component.tsx b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_component.tsx index d7d1c84cf9f10..034450735cb09 100644 --- a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_component.tsx +++ b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_component.tsx @@ -18,6 +18,7 @@ import { EuiLoadingChart } from '@elastic/eui'; import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '../../common/constants'; import type { AiopsPluginStartDeps } from '../types'; import type { EmbeddableChangePointChartInput } from './embeddable_change_point_chart'; +import type { ChangePointAnnotation } from '../components/change_point_detection/change_point_detection_context'; export interface EmbeddableChangePointChartProps { dataViewId: string; @@ -27,6 +28,18 @@ export interface EmbeddableChangePointChartProps { splitField?: string; partitions?: string[]; maxSeriesToPlot?: number; + /** + * Component to render if there are no change points found + */ + emptyState?: React.ReactElement; + /** + * Outputs the most recent change point data + */ + onChange?: (changePointData: ChangePointAnnotation[]) => void; + /** + * Last reload request time, can be used for manual reload + */ + lastReloadRequestTime?: number; } export function getEmbeddableChangePointChart(core: CoreStart, plugins: AiopsPluginStartDeps) { diff --git a/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx b/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx index 54ed702eadf63..2bace3b693853 100644 --- a/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx +++ b/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx @@ -5,8 +5,9 @@ * 2.0. */ -import { type Observable } from 'rxjs'; -import React, { FC, useEffect, useMemo } from 'react'; +import { BehaviorSubject, type Observable, combineLatest } from 'rxjs'; +import { map, distinctUntilChanged } from 'rxjs/operators'; +import React, { FC, useEffect, useMemo, useState } from 'react'; import { useTimefilter } from '@kbn/ml-date-picker'; import { css } from '@emotion/react'; import useObservable from 'react-use/lib/useObservable'; @@ -55,8 +56,31 @@ export const EmbeddableInputTracker: FC = ({ }) => { const input = useObservable(input$, initialInput); + const [manualReload$] = useState>( + new BehaviorSubject(initialInput.lastReloadRequestTime ?? Date.now()) + ); + + useEffect( + function updateManualReloadSubject() { + if ( + input.lastReloadRequestTime === initialInput.lastReloadRequestTime || + !input.lastReloadRequestTime + ) + return; + manualReload$.next(input.lastReloadRequestTime); + }, + [input.lastReloadRequestTime, initialInput.lastReloadRequestTime, manualReload$] + ); + + const resultObservable$ = useMemo>(() => { + return combineLatest([reload$, manualReload$]).pipe( + map(([reload, manualReload]) => Math.max(reload, manualReload)), + distinctUntilChanged() + ); + }, [manualReload$, reload$]); + return ( - + = ({ onLoading={onLoading} onRenderComplete={onRenderComplete} onError={onError} + onChange={input.onChange} + emptyState={input.emptyState} /> @@ -103,6 +129,8 @@ export const ChartGridEmbeddableWrapper: FC< onError, onLoading, onRenderComplete, + onChange, + emptyState, }) => { const { filters, query, timeRange } = useFilerQueryUpdates(); @@ -189,8 +217,12 @@ export const ChartGridEmbeddableWrapper: FC< resultChangePoints = resultChangePoints.slice(0, maxSeriesToPlot); } + if (onChange) { + onChange(resultChangePoints); + } + return resultChangePoints; - }, [results, maxSeriesToPlot]); + }, [results, maxSeriesToPlot, onChange]); return (
+ ) : emptyState ? ( + emptyState ) : ( )} diff --git a/x-pack/plugins/aiops/public/types.ts b/x-pack/plugins/aiops/public/types.ts index 9c28951c25c99..e0f86c68864bd 100755 --- a/x-pack/plugins/aiops/public/types.ts +++ b/x-pack/plugins/aiops/public/types.ts @@ -17,8 +17,8 @@ import type { UiActionsStart, UiActionsSetup } from '@kbn/ui-actions-plugin/publ import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import type { CasesUiSetup } from '@kbn/cases-plugin/public'; -import { LicensingPluginSetup } from '@kbn/licensing-plugin/public'; -import type { EmbeddableChangePointChartProps } from './embeddable'; +import type { LicensingPluginSetup } from '@kbn/licensing-plugin/public'; +import type { EmbeddableChangePointChartInput } from './embeddable/embeddable_change_point_chart'; export interface AiopsPluginSetupDeps { embeddable: EmbeddableSetup; @@ -44,5 +44,5 @@ export interface AiopsPluginStartDeps { export type AiopsPluginSetup = void; export interface AiopsPluginStart { - EmbeddableChangePointChart: React.ComponentType; + EmbeddableChangePointChart: React.ComponentType; } diff --git a/x-pack/plugins/aiops/server/lib/track_route_usage.test.ts b/x-pack/plugins/aiops/server/lib/track_route_usage.test.ts new file mode 100644 index 0000000000000..31e8435e7be3f --- /dev/null +++ b/x-pack/plugins/aiops/server/lib/track_route_usage.test.ts @@ -0,0 +1,32 @@ +/* + * 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 { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; +import { trackAIOpsRouteUsage } from './track_route_usage'; + +describe('trackAIOpsRouteUsage', () => { + it('should call `usageCounter.incrementCounter`', () => { + const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); + const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); + + trackAIOpsRouteUsage('test_type', 'test_source', mockUsageCounter); + expect(mockUsageCounter.incrementCounter).toHaveBeenCalledWith({ + counterName: 'test_type', + counterType: 'run_via_test_source', + incrementBy: 1, + }); + }); + + it('should do nothing if no usage counter is provided', () => { + let err; + try { + trackAIOpsRouteUsage('test', undefined); + } catch (e) { + err = e; + } + expect(err).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/aiops/server/lib/track_route_usage.ts b/x-pack/plugins/aiops/server/lib/track_route_usage.ts new file mode 100644 index 0000000000000..ebea9cd0c24c6 --- /dev/null +++ b/x-pack/plugins/aiops/server/lib/track_route_usage.ts @@ -0,0 +1,22 @@ +/* + * 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 { UsageCounter } from '@kbn/usage-collection-plugin/server'; + +export function trackAIOpsRouteUsage( + analysisType: string, + source?: string | string[], + usageCounter?: UsageCounter +) { + if (usageCounter && typeof source === 'string') { + usageCounter.incrementCounter({ + counterName: analysisType, + counterType: `run_via_${source}`, + incrementBy: 1, + }); + } +} diff --git a/x-pack/plugins/aiops/server/plugin.ts b/x-pack/plugins/aiops/server/plugin.ts index 356dfc570e6ef..2adcb2aaaa88b 100755 --- a/x-pack/plugins/aiops/server/plugin.ts +++ b/x-pack/plugins/aiops/server/plugin.ts @@ -9,8 +9,10 @@ import { Subscription } from 'rxjs'; import { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server'; import type { DataRequestHandlerContext } from '@kbn/data-plugin/server'; +import type { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { CASES_ATTACHMENT_CHANGE_POINT_CHART } from '../common/constants'; +import { PLUGIN_ID } from '../common'; import { isActiveLicense } from './lib/license'; import { AiopsLicense, @@ -28,6 +30,7 @@ export class AiopsPlugin { private readonly logger: Logger; private licenseSubscription: Subscription | null = null; + private usageCounter?: UsageCounter; constructor(initializerContext: PluginInitializerContext) { this.logger = initializerContext.logger.get(); @@ -38,6 +41,7 @@ export class AiopsPlugin plugins: AiopsPluginSetupDeps ) { this.logger.debug('aiops: Setup'); + this.usageCounter = plugins.usageCollection?.createUsageCounter(PLUGIN_ID); // Subscribe to license changes and store the current license in `currentLicense`. // This way we can pass on license changes to the route factory having always @@ -51,8 +55,8 @@ export class AiopsPlugin // Register server side APIs core.getStartServices().then(([coreStart, depsStart]) => { - defineLogRateAnalysisRoute(router, aiopsLicense, this.logger, coreStart); - defineLogCategorizationRoutes(router, aiopsLicense); + defineLogRateAnalysisRoute(router, aiopsLicense, this.logger, coreStart, this.usageCounter); + defineLogCategorizationRoutes(router, aiopsLicense, this.usageCounter); }); if (plugins.cases) { diff --git a/x-pack/plugins/aiops/server/routes/log_categorization.ts b/x-pack/plugins/aiops/server/routes/log_categorization.ts index 9ce8bd3379f0e..dd437f68617ad 100644 --- a/x-pack/plugins/aiops/server/routes/log_categorization.ts +++ b/x-pack/plugins/aiops/server/routes/log_categorization.ts @@ -8,14 +8,18 @@ import type { IRouter } from '@kbn/core/server'; import type { DataRequestHandlerContext } from '@kbn/data-plugin/server'; import { categorizationExamplesProvider } from '@kbn/ml-category-validator'; +import type { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { categorizationFieldValidationSchema } from '../../common/api/log_categorization/schema'; import { AIOPS_API_ENDPOINT } from '../../common/api'; import type { AiopsLicense } from '../types'; import { wrapError } from './error_wrapper'; +import { trackAIOpsRouteUsage } from '../lib/track_route_usage'; +import { AIOPS_TELEMETRY_ID } from '../../common/constants'; export const defineLogCategorizationRoutes = ( router: IRouter, - license: AiopsLicense + license: AiopsLicense, + usageCounter?: UsageCounter ) => { router.versioned .post({ @@ -32,6 +36,13 @@ export const defineLogCategorizationRoutes = ( }, }, async (context, request, response) => { + const { headers } = request; + trackAIOpsRouteUsage( + `POST ${AIOPS_API_ENDPOINT.CATEGORIZATION_FIELD_VALIDATION}`, + headers[AIOPS_TELEMETRY_ID.AIOPS_ANALYSIS_RUN_ORIGIN], + usageCounter + ); + if (!license.isActivePlatinumLicense) { return response.forbidden(); } diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis.ts index f31f6c5f30c35..a9ccce753a02a 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis.ts @@ -23,8 +23,9 @@ import type { } from '@kbn/ml-agg-utils'; import { fetchHistogramsForFields } from '@kbn/ml-agg-utils'; import { createExecutionContext } from '@kbn/ml-route-utils'; +import type { UsageCounter } from '@kbn/usage-collection-plugin/server'; -import { RANDOM_SAMPLER_SEED } from '../../common/constants'; +import { RANDOM_SAMPLER_SEED, AIOPS_TELEMETRY_ID } from '../../common/constants'; import { addSignificantTermsAction, addSignificantTermsGroupAction, @@ -52,6 +53,7 @@ import { fetchFrequentItemSets } from './queries/fetch_frequent_item_sets'; import { getHistogramQuery } from './queries/get_histogram_query'; import { getGroupFilter } from './queries/get_group_filter'; import { getSignificantTermGroups } from './queries/get_significant_term_groups'; +import { trackAIOpsRouteUsage } from '../lib/track_route_usage'; // 10s ping frequency to keep the stream alive. const PING_FREQUENCY = 10000; @@ -67,7 +69,8 @@ export const defineLogRateAnalysisRoute = ( router: IRouter, license: AiopsLicense, logger: Logger, - coreStart: CoreStart + coreStart: CoreStart, + usageCounter?: UsageCounter ) => { router.versioned .post({ @@ -85,6 +88,14 @@ export const defineLogRateAnalysisRoute = ( }, }, async (context, request, response) => { + const { headers } = request; + + trackAIOpsRouteUsage( + `POST ${AIOPS_API_ENDPOINT.LOG_RATE_ANALYSIS}`, + headers[AIOPS_TELEMETRY_ID.AIOPS_ANALYSIS_RUN_ORIGIN], + usageCounter + ); + if (!license.isActivePlatinumLicense) { return response.forbidden(); } diff --git a/x-pack/plugins/aiops/server/types.ts b/x-pack/plugins/aiops/server/types.ts index 8359996138dce..562f6f7535b87 100755 --- a/x-pack/plugins/aiops/server/types.ts +++ b/x-pack/plugins/aiops/server/types.ts @@ -8,11 +8,13 @@ import type { PluginSetup, PluginStart } from '@kbn/data-plugin/server'; import type { LicensingPluginStart } from '@kbn/licensing-plugin/server'; import type { CasesSetup } from '@kbn/cases-plugin/server'; +import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; export interface AiopsPluginSetupDeps { data: PluginSetup; licensing: LicensingPluginStart; cases?: CasesSetup; + usageCollection?: UsageCollectionSetup; } export interface AiopsPluginStartDeps { diff --git a/x-pack/plugins/aiops/tsconfig.json b/x-pack/plugins/aiops/tsconfig.json index 6ee1275439d6e..6303a009bb36d 100644 --- a/x-pack/plugins/aiops/tsconfig.json +++ b/x-pack/plugins/aiops/tsconfig.json @@ -63,6 +63,7 @@ "@kbn/core-lifecycle-browser", "@kbn/cases-plugin", "@kbn/react-kibana-mount", + "@kbn/usage-collection-plugin", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx index cc841b200a5b5..acddb4677bf07 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx @@ -24,6 +24,7 @@ import { useTimeRange } from '../../../../hooks/use_time_range'; import { getAlertingCapabilities } from '../../../alerting/utils/get_alerting_capabilities'; import { MobileSearchBar } from '../../../app/mobile/search_bar'; import { ServiceIcons } from '../../../shared/service_icons'; +import { BetaBadge } from '../../../shared/beta_badge'; import { TechnicalPreviewBadge } from '../../../shared/technical_preview_badge'; import { ApmMainTemplate } from '../apm_main_template'; import { AnalyzeDataButton } from '../apm_service_template/analyze_data_button'; @@ -122,7 +123,7 @@ function TemplateWithContext({ /> - + diff --git a/x-pack/plugins/elastic_assistant/server/routes/evaluate/utils.ts b/x-pack/plugins/elastic_assistant/server/routes/evaluate/utils.ts index b1a37a5e60e81..a519398f158be 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/evaluate/utils.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/evaluate/utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/common/gen_ai/constants'; +import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/common/openai/constants'; import type { ActionResult } from '@kbn/actions-plugin/server'; /** diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/log_rate_analysis.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/log_rate_analysis.tsx index 8dc2688956a49..8ffb0cc87a1d9 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/log_rate_analysis.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/log_rate_analysis.tsx @@ -268,6 +268,7 @@ export const LogRateAnalysis: FC = ({ r {ruleParams.criteria.map((criterion, criterionIndex) => - criterion.metrics?.map( - (metric, metricIndex) => - dataView && - dataView.id && ( - - ) - ) + criterion.metrics?.map((metric, metricIndex) => { + const id = `embeddableChart-criterion${criterionIndex}-metric${metricIndex}`; + return dataView?.id ? ( + + ) : null; + }) )} diff --git a/x-pack/plugins/security_solution/common/api/search_strategy/hosts/all.ts b/x-pack/plugins/security_solution/common/api/search_strategy/hosts/all.ts index b79c4b3afe93d..fdc2e992a20a1 100644 --- a/x-pack/plugins/security_solution/common/api/search_strategy/hosts/all.ts +++ b/x-pack/plugins/security_solution/common/api/search_strategy/hosts/all.ts @@ -16,7 +16,7 @@ export const allHostsSchema = requestBasicOptionsSchema.extend({ sort, pagination, timerange, - isNewRiskScoreModuleAvailable: z.boolean().default(false), + isNewRiskScoreModuleInstalled: z.boolean().default(false), factoryQueryType: z.literal(HostsQueries.hosts), }); diff --git a/x-pack/plugins/security_solution/common/api/search_strategy/related_entities/related_hosts.ts b/x-pack/plugins/security_solution/common/api/search_strategy/related_entities/related_hosts.ts index 0db0effe8e3b1..ffb7946f59e47 100644 --- a/x-pack/plugins/security_solution/common/api/search_strategy/related_entities/related_hosts.ts +++ b/x-pack/plugins/security_solution/common/api/search_strategy/related_entities/related_hosts.ts @@ -15,7 +15,7 @@ export const relatedHostsRequestOptionsSchema = requestBasicOptionsSchema.extend skip: z.boolean().optional(), from: z.string(), inspect, - isNewRiskScoreModuleAvailable: z.boolean().default(false), + isNewRiskScoreModuleInstalled: z.boolean().default(false), factoryQueryType: z.literal(RelatedEntitiesQueries.relatedHosts), }); diff --git a/x-pack/plugins/security_solution/common/api/search_strategy/related_entities/related_users.ts b/x-pack/plugins/security_solution/common/api/search_strategy/related_entities/related_users.ts index f1386591836ba..aeeedf0a0eaa0 100644 --- a/x-pack/plugins/security_solution/common/api/search_strategy/related_entities/related_users.ts +++ b/x-pack/plugins/security_solution/common/api/search_strategy/related_entities/related_users.ts @@ -15,7 +15,7 @@ export const relatedUsersRequestOptionsSchema = requestBasicOptionsSchema.extend skip: z.boolean().optional(), from: z.string(), inspect, - isNewRiskScoreModuleAvailable: z.boolean().default(false), + isNewRiskScoreModuleInstalled: z.boolean().default(false), factoryQueryType: z.literal(RelatedEntitiesQueries.relatedUsers), }); diff --git a/x-pack/plugins/security_solution/common/api/search_strategy/users/all.ts b/x-pack/plugins/security_solution/common/api/search_strategy/users/all.ts index 433c0ca7259cc..94ba9de7093cd 100644 --- a/x-pack/plugins/security_solution/common/api/search_strategy/users/all.ts +++ b/x-pack/plugins/security_solution/common/api/search_strategy/users/all.ts @@ -22,7 +22,7 @@ export const usersSchema = requestOptionsPaginatedSchema.extend({ field: z.enum([UsersFields.name, UsersFields.lastSeen]), }), timerange, - isNewRiskScoreModuleAvailable: z.boolean().default(false), + isNewRiskScoreModuleInstalled: z.boolean().default(false), factoryQueryType: z.literal(UsersQueries.users), }); diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/common/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/common/index.ts index 1353ec7dd14bd..1bf6ef39097d3 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/common/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/common/index.ts @@ -17,9 +17,9 @@ export { RiskQueries } from '../../../../api/search_strategy'; export const getHostRiskIndex = ( spaceId: string, onlyLatest: boolean = true, - isNewRiskScoreModuleAvailable: boolean + isNewRiskScoreModuleInstalled: boolean ): string => { - return isNewRiskScoreModuleAvailable + return isNewRiskScoreModuleInstalled ? getRiskScoreLatestIndex(spaceId) : `${RISKY_HOSTS_INDEX_PREFIX}${onlyLatest ? 'latest_' : ''}${spaceId}`; }; @@ -27,9 +27,9 @@ export const getHostRiskIndex = ( export const getUserRiskIndex = ( spaceId: string, onlyLatest: boolean = true, - isNewRiskScoreModuleAvailable: boolean + isNewRiskScoreModuleInstalled: boolean ): string => { - return isNewRiskScoreModuleAvailable + return isNewRiskScoreModuleInstalled ? getRiskScoreLatestIndex(spaceId) : `${RISKY_USERS_INDEX_PREFIX}${onlyLatest ? 'latest_' : ''}${spaceId}`; }; diff --git a/x-pack/plugins/security_solution/public/common/containers/related_entities/related_hosts/index.tsx b/x-pack/plugins/security_solution/public/common/containers/related_entities/related_hosts/index.tsx index 9ad0d13c92d6a..807e8a5d3fdd3 100644 --- a/x-pack/plugins/security_solution/public/common/containers/related_entities/related_hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/related_entities/related_hosts/index.tsx @@ -12,7 +12,7 @@ import { RelatedEntitiesQueries } from '../../../../../common/search_strategy/se import type { RelatedHost } from '../../../../../common/search_strategy/security_solution/related_entities/related_hosts'; import { useSearchStrategy } from '../../use_search_strategy'; import { FAIL_RELATED_HOSTS } from './translations'; -import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; +import { useIsNewRiskScoreModuleInstalled } from '../../../../entity_analytics/api/hooks/use_risk_engine_status'; export interface UseUserRelatedHostsResult { inspect: InspectResponse; @@ -50,7 +50,8 @@ export const useUserRelatedHosts = ({ errorMessage: FAIL_RELATED_HOSTS, abort: skip, }); - const isNewRiskScoreModuleAvailable = useIsExperimentalFeatureEnabled('riskScoringRoutesEnabled'); + + const isNewRiskScoreModuleInstalled = useIsNewRiskScoreModuleInstalled(); const userRelatedHostsResponse = useMemo( () => ({ @@ -69,9 +70,9 @@ export const useUserRelatedHosts = ({ factoryQueryType: RelatedEntitiesQueries.relatedHosts, userName, from, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, }), - [indexNames, from, userName, isNewRiskScoreModuleAvailable] + [indexNames, from, userName, isNewRiskScoreModuleInstalled] ); useEffect(() => { diff --git a/x-pack/plugins/security_solution/public/common/containers/related_entities/related_users/index.tsx b/x-pack/plugins/security_solution/public/common/containers/related_entities/related_users/index.tsx index 6184f1bebc51c..736839a5c0d1b 100644 --- a/x-pack/plugins/security_solution/public/common/containers/related_entities/related_users/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/related_entities/related_users/index.tsx @@ -12,7 +12,7 @@ import { RelatedEntitiesQueries } from '../../../../../common/search_strategy/se import type { RelatedUser } from '../../../../../common/search_strategy/security_solution/related_entities/related_users'; import { useSearchStrategy } from '../../use_search_strategy'; import { FAIL_RELATED_USERS } from './translations'; -import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; +import { useIsNewRiskScoreModuleInstalled } from '../../../../entity_analytics/api/hooks/use_risk_engine_status'; export interface UseHostRelatedUsersResult { inspect: InspectResponse; @@ -35,7 +35,7 @@ export const useHostRelatedUsers = ({ from, skip = false, }: UseHostRelatedUsersParam): UseHostRelatedUsersResult => { - const isNewRiskScoreModuleAvailable = useIsExperimentalFeatureEnabled('riskScoringRoutesEnabled'); + const isNewRiskScoreModuleInstalled = useIsNewRiskScoreModuleInstalled(); const { loading, result: response, @@ -69,9 +69,9 @@ export const useHostRelatedUsers = ({ factoryQueryType: RelatedEntitiesQueries.relatedUsers, hostName, from, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, }), - [indexNames, from, hostName, isNewRiskScoreModuleAvailable] + [indexNames, from, hostName, isNewRiskScoreModuleInstalled] ); useEffect(() => { diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_status.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_status.ts index 981fc29d8f702..504ed59a40423 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_status.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_status.ts @@ -21,19 +21,36 @@ export const useInvalidateRiskEngineStatusQuery = () => { }, [queryClient]); }; +export const useIsNewRiskScoreModuleInstalled = () => { + const { data: riskEngineStatus } = useRiskEngineStatus(); + + return riskEngineStatus?.isNewRiskScoreModuleInstalled ?? false; +}; + export const useRiskEngineStatus = () => { - const isRiskEngineEnabled = useIsExperimentalFeatureEnabled('riskScoringRoutesEnabled'); + const isNewRiskScoreModuleAvailable = useIsExperimentalFeatureEnabled('riskScoringRoutesEnabled'); return useQuery(FETCH_RISK_ENGINE_STATUS, async ({ signal }) => { - if (!isRiskEngineEnabled) { - return null; + if (!isNewRiskScoreModuleAvailable) { + return { + isUpdateAvailable: false, + isNewRiskScoreModuleInstalled: false, + isNewRiskScoreModuleAvailable, + risk_engine_status: null, + legacy_risk_engine_status: null, + is_max_amount_of_risk_engines_reached: false, + }; } const response = await fetchRiskEngineStatus({ signal }); const isUpdateAvailable = response?.legacy_risk_engine_status === RiskEngineStatus.ENABLED && response.risk_engine_status === RiskEngineStatus.NOT_INSTALLED; + const isNewRiskScoreModuleInstalled = + response.risk_engine_status !== RiskEngineStatus.NOT_INSTALLED; return { isUpdateAvailable, + isNewRiskScoreModuleInstalled, + isNewRiskScoreModuleAvailable, ...response, }; }); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_update_panel.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_update_panel.tsx index 13668bc595ad8..37baf3c6c97cd 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_update_panel.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_update_panel.tsx @@ -13,18 +13,22 @@ import { SecurityPageName } from '../../../common/constants'; export const RiskScoreUpdatePanel = () => { return ( - - {i18n.UPDATE_PANEL_MESSAGE} + <> + + {i18n.UPDATE_PANEL_MESSAGE} + + + + {i18n.UPDATE_PANEL_GO_TO_MANAGE} + + + - - - {i18n.UPDATE_PANEL_GO_TO_MANAGE} - - - + ); }; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/translations.ts b/x-pack/plugins/security_solution/public/entity_analytics/translations.ts index 837de7ca493fd..5cb9bca580269 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/translations.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/translations.ts @@ -170,14 +170,15 @@ export const UPDATE_RISK_ENGINE_MODAL_EXISTING_USER_HOST_2 = i18n.translate( export const UPDATE_RISK_ENGINE_MODAL_EXISTING_DATA_1 = i18n.translate( 'xpack.securitySolution.riskScore.updateRiskEngineModal.existingData_1', { - defaultMessage: 'None of your risk score data will be deleted', + defaultMessage: 'Legacy risk score data will not be deleted', } ); export const UPDATE_RISK_ENGINE_MODAL_EXISTING_DATA_2 = i18n.translate( 'xpack.securitySolution.riskScore.updateRiskEngineModal.existingData_2', { - defaultMessage: ', you will need to remove any old risk score data manually.', + defaultMessage: + ', it will still exist in the index but will no longer be available in the user interface. You will need to remove legacy risk score data manually.', } ); diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/enable_risk_score/index.tsx b/x-pack/plugins/security_solution/public/explore/components/risk_score/enable_risk_score/index.tsx index 864d1458eda86..4f8b12db74c9c 100644 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/enable_risk_score/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/components/risk_score/enable_risk_score/index.tsx @@ -6,7 +6,6 @@ */ import { EuiEmptyPrompt, EuiPanel, EuiToolTip } from '@elastic/eui'; import React from 'react'; -import { RiskScoreUpgradeButton } from '../risk_score_onboarding/risk_score_upgrade_button'; import type { RiskScoreEntity } from '../../../../../common/search_strategy'; import { useCheckSignalIndex } from '../../../../detections/containers/detection_engine/alerts/use_check_signal_index'; import type { inputsModel } from '../../../../common/store'; @@ -64,23 +63,12 @@ const EnableRiskScoreComponent = ({ } actions={ - {isDeprecated ? ( - - ) : ( - - )} + } /> diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_details_tab_body/index.tsx b/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_details_tab_body/index.tsx index cdff32acef9fd..208fd950315e4 100644 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_details_tab_body/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_details_tab_body/index.tsx @@ -36,7 +36,7 @@ import { useDashboardHref } from '../../../../common/hooks/use_dashboard_href'; import { RiskScoresNoDataDetected } from '../risk_score_onboarding/risk_score_no_data_detected'; import { useRiskEngineStatus } from '../../../../entity_analytics/api/hooks/use_risk_engine_status'; import { RiskScoreUpdatePanel } from '../../../../entity_analytics/components/risk_score_update_panel'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; + const StyledEuiFlexGroup = styled(EuiFlexGroup)` margin-top: ${({ theme }) => theme.eui.euiSizeL}; `; @@ -59,7 +59,6 @@ const RiskDetailsTabBodyComponent: React.FC< : UserRiskScoreQueryId.USER_DETAILS_RISK_SCORE, [riskEntity] ); - const isNewRiskScoreModuleAvailable = useIsExperimentalFeatureEnabled('riskScoringRoutesEnabled'); const severitySelectionRedux = useDeepEqualSelector((state: State) => riskEntity === RiskScoreEntity.host @@ -135,10 +134,6 @@ const RiskDetailsTabBodyComponent: React.FC< isDeprecated: isDeprecated && !loading, }; - if (riskScoreEngineStatus?.isUpdateAvailable) { - return ; - } - if (status.isDisabled || status.isDeprecated) { return ( - {isNewRiskScoreModuleAvailable ? ( + {riskScoreEngineStatus?.isUpdateAvailable && } + {riskScoreEngineStatus?.isNewRiskScoreModuleInstalled ? ( {data?.[0] && ( diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_enable_button.tsx b/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_enable_button.tsx index 208d9a2c52a2b..6e84308911edd 100644 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_enable_button.tsx +++ b/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_enable_button.tsx @@ -74,6 +74,7 @@ const RiskScoreEnableButtonComponent = ({ color="primary" fill deepLinkId={SecurityPageName.entityAnalyticsManagement} + data-test-subj={`enable_${riskScoreEntity}_risk_score`} > { - const isNewRiskScoreModuleAvailable = useIsExperimentalFeatureEnabled('riskScoringRoutesEnabled'); + const isNewRiskScoreModuleInstalled = useIsNewRiskScoreModuleInstalled(); const translations = useMemo( () => ({ @@ -51,7 +51,7 @@ const RiskScoresNoDataDetectedComponent = ({ body={translations.body} actions={ <> - {!isNewRiskScoreModuleAvailable && ( + {!isNewRiskScoreModuleInstalled && ( diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_upgrade_button.test.tsx b/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_upgrade_button.test.tsx deleted file mode 100644 index 41032690fdfd0..0000000000000 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_upgrade_button.test.tsx +++ /dev/null @@ -1,122 +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 { act, render, screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import React from 'react'; -import { RiskScoreEntity } from '../../../../../common/search_strategy'; -import { TestProviders } from '../../../../common/mock'; -import { RiskScoreUpgradeButton } from './risk_score_upgrade_button'; -import { upgradeHostRiskScoreModule, upgradeUserRiskScoreModule } from './utils'; - -jest.mock('./utils'); - -describe('RiskScoreUpgradeButton', () => { - const mockRefetch = jest.fn(); - const timerange = { - from: 'mockStartDate', - to: 'mockEndDate', - }; - const hostTestProps = { - refetch: mockRefetch, - riskScoreEntity: RiskScoreEntity.host, - timerange, - title: 'upgrade', - }; - const userTestProps = { - refetch: mockRefetch, - riskScoreEntity: RiskScoreEntity.user, - timerange, - title: 'upgrade', - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - describe.each([ - [RiskScoreEntity.host, hostTestProps], - [RiskScoreEntity.user, userTestProps], - ])('%s', (riskScoreEntity, testProps) => { - it('Renders expected children', () => { - render( - - - - ); - - expect(screen.getByTestId(`${riskScoreEntity}-risk-score-upgrade`)).toBeInTheDocument(); - expect(screen.getByTestId(`${riskScoreEntity}-risk-score-upgrade`)).toHaveTextContent( - testProps.title - ); - }); - - it('Triggers the confirmation modal before upgrading', async () => { - render( - - - - ); - - await act(async () => { - await userEvent.click(screen.getByTestId(`${riskScoreEntity}-risk-score-upgrade`)); - }); - - expect( - screen.getByTestId(`${riskScoreEntity}-risk-score-upgrade-confirmation-modal`) - ).toBeInTheDocument(); - await act(async () => { - await userEvent.click(screen.getByText('Erase data and Upgrade')); - }); - - expect( - screen.queryByTestId(`${riskScoreEntity}-risk-score-upgrade-confirmation-modal`) - ).not.toBeInTheDocument(); - - if (riskScoreEntity === RiskScoreEntity.user) { - expect(upgradeUserRiskScoreModule).toHaveBeenCalled(); - expect(upgradeHostRiskScoreModule).not.toHaveBeenCalled(); - } else { - expect(upgradeUserRiskScoreModule).not.toHaveBeenCalled(); - expect(upgradeHostRiskScoreModule).toHaveBeenCalled(); - } - }); - - it('Shows doc link in the confirmation modal', async () => { - render( - - - - ); - - await act(async () => { - await userEvent.click(screen.getByTestId(`${riskScoreEntity}-risk-score-upgrade`)); - }); - - expect(screen.getByText('Preserve data')).toHaveProperty( - 'href', - `https://www.elastic.co/guide/en/security/current/${riskScoreEntity}-risk-score.html` - ); - }); - - it('Update button state while upgrading', async () => { - render( - - - - ); - - userEvent.click(screen.getByTestId(`${riskScoreEntity}-risk-score-upgrade`)); - userEvent.click(screen.getByText('Erase data and Upgrade')); - await waitFor(() => { - expect(screen.getByTestId(`${riskScoreEntity}-risk-score-upgrade`)).toHaveProperty( - 'disabled', - true - ); - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_upgrade_button.tsx b/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_upgrade_button.tsx deleted file mode 100644 index a08710a17ed2d..0000000000000 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_upgrade_button.tsx +++ /dev/null @@ -1,127 +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 { EuiButton, EuiConfirmModal } from '@elastic/eui'; -import React, { useCallback, useState } from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { useSpaceId } from '../../../../common/hooks/use_space_id'; -import { useKibana } from '../../../../common/lib/kibana'; -import type { inputsModel } from '../../../../common/store'; -import { upgradeHostRiskScoreModule, upgradeUserRiskScoreModule } from './utils'; -import { RiskScoreEntity } from '../../../../../common/search_strategy'; -import { useRiskScoreToastContent } from './use_risk_score_toast_content'; -import { REQUEST_NAMES, useFetch } from '../../../../common/hooks/use_fetch'; -import { RiskScoreDocLink } from './risk_score_doc_link'; - -const RiskScoreUpgradeButtonComponent = ({ - disabled, - refetch, - riskScoreEntity, - timerange, - title, -}: { - disabled?: boolean; - refetch: inputsModel.Refetch; - riskScoreEntity: RiskScoreEntity; - timerange: { - from: string; - to: string; - }; - title: string; -}) => { - const spaceId = useSpaceId(); - const { http, notifications, theme, dashboard } = useKibana().services; - const { renderDocLink, renderDashboardLink } = useRiskScoreToastContent(riskScoreEntity); - const { fetch, isLoading } = useFetch( - REQUEST_NAMES.UPGRADE_RISK_SCORE, - riskScoreEntity === RiskScoreEntity.user - ? upgradeUserRiskScoreModule - : upgradeHostRiskScoreModule - ); - const [isModalVisible, setIsModalVisible] = useState(false); - const closeModal = useCallback(() => setIsModalVisible(false), []); - const showModal = useCallback(() => setIsModalVisible(true), []); - const upgradeRiskScore = useCallback(async () => { - closeModal(); - fetch({ - http, - notifications, - spaceId, - timerange, - refetch, - renderDashboardLink, - renderDocLink, - riskScoreEntity, - theme, - dashboard, - }); - }, [ - closeModal, - fetch, - http, - notifications, - spaceId, - timerange, - refetch, - renderDashboardLink, - renderDocLink, - riskScoreEntity, - theme, - dashboard, - ]); - - return ( - <> - - {title} - - {isModalVisible && ( - - } - /> - } - confirmButtonText={ - - } - buttonColor="danger" - defaultFocusedButton="confirm" - > - - - )} - - ); -}; - -export const RiskScoreUpgradeButton = React.memo(RiskScoreUpgradeButtonComponent); -RiskScoreUpgradeButton.displayName = 'RiskScoreUpgradeButton'; diff --git a/x-pack/plugins/security_solution/public/explore/containers/risk_score/all/index.tsx b/x-pack/plugins/security_solution/public/explore/containers/risk_score/all/index.tsx index 13a093090fb86..f49879ecf4754 100644 --- a/x-pack/plugins/security_solution/public/explore/containers/risk_score/all/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/containers/risk_score/all/index.tsx @@ -28,7 +28,7 @@ import { isIndexNotFoundError } from '../../../../common/utils/exceptions'; import type { inputsModel } from '../../../../common/store'; import { useSpaceId } from '../../../../common/hooks/use_space_id'; import { useSearchStrategy } from '../../../../common/containers/use_search_strategy'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; +import { useIsNewRiskScoreModuleInstalled } from '../../../../entity_analytics/api/hooks/use_risk_engine_status'; export interface RiskScoreState { data: @@ -84,11 +84,11 @@ export const useRiskScore = ): RiskScoreState => { const spaceId = useSpaceId(); - const isNewRiskScoreModuleAvailable = useIsExperimentalFeatureEnabled('riskScoringRoutesEnabled'); + const isNewRiskScoreModuleInstalled = useIsNewRiskScoreModuleInstalled(); const defaultIndex = spaceId ? riskEntity === RiskScoreEntity.host - ? getHostRiskIndex(spaceId, onlyLatest, isNewRiskScoreModuleAvailable) - : getUserRiskIndex(spaceId, onlyLatest, isNewRiskScoreModuleAvailable) + ? getHostRiskIndex(spaceId, onlyLatest, isNewRiskScoreModuleInstalled) + : getUserRiskIndex(spaceId, onlyLatest, isNewRiskScoreModuleInstalled) : undefined; const factoryQueryType = riskEntity === RiskScoreEntity.host ? RiskQueries.hostsRiskScore : RiskQueries.usersRiskScore; @@ -207,5 +207,7 @@ export const useRiskScore = (null); @@ -145,7 +145,7 @@ export const useAllHost = ({ direction, field: sortField, }, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, }; if (!deepEqual(prevRequest, myRequest)) { return myRequest; @@ -161,7 +161,7 @@ export const useAllHost = ({ limit, startDate, sortField, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, ]); useEffect(() => { diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/navigation/host_risk_score_tab_body.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/navigation/host_risk_score_tab_body.tsx index 055a02d9c072e..7139102bd35a5 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/navigation/host_risk_score_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/navigation/host_risk_score_tab_body.tsx @@ -95,10 +95,6 @@ export const HostRiskScoreQueryTabBody = ({ isDeprecated: isDeprecated && !loading, }; - if (riskScoreEngineStatus?.isUpdateAvailable) { - return ; - } - if (status.isDisabled || status.isDeprecated) { return ( @@ -123,21 +119,24 @@ export const HostRiskScoreQueryTabBody = ({ } return ( - + <> + {riskScoreEngineStatus?.isUpdateAvailable && } + + ); }; diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/navigation/all_users_query_tab_body.tsx b/x-pack/plugins/security_solution/public/explore/users/pages/navigation/all_users_query_tab_body.tsx index 47c9002e36a51..286a1b21c735b 100644 --- a/x-pack/plugins/security_solution/public/explore/users/pages/navigation/all_users_query_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/pages/navigation/all_users_query_tab_body.tsx @@ -19,7 +19,7 @@ import { generateTablePaginationOptions } from '../../../components/paginated_ta import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; import { usersSelectors } from '../../store'; import { useQueryToggle } from '../../../../common/containers/query_toggle'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; +import { useIsNewRiskScoreModuleInstalled } from '../../../../entity_analytics/api/hooks/use_risk_engine_status'; const UsersTableManage = manageQuery(UsersTable); @@ -43,7 +43,7 @@ export const AllUsersQueryTabBody = ({ const getUsersSelector = useMemo(() => usersSelectors.allUsersSelector(), []); const { activePage, limit, sort } = useDeepEqualSelector((state) => getUsersSelector(state)); - const isNewRiskScoreModuleAvailable = useIsExperimentalFeatureEnabled('riskScoringRoutesEnabled'); + const isNewRiskScoreModuleInstalled = useIsNewRiskScoreModuleInstalled(); const { loading, @@ -78,7 +78,7 @@ export const AllUsersQueryTabBody = ({ }, pagination: generateTablePaginationOptions(activePage, limit), sort, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, }); } }, [ @@ -91,7 +91,7 @@ export const AllUsersQueryTabBody = ({ activePage, limit, sort, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, ]); return ( diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/navigation/user_risk_score_tab_body.tsx b/x-pack/plugins/security_solution/public/explore/users/pages/navigation/user_risk_score_tab_body.tsx index c1652a49036c2..4097d673f3982 100644 --- a/x-pack/plugins/security_solution/public/explore/users/pages/navigation/user_risk_score_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/pages/navigation/user_risk_score_tab_body.tsx @@ -95,10 +95,6 @@ export const UserRiskScoreQueryTabBody = ({ isDeprecated: isDeprecated && !loading, }; - if (riskScoreEngineStatus?.isUpdateAvailable) { - return ; - } - if (status.isDisabled || status.isDeprecated) { return ( + <> + {riskScoreEngineStatus?.isUpdateAvailable && } + + ); }; diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx index 57536596e085e..332f5535a1304 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx @@ -35,7 +35,6 @@ import { useNavigateToAlertsPageWithFilters } from '../../../../common/hooks/use import { getRiskEntityTranslation } from './translations'; import { useKibana } from '../../../../common/lib/kibana'; import { useGlobalFilterQuery } from '../../../../common/hooks/use_global_filter_query'; -import { useRiskEngineStatus } from '../../../../entity_analytics/api/hooks/use_risk_engine_status'; const EntityAnalyticsRiskScoresComponent = ({ riskEntity }: { riskEntity: RiskScoreEntity }) => { const { deleteQuery, setQuery, from, to } = useGlobalTime(); @@ -126,8 +125,6 @@ const EntityAnalyticsRiskScoresComponent = ({ riskEntity }: { riskEntity: RiskSc includeAlertsCount: true, }); - const { data: riskScoreEngineStatus } = useRiskEngineStatus(); - useQueryInspector({ queryId: entity.tableQueryId, loading: isTableLoading, @@ -152,10 +149,6 @@ const EntityAnalyticsRiskScoresComponent = ({ riskEntity }: { riskEntity: RiskSc isDeprecated: isDeprecated && !isTableLoading, }; - if (riskScoreEngineStatus?.isUpdateAvailable) { - return null; - } - if (status.isDisabled || status.isDeprecated) { return ( { const isHostRiskScoreIndexExist = await services.scopedClusterClient.asCurrentUser.indices.exists( { - index: getHostRiskIndex(spaceId, true, isNewRiskScoreModuleAvailable), + index: getHostRiskIndex(spaceId, true, isNewRiskScoreModuleInstalled), } ); @@ -32,11 +32,11 @@ export const createHostRiskEnrichments: CreateRiskEnrichment = async ({ logger, events, spaceId, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, }) => { return createSingleFieldMatchEnrichment({ name: 'Host Risk', - index: [getHostRiskIndex(spaceId, true, isNewRiskScoreModuleAvailable)], + index: [getHostRiskIndex(spaceId, true, isNewRiskScoreModuleInstalled)], services, logger, events, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/enrichment_by_type/user_risk.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/enrichment_by_type/user_risk.ts index 9fdb5e85b391b..b0e8d87f3019f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/enrichment_by_type/user_risk.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/enrichment_by_type/user_risk.ts @@ -15,11 +15,11 @@ import { getFieldValue } from '../utils/events'; export const getIsUserRiskScoreAvailable: GetIsRiskScoreAvailable = async ({ services, spaceId, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, }) => { const isUserRiskScoreIndexExist = await services.scopedClusterClient.asCurrentUser.indices.exists( { - index: getUserRiskIndex(spaceId, true, isNewRiskScoreModuleAvailable), + index: getUserRiskIndex(spaceId, true, isNewRiskScoreModuleInstalled), } ); @@ -31,11 +31,11 @@ export const createUserRiskEnrichments: CreateRiskEnrichment = async ({ logger, events, spaceId, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, }) => { return createSingleFieldMatchEnrichment({ name: 'User Risk', - index: [getUserRiskIndex(spaceId, true, isNewRiskScoreModuleAvailable)], + index: [getUserRiskIndex(spaceId, true, isNewRiskScoreModuleInstalled)], services, logger, events, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/index.ts index 3f6015929e3ce..a27cc55801820 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/index.ts @@ -34,9 +34,18 @@ export const enrichEvents: EnrichEventsFunction = async ({ logger.debug('Alert enrichments started'); const isNewRiskScoreModuleAvailable = experimentalFeatures?.riskScoringRoutesEnabled ?? false; + let isNewRiskScoreModuleInstalled = false; + if (isNewRiskScoreModuleAvailable) { + isNewRiskScoreModuleInstalled = await getIsHostRiskScoreAvailable({ + spaceId, + services, + isNewRiskScoreModuleInstalled: true, + }); + } + const [isHostRiskScoreIndexExist, isUserRiskScoreIndexExist] = await Promise.all([ - getIsHostRiskScoreAvailable({ spaceId, services, isNewRiskScoreModuleAvailable }), - getIsUserRiskScoreAvailable({ spaceId, services, isNewRiskScoreModuleAvailable }), + getIsHostRiskScoreAvailable({ spaceId, services, isNewRiskScoreModuleInstalled }), + getIsUserRiskScoreAvailable({ spaceId, services, isNewRiskScoreModuleInstalled }), ]); if (isHostRiskScoreIndexExist) { @@ -46,7 +55,7 @@ export const enrichEvents: EnrichEventsFunction = async ({ logger, events, spaceId, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, }) ); } @@ -58,7 +67,7 @@ export const enrichEvents: EnrichEventsFunction = async ({ logger, events, spaceId, - isNewRiskScoreModuleAvailable, + isNewRiskScoreModuleInstalled, }) ); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/types.ts index 352cb4ffc18ae..73c703235edca 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/types.ts @@ -76,13 +76,13 @@ export type SearchEnrichments = (params: { export type GetIsRiskScoreAvailable = (params: { spaceId: string; services: RuleServices; - isNewRiskScoreModuleAvailable: boolean; + isNewRiskScoreModuleInstalled: boolean; }) => Promise; export type CreateRiskEnrichment = ( params: BasedEnrichParamters & { spaceId: string; - isNewRiskScoreModuleAvailable: boolean; + isNewRiskScoreModuleInstalled: boolean; } ) => Promise; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/__mocks__/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/__mocks__/index.ts index 3db8573a6a606..11868b86f2530 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/__mocks__/index.ts @@ -31,7 +31,7 @@ export const mockOptions: HostsRequestOptions = { pagination: { activePage: 0, cursorStart: 0, fakePossibleCount: 50, querySize: 10 }, timerange: { interval: '12h', from: '2020-09-03T09:15:21.415Z', to: '2020-09-04T09:15:21.415Z' }, sort: { direction: Direction.desc, field: HostsFields.lastSeen }, - isNewRiskScoreModuleAvailable: false, + isNewRiskScoreModuleInstalled: false, }; export const mockSearchStrategyResponse: IEsSearchResponse = { diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts index 0131f5417d0d5..f3cd1eb0cf100 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts @@ -72,7 +72,7 @@ export const allHosts: SecuritySolutionFactory = { hostNames, deps.spaceId, deps.esClient, - options.isNewRiskScoreModuleAvailable + options.isNewRiskScoreModuleInstalled ) : edges; @@ -95,13 +95,13 @@ async function enhanceEdges( hostNames: string[], spaceId: string, esClient: IScopedClusterClient, - isNewRiskScoreModuleAvailable: boolean + isNewRiskScoreModuleInstalled: boolean ): Promise { const hostRiskData = await getHostRiskData( esClient, spaceId, hostNames, - isNewRiskScoreModuleAvailable + isNewRiskScoreModuleInstalled ); const hostsRiskByHostName: Record | undefined = hostRiskData?.hits.hits.reduce( (acc, hit) => ({ @@ -126,12 +126,12 @@ export async function getHostRiskData( esClient: IScopedClusterClient, spaceId: string, hostNames: string[], - isNewRiskScoreModuleAvailable: boolean + isNewRiskScoreModuleInstalled: boolean ) { try { const hostRiskResponse = await esClient.asCurrentUser.search( buildRiskScoreQuery({ - defaultIndex: [getHostRiskIndex(spaceId, true, isNewRiskScoreModuleAvailable)], + defaultIndex: [getHostRiskIndex(spaceId, true, isNewRiskScoreModuleInstalled)], filterQuery: buildHostNamesFilter(hostNames), riskScoreEntity: RiskScoreEntity.host, factoryQueryType: RiskQueries.hostsRiskScore, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_hosts/__mocks__/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_hosts/__mocks__/index.ts index 979f80440d44e..6a9e3ae82aa05 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_hosts/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_hosts/__mocks__/index.ts @@ -21,7 +21,7 @@ export const mockOptions: RelatedHostsRequestOptions = { factoryQueryType: RelatedEntitiesQueries.relatedHosts, userName: 'user1', from: '2020-09-02T15:17:13.678Z', - isNewRiskScoreModuleAvailable: false, + isNewRiskScoreModuleInstalled: false, }; export const mockSearchStrategyResponse: IEsSearchResponse = { diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_hosts/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_hosts/index.ts index ee4787c83c912..19da422fbf3ae 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_hosts/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_hosts/index.ts @@ -61,7 +61,7 @@ export const usersRelatedHosts: SecuritySolutionFactory { const hostNames = relatedHosts.map((item) => item.host); const hostRiskData = await getHostRiskData( esClient, spaceId, hostNames, - isNewRiskScoreModuleAvailable + isNewRiskScoreModuleInstalled ); const hostsRiskByHostName: Record | undefined = hostRiskData?.hits.hits.reduce( diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_users/__mocks__/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_users/__mocks__/index.ts index c503928861472..a7c6d3501c0f0 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_users/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_users/__mocks__/index.ts @@ -21,7 +21,7 @@ export const mockOptions: RelatedUsersRequestOptions = { factoryQueryType: RelatedEntitiesQueries.relatedUsers, hostName: 'host1', from: '2020-09-02T15:17:13.678Z', - isNewRiskScoreModuleAvailable: false, + isNewRiskScoreModuleInstalled: false, }; export const mockSearchStrategyResponse: IEsSearchResponse = { diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_users/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_users/index.ts index abe95325ebce1..371083a01e42c 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_users/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/related_entities/related_users/index.ts @@ -60,7 +60,7 @@ export const hostsRelatedUsers: SecuritySolutionFactory { const userNames = relatedUsers.map((item) => item.user); const userRiskData = await getUserRiskData( esClient, spaceId, userNames, - isNewRiskScoreModuleAvailable + isNewRiskScoreModuleInstalled ); const usersRiskByUserName: Record | undefined = userRiskData?.hits.hits.reduce( diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/__mocks__/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/__mocks__/index.ts index 2670f2d5b9b65..0e5a7c88851dd 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/__mocks__/index.ts @@ -33,7 +33,7 @@ export const mockOptions: UsersRequestOptions = { querySize: 10, }, sort: { field: UsersFields.name, direction: Direction.asc }, - isNewRiskScoreModuleAvailable: false, + isNewRiskScoreModuleInstalled: false, }; export const mockSearchStrategyResponse: IEsSearchResponse = { diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts index 8f1836e8a05dc..a8eab4d4b92db 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts @@ -78,7 +78,7 @@ export const allUsers: SecuritySolutionFactory = { userNames, deps.spaceId, deps.esClient, - options.isNewRiskScoreModuleAvailable + options.isNewRiskScoreModuleInstalled ) : edges; @@ -101,13 +101,13 @@ async function enhanceEdges( userNames: string[], spaceId: string, esClient: IScopedClusterClient, - isNewRiskScoreModuleAvailable: boolean + isNewRiskScoreModuleInstalled: boolean ): Promise { const userRiskData = await getUserRiskData( esClient, spaceId, userNames, - isNewRiskScoreModuleAvailable + isNewRiskScoreModuleInstalled ); const usersRiskByUserName: Record | undefined = userRiskData?.hits.hits.reduce( @@ -132,12 +132,12 @@ export async function getUserRiskData( esClient: IScopedClusterClient, spaceId: string, userNames: string[], - isNewRiskScoreModuleAvailable: boolean + isNewRiskScoreModuleInstalled: boolean ) { try { const userRiskResponse = await esClient.asCurrentUser.search( buildRiskScoreQuery({ - defaultIndex: [getUserRiskIndex(spaceId, true, isNewRiskScoreModuleAvailable)], + defaultIndex: [getUserRiskIndex(spaceId, true, isNewRiskScoreModuleInstalled)], filterQuery: buildUserNamesFilter(userNames), riskScoreEntity: RiskScoreEntity.user, factoryQueryType: RiskQueries.usersRiskScore, diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 2391c36acc263..11872fd12e242 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -33621,9 +33621,6 @@ "xpack.securitySolution.riskScore.savedObjects.bulkDeleteFailureTitle": "Impossible de supprimer les objets enregistrés", "xpack.securitySolution.riskScore.technicalPreviewLabel": "Version d'évaluation technique", "xpack.securitySolution.riskScore.uninstall.errorMessageTitle": "Erreur de désinstallation", - "xpack.securitySolution.riskScore.upgradeConfirmation.cancel": "Conserver les données", - "xpack.securitySolution.riskScore.upgradeConfirmation.confirm": "Effacer et mettre à niveau", - "xpack.securitySolution.riskScore.upgradeConfirmation.content": "La mise à niveau supprimera les scores de risque existants de votre environnement. Vous pouvez conserver les données de risque existantes avant de mettre à niveau le package Score de risque. Voulez-vous effectuer la mise à niveau ?", "xpack.securitySolution.riskScore.userRiskScoresEnabledTitle": "Scores de risque de l'utilisateur activés", "xpack.securitySolution.riskScore.usersDashboardRestartTooltip": "Le calcul du score de risque pourra prendre un certain temps à se lancer. Cependant, en appuyant sur Redémarrer, vous pouvez le forcer à s'exécuter immédiatement.", "xpack.securitySolution.riskScore.usersDashboardWarningPanelBody": "Nous n’avons pas trouvé de données de score de risque de l’utilisateur. Vérifiez si vous avez des filtres globaux dans la barre de recherche KQL globale. Si vous venez d’activer le module de risque de l’utilisateur, le moteur de risque peut mettre une heure à générer les données de score de risque de l’utilisateur et à les afficher dans ce panneau.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index ebd523dace815..a48765228124e 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -33620,9 +33620,6 @@ "xpack.securitySolution.riskScore.savedObjects.bulkDeleteFailureTitle": "保存されたオブジェクトを削除できませんでした", "xpack.securitySolution.riskScore.technicalPreviewLabel": "テクニカルプレビュー", "xpack.securitySolution.riskScore.uninstall.errorMessageTitle": "アンインストールエラー", - "xpack.securitySolution.riskScore.upgradeConfirmation.cancel": "データの保持", - "xpack.securitySolution.riskScore.upgradeConfirmation.confirm": "データを消去してアップグレード", - "xpack.securitySolution.riskScore.upgradeConfirmation.content": "アップグレードを実行すると、既存のリスクスコアが環境から削除されます。既存のリスクデータを保持するには、リスクスコアパッケージをアップグレードしてください。アップグレードしますか?", "xpack.securitySolution.riskScore.userRiskScoresEnabledTitle": "ユーザーリスクスコア有効", "xpack.securitySolution.riskScore.usersDashboardRestartTooltip": "リスクスコア計算の実行には少し時間がかかる場合があります。ただし、再起動を押すと、すぐに強制的に実行できます。", "xpack.securitySolution.riskScore.usersDashboardWarningPanelBody": "ユーザーリスクスコアデータが見つかりません。グローバルKQL検索バーにグローバルフィルターがあるかどうかを確認してください。ユーザーリスクモジュールを有効にしたばかりの場合は、リスクエンジンがユーザーリスクスコアデータを生成し、このパネルに表示するまでに1時間かかることがあります。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 96adbe87e50d9..e2019067a5ea9 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -33616,9 +33616,6 @@ "xpack.securitySolution.riskScore.savedObjects.bulkDeleteFailureTitle": "无法删除已保存对象", "xpack.securitySolution.riskScore.technicalPreviewLabel": "技术预览", "xpack.securitySolution.riskScore.uninstall.errorMessageTitle": "卸载错误", - "xpack.securitySolution.riskScore.upgradeConfirmation.cancel": "保留数据", - "xpack.securitySolution.riskScore.upgradeConfirmation.confirm": "擦除数据并升级", - "xpack.securitySolution.riskScore.upgradeConfirmation.content": "升级会从您的环境中删除现有风险分数。您可以先保留现有风险数据,然后再升级风险分数软件包。是否升级?", "xpack.securitySolution.riskScore.userRiskScoresEnabledTitle": "已启用用户风险分数", "xpack.securitySolution.riskScore.usersDashboardRestartTooltip": "风险分数计算可能需要一段时间运行。但是,通过按“重新启动”,您可以立即强制运行该计算。", "xpack.securitySolution.riskScore.usersDashboardWarningPanelBody": "找不到任何用户风险分数数据。检查全局 KQL 搜索栏中是否具有任何全局筛选。如果刚刚启用了用户风险模块,风险引擎可能需要一小时才能生成并在此面板中显示用户风险分数数据。", diff --git a/x-pack/test/functional/apps/observability_log_explorer/dataset_selector.ts b/x-pack/test/functional/apps/observability_log_explorer/dataset_selector.ts index d7d63384eec29..b630cfea6ba4d 100644 --- a/x-pack/test/functional/apps/observability_log_explorer/dataset_selector.ts +++ b/x-pack/test/functional/apps/observability_log_explorer/dataset_selector.ts @@ -30,7 +30,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const noIntegrationsTitle = 'No integrations found'; const noUncategorizedTitle = 'No data streams found'; - describe('Dataset Selector', () => { + // Failing: See https://github.com/elastic/kibana/issues/167621 + describe.skip('Dataset Selector', () => { before(async () => { await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); await PageObjects.observabilityLogExplorer.removeInstalledPackages(); diff --git a/x-pack/test/security_solution_cypress/config.ts b/x-pack/test/security_solution_cypress/config.ts index 21259c2d289e2..ece8ee522917c 100644 --- a/x-pack/test/security_solution_cypress/config.ts +++ b/x-pack/test/security_solution_cypress/config.ts @@ -48,6 +48,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { 'alertDetailsPageEnabled', 'chartEmbeddablesEnabled', 'discoverInTimeline', + 'riskScoringRoutesEnabled', + 'riskScoringPersistence', ])}`, // mock cloud to enable the guided onboarding tour in e2e tests '--xpack.cloud.id=test', diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/enrichments.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/enrichments.cy.ts index 38a16a8225445..4432a1c6c90a7 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/enrichments.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/enrichments.cy.ts @@ -30,11 +30,18 @@ import { login } from '../../tasks/login'; import { visitWithTimeRange } from '../../tasks/navigation'; import { ALERTS_URL } from '../../urls/navigation'; +import { deleteRiskEngineConfiguration } from '../../tasks/api_calls/risk_engine'; +import { enableRiskEngine } from '../../tasks/entity_analytics'; + +const CURRENT_HOST_RISK_CLASIFICATION = 'Current host risk classification'; +const ORIGINAL_HOST_RISK_CLASIFICATION = 'Original host risk classification'; // TODO: https://github.com/elastic/kibana/issues/161539 describe('Enrichment', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { before(() => { cleanKibana(); + cy.task('esArchiverUnload', 'risk_scores_new'); + cy.task('esArchiverUnload', 'risk_scores_new_updated'); cy.task('esArchiverLoad', { archiveName: 'risk_users' }); }); @@ -43,44 +50,91 @@ describe('Enrichment', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, }); describe('Custom query rule', () => { - beforeEach(() => { - disableExpandableFlyout(); - cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); - deleteAlertsAndRules(); - createRule(getNewRule({ rule_id: 'rule1' })); - login(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); - }); + describe('from legacy risk scores', () => { + beforeEach(() => { + disableExpandableFlyout(); + cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); + deleteAlertsAndRules(); + createRule(getNewRule({ rule_id: 'rule1' })); + login(); + deleteRiskEngineConfiguration(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + }); + + afterEach(() => { + cy.task('esArchiverUnload', 'risk_hosts'); + cy.task('esArchiverUnload', 'risk_hosts_updated'); + }); - afterEach(() => { - cy.task('esArchiverUnload', 'risk_hosts'); - cy.task('esArchiverUnload', 'risk_hosts_updated'); + it('Should has enrichment fields from legacy risk', function () { + cy.get(ALERTS_COUNT) + .invoke('text') + .should('match', /^[1-9].+$/); // Any number of alerts + cy.get(HOST_RISK_HEADER_COLIMN).contains('host.risk.calculated_level'); + cy.get(USER_RISK_HEADER_COLIMN).contains('user.risk.calculated_level'); + scrollAlertTableColumnIntoView(HOST_RISK_COLUMN); + cy.get(HOST_RISK_COLUMN).contains('Low'); + scrollAlertTableColumnIntoView(USER_RISK_COLUMN); + cy.get(USER_RISK_COLUMN).contains('Low'); + scrollAlertTableColumnIntoView(ACTION_COLUMN); + expandFirstAlert(); + cy.get(ENRICHED_DATA_ROW).contains('Low'); + cy.get(ENRICHED_DATA_ROW).contains(CURRENT_HOST_RISK_CLASIFICATION); + cy.get(ENRICHED_DATA_ROW).contains('Critical').should('not.exist'); + cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_CLASIFICATION).should('not.exist'); + + closeAlertFlyout(); + cy.task('esArchiverUnload', 'risk_hosts'); + cy.task('esArchiverLoad', { archiveName: 'risk_hosts_updated' }); + expandFirstAlert(); + cy.get(ENRICHED_DATA_ROW).contains('Critical'); + cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_CLASIFICATION); + }); }); - it('Should has enrichment fields', function () { - cy.get(ALERTS_COUNT) - .invoke('text') - .should('match', /^[1-9].+$/); // Any number of alerts - cy.get(HOST_RISK_HEADER_COLIMN).contains('host.risk.calculated_level'); - cy.get(USER_RISK_HEADER_COLIMN).contains('user.risk.calculated_level'); - scrollAlertTableColumnIntoView(HOST_RISK_COLUMN); - cy.get(HOST_RISK_COLUMN).contains('Low'); - scrollAlertTableColumnIntoView(USER_RISK_COLUMN); - cy.get(USER_RISK_COLUMN).contains('Low'); - scrollAlertTableColumnIntoView(ACTION_COLUMN); - expandFirstAlert(); - cy.get(ENRICHED_DATA_ROW).contains('Low'); - cy.get(ENRICHED_DATA_ROW).contains('Current host risk classification'); - cy.get(ENRICHED_DATA_ROW).contains('Critical').should('not.exist'); - cy.get(ENRICHED_DATA_ROW).contains('Original host risk classification').should('not.exist'); + describe('from new risk scores', () => { + beforeEach(() => { + disableExpandableFlyout(); + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); + deleteAlertsAndRules(); + createRule(getNewRule({ rule_id: 'rule1' })); + login(); + enableRiskEngine(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + }); + + afterEach(() => { + cy.task('esArchiverUnload', 'risk_scores_new'); + cy.task('esArchiverUnload', 'risk_scores_new_updated'); + deleteRiskEngineConfiguration(); + }); + + it('Should has enrichment fields from legacy risk', function () { + cy.get(ALERTS_COUNT) + .invoke('text') + .should('match', /^[1-9].+$/); // Any number of alerts + cy.get(HOST_RISK_HEADER_COLIMN).contains('host.risk.calculated_level'); + cy.get(USER_RISK_HEADER_COLIMN).contains('user.risk.calculated_level'); + scrollAlertTableColumnIntoView(HOST_RISK_COLUMN); + cy.get(HOST_RISK_COLUMN).contains('Critical'); + scrollAlertTableColumnIntoView(USER_RISK_COLUMN); + cy.get(USER_RISK_COLUMN).contains('High'); + scrollAlertTableColumnIntoView(ACTION_COLUMN); + expandFirstAlert(); + cy.get(ENRICHED_DATA_ROW).contains('Critical'); + cy.get(ENRICHED_DATA_ROW).contains(CURRENT_HOST_RISK_CLASIFICATION); + cy.get(ENRICHED_DATA_ROW).contains('Low').should('not.exist'); + cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_CLASIFICATION).should('not.exist'); - closeAlertFlyout(); - cy.task('esArchiverUnload', 'risk_hosts'); - cy.task('esArchiverLoad', { archiveName: 'risk_hosts_updated' }); - expandFirstAlert(); - cy.get(ENRICHED_DATA_ROW).contains('Critical'); - cy.get(ENRICHED_DATA_ROW).contains('Original host risk classification'); + closeAlertFlyout(); + cy.task('esArchiverUnload', 'risk_scores_new'); + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new_updated' }); + expandFirstAlert(); + cy.get(ENRICHED_DATA_ROW).contains('Low'); + cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_CLASIFICATION); + }); }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts index 272a548bee666..86168a7798948 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts @@ -26,7 +26,7 @@ import { ENTITY_ANALYTICS_MANAGEMENT_URL } from '../../urls/navigation'; import { getNewRule } from '../../objects/rule'; import { createRule } from '../../tasks/api_calls/rules'; import { - deleteConfiguration, + deleteRiskEngineConfiguration, interceptRiskPreviewError, interceptRiskPreviewSuccess, interceptRiskInitError, @@ -35,8 +35,7 @@ import { updateDateRangeInLocalDatePickers } from '../../tasks/date_picker'; import { fillLocalSearchBar, submitLocalSearch } from '../../tasks/search_bar'; import { riskEngineStatusChange, - updateRiskEngine, - updateRiskEngineConfirm, + upgradeRiskEngine, previewErrorButtonClick, } from '../../tasks/entity_analytics'; @@ -44,9 +43,6 @@ import { describe( 'Entity analytics management page', { - env: { - ftrConfig: { enableExperimental: ['riskScoringRoutesEnabled', 'riskScoringPersistence'] }, - }, tags: ['@ess', '@serverless', '@brokenInServerless'], }, () => { @@ -58,7 +54,7 @@ describe( beforeEach(() => { login(); createRule(getNewRule({ query: 'user.name:* or host.name:*', risk_score: 70 })); - deleteConfiguration(); + deleteRiskEngineConfiguration(); visit(ENTITY_ANALYTICS_MANAGEMENT_URL); }); @@ -147,10 +143,7 @@ describe( cy.get(RISK_SCORE_STATUS).should('not.exist'); - updateRiskEngine(); - updateRiskEngineConfirm(); - - cy.get(RISK_SCORE_STATUS).should('have.text', 'On'); + upgradeRiskEngine(); deleteRiskScore({ riskScoreEntity: RiskScoreEntity.host, spaceId: 'default' }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/enable_risk_score.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/enable_risk_score.cy.ts deleted file mode 100644 index 18dce59372d0e..0000000000000 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/enable_risk_score.cy.ts +++ /dev/null @@ -1,125 +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 { getNewRule } from '../../../objects/rule'; -import { - ENABLE_HOST_RISK_SCORE_BUTTON, - ENABLE_USER_RISK_SCORE_BUTTON, - RISK_SCORE_DASHBOARDS_INSTALLATION_SUCCESS_TOAST, - RISK_SCORE_INSTALLATION_SUCCESS_TOAST, -} from '../../../screens/entity_analytics'; -import { - deleteRiskScore, - interceptInstallRiskScoreModule, - waitForInstallRiskScoreModule, -} from '../../../tasks/api_calls/risk_scores'; -import { findSavedObjects } from '../../../tasks/api_calls/risk_scores/saved_objects'; -import { createRule } from '../../../tasks/api_calls/rules'; -import { cleanKibana } from '../../../tasks/common'; -import { login } from '../../../tasks/login'; -import { visitWithTimeRange } from '../../../tasks/navigation'; -import { clickEnableRiskScore } from '../../../tasks/risk_scores'; -import { RiskScoreEntity } from '../../../tasks/risk_scores/common'; -import { - getRiskScoreLatestTransformId, - getRiskScorePivotTransformId, - getTransformState, -} from '../../../tasks/risk_scores/transforms'; -import { ENTITY_ANALYTICS_URL } from '../../../urls/navigation'; - -const spaceId = 'default'; - -// FLAKY: https://github.com/elastic/kibana/issues/165644 -describe('Enable risk scores', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { - before(() => { - cleanKibana(); - login(); - createRule(getNewRule({ rule_id: 'rule1' })); - }); - - beforeEach(() => { - login(); - deleteRiskScore({ riskScoreEntity: RiskScoreEntity.host, spaceId }); - deleteRiskScore({ riskScoreEntity: RiskScoreEntity.user, spaceId }); - visitWithTimeRange(ENTITY_ANALYTICS_URL); - }); - - afterEach(() => { - deleteRiskScore({ riskScoreEntity: RiskScoreEntity.host, spaceId }); - deleteRiskScore({ riskScoreEntity: RiskScoreEntity.user, spaceId }); - }); - - it('shows enable host risk button', () => { - cy.get(ENABLE_HOST_RISK_SCORE_BUTTON).should('exist'); - }); - - it('should install host risk score successfully', { tags: ['@brokenInServerless'] }, () => { - interceptInstallRiskScoreModule(); - clickEnableRiskScore(RiskScoreEntity.host); - waitForInstallRiskScoreModule(); - - cy.get(ENABLE_HOST_RISK_SCORE_BUTTON).should('be.disabled'); - - cy.get(RISK_SCORE_INSTALLATION_SUCCESS_TOAST(RiskScoreEntity.host)).should('exist'); - cy.get(RISK_SCORE_DASHBOARDS_INSTALLATION_SUCCESS_TOAST(RiskScoreEntity.host)).should('exist'); - cy.get(ENABLE_HOST_RISK_SCORE_BUTTON).should('not.exist'); - getTransformState(getRiskScorePivotTransformId(RiskScoreEntity.host, spaceId)).then((res) => { - expect(res.status).to.eq(200); - expect(res.body.transforms[0].id).to.eq( - getRiskScorePivotTransformId(RiskScoreEntity.host, spaceId) - ); - expect(res.body.transforms[0].state).to.eq('started'); - }); - getTransformState(getRiskScoreLatestTransformId(RiskScoreEntity.host, spaceId)).then((res) => { - expect(res.status).to.eq(200); - expect(res.body.transforms[0].id).to.eq( - getRiskScoreLatestTransformId(RiskScoreEntity.host, spaceId) - ); - expect(res.body.transforms[0].state).to.eq('started'); - }); - findSavedObjects(RiskScoreEntity.host, spaceId).then((res) => { - expect(res.status).to.eq(200); - expect(res.body.saved_objects.length).to.eq(11); - }); - }); - - it('shows enable user risk button', () => { - cy.get(ENABLE_USER_RISK_SCORE_BUTTON).should('exist'); - }); - - it('should install user risk score successfully', { tags: ['@brokenInServerless'] }, () => { - interceptInstallRiskScoreModule(); - clickEnableRiskScore(RiskScoreEntity.user); - waitForInstallRiskScoreModule(); - - cy.get(ENABLE_USER_RISK_SCORE_BUTTON).should('be.disabled'); - - cy.get(RISK_SCORE_INSTALLATION_SUCCESS_TOAST(RiskScoreEntity.user)).should('exist'); - - cy.get(RISK_SCORE_DASHBOARDS_INSTALLATION_SUCCESS_TOAST(RiskScoreEntity.user)).should('exist'); - cy.get(ENABLE_USER_RISK_SCORE_BUTTON).should('not.exist'); - getTransformState(getRiskScorePivotTransformId(RiskScoreEntity.user, spaceId)).then((res) => { - expect(res.status).to.eq(200); - expect(res.body.transforms[0].id).to.eq( - getRiskScorePivotTransformId(RiskScoreEntity.user, spaceId) - ); - expect(res.body.transforms[0].state).to.eq('started'); - }); - getTransformState(getRiskScoreLatestTransformId(RiskScoreEntity.user, spaceId)).then((res) => { - expect(res.status).to.eq(200); - expect(res.body.transforms[0].id).to.eq( - getRiskScoreLatestTransformId(RiskScoreEntity.user, spaceId) - ); - expect(res.body.transforms[0].state).to.eq('started'); - }); - - findSavedObjects(RiskScoreEntity.user, spaceId).then((res) => { - expect(res.status).to.eq(200); - expect(res.body.saved_objects.length).to.eq(11); - }); - }); -}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/enable_risk_score_redirect.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/enable_risk_score_redirect.cy.ts new file mode 100644 index 0000000000000..a684968bf8b33 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/enable_risk_score_redirect.cy.ts @@ -0,0 +1,53 @@ +/* + * 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 { + ENABLE_HOST_RISK_SCORE_BUTTON, + ENABLE_USER_RISK_SCORE_BUTTON, +} from '../../../screens/entity_analytics'; + +import { cleanKibana } from '../../../tasks/common'; +import { login } from '../../../tasks/login'; +import { visit } from '../../../tasks/navigation'; +import { clickEnableRiskScore } from '../../../tasks/risk_scores'; +import { RiskScoreEntity } from '../../../tasks/risk_scores/common'; + +import { ENTITY_ANALYTICS_URL } from '../../../urls/navigation'; +import { PAGE_TITLE } from '../../../screens/entity_analytics_management'; + +// FLAKY: https://github.com/elastic/kibana/issues/165644 +describe( + 'Enable risk scores from dashboard', + { tags: ['@ess', '@serverless', '@brokenInServerless'] }, + () => { + before(() => { + cleanKibana(); + login(); + }); + + beforeEach(() => { + login(); + visit(ENTITY_ANALYTICS_URL); + }); + + it('host risk enable button should redirect to entity management page', () => { + cy.get(ENABLE_HOST_RISK_SCORE_BUTTON).should('exist'); + + clickEnableRiskScore(RiskScoreEntity.host); + + cy.get(PAGE_TITLE).should('have.text', 'Entity Risk Score'); + }); + + it('user risk enable button should redirect to entity management page', () => { + cy.get(ENABLE_USER_RISK_SCORE_BUTTON).should('exist'); + + clickEnableRiskScore(RiskScoreEntity.user); + + cy.get(PAGE_TITLE).should('have.text', 'Entity Risk Score'); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts index 77557f3b3b311..39d8e1476a6cd 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts @@ -20,8 +20,6 @@ import { HOSTS_DONUT_CHART, HOSTS_TABLE_ROWS, HOST_RISK_SCORE_NO_DATA_DETECTED, - UPGRADE_HOST_RISK_SCORE_BUTTON, - UPGRADE_USER_RISK_SCORE_BUTTON, USERS_DONUT_CHART, USERS_TABLE, USERS_TABLE_ROWS, @@ -35,7 +33,13 @@ import { import { openRiskTableFilterAndSelectTheLowOption, removeLowFilterAndCloseRiskTableFilter, + openRiskTableFilterAndSelectTheCriticalOption, + removeCriticalFilterAndCloseRiskTableFilter, } from '../../../tasks/host_risk'; +import { + removeLowFilterAndCloseUserRiskTableFilter, + openUserRiskTableFilterAndSelectTheLowOption, +} from '../../../tasks/user_risk'; import { createRule } from '../../../tasks/api_calls/rules'; import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; import { getNewRule } from '../../../objects/rule'; @@ -49,6 +53,8 @@ import { navigateToNextPage, waitForAnomaliesToBeLoaded, } from '../../../tasks/entity_analytics'; +import { deleteRiskEngineConfiguration } from '../../../tasks/api_calls/risk_engine'; +import { enableRiskEngine } from '../../../tasks/entity_analytics'; const TEST_USER_ALERTS = 2; const TEST_USER_NAME = 'test'; @@ -59,246 +65,476 @@ const END_DATE = 'Jan 19, 2019 @ 20:33:29.186'; describe('Entity Analytics Dashboard', { tags: ['@ess', '@brokenInServerless'] }, () => { before(() => { cleanKibana(); + login(); + deleteRiskEngineConfiguration(); }); - describe('Without data', () => { - beforeEach(() => { - login(); - visitWithTimeRange(ENTITY_ANALYTICS_URL); - }); + describe('legcay risk score', () => { + describe('Without data', () => { + beforeEach(() => { + login(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); - it('shows enable host risk button', () => { - cy.get(ENABLE_HOST_RISK_SCORE_BUTTON).should('be.visible'); - }); + it('shows enable host risk button', () => { + cy.get(ENABLE_HOST_RISK_SCORE_BUTTON).should('be.visible'); + }); - it('shows enable user risk button', () => { - cy.get(ENABLE_USER_RISK_SCORE_BUTTON).should('be.visible'); + it('shows enable user risk button', () => { + cy.get(ENABLE_USER_RISK_SCORE_BUTTON).should('be.visible'); + }); }); - }); - describe('Risk Score enabled but still no data', () => { - before(() => { - cy.task('esArchiverLoad', { archiveName: 'risk_hosts_no_data' }); - cy.task('esArchiverLoad', { archiveName: 'risk_users_no_data' }); - }); + describe('Risk Score enabled but still no data', () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'risk_hosts_no_data' }); + cy.task('esArchiverLoad', { archiveName: 'risk_users_no_data' }); + }); - beforeEach(() => { - login(); - visitWithTimeRange(ENTITY_ANALYTICS_URL); - }); + beforeEach(() => { + login(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); - after(() => { - cy.task('esArchiverUnload', 'risk_hosts_no_data'); - cy.task('esArchiverUnload', 'risk_users_no_data'); - }); + after(() => { + cy.task('esArchiverUnload', 'risk_hosts_no_data'); + cy.task('esArchiverUnload', 'risk_users_no_data'); + }); - it('shows no data detected prompt for host risk score module', () => { - cy.get(HOST_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); - }); + it('shows no data detected prompt for host risk score module', () => { + cy.get(HOST_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + }); - it('shows no data detected prompt for user risk score module', () => { - cy.get(USER_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + it('shows no data detected prompt for user risk score module', () => { + cy.get(USER_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + }); }); - }); - describe('With Legacy data', () => { - before(() => { - cy.task('esArchiverLoad', { archiveName: 'risk_hosts_legacy_data' }); - cy.task('esArchiverLoad', { archiveName: 'risk_users_legacy_data' }); - }); + describe('With Legacy data', () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'risk_hosts_legacy_data' }); + cy.task('esArchiverLoad', { archiveName: 'risk_users_legacy_data' }); + }); - beforeEach(() => { - login(); - visitWithTimeRange(ENTITY_ANALYTICS_URL); - }); + beforeEach(() => { + login(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); - after(() => { - cy.task('esArchiverUnload', 'risk_hosts_legacy_data'); - cy.task('esArchiverUnload', 'risk_users_legacy_data'); - }); + after(() => { + cy.task('esArchiverUnload', 'risk_hosts_legacy_data'); + cy.task('esArchiverUnload', 'risk_users_legacy_data'); + }); - it('shows upgrade host risk button', () => { - cy.get(UPGRADE_HOST_RISK_SCORE_BUTTON).should('be.visible'); - }); + it('shows enable host risk button', () => { + cy.get(ENABLE_HOST_RISK_SCORE_BUTTON).should('be.visible'); + }); - it('shows upgrade user risk button', () => { - cy.get(UPGRADE_USER_RISK_SCORE_BUTTON).should('be.visible'); + it('shows enable user risk button', () => { + cy.get(ENABLE_USER_RISK_SCORE_BUTTON).should('be.visible'); + }); }); - }); - describe('With host risk data', () => { - before(() => { - cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); - }); + describe('With host risk data', () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); + }); - beforeEach(() => { - login(); - visitWithTimeRange(ENTITY_ANALYTICS_URL); - }); + beforeEach(() => { + login(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); - after(() => { - cy.task('esArchiverUnload', 'risk_hosts'); - }); + after(() => { + cy.task('esArchiverUnload', 'risk_hosts'); + }); - it('renders donut chart', () => { - cy.get(HOSTS_DONUT_CHART).should('include.text', '6Total'); - }); + it('renders donut chart', () => { + cy.get(HOSTS_DONUT_CHART).should('include.text', '6Total'); + }); - it('renders table', () => { - cy.get(HOSTS_TABLE).should('be.visible'); - cy.get(HOSTS_TABLE_ROWS).should('have.length', 5); - }); + it('renders table', () => { + cy.get(HOSTS_TABLE).should('be.visible'); + cy.get(HOSTS_TABLE_ROWS).should('have.length', 5); + }); - it('renders alerts column', () => { - cy.get(HOSTS_TABLE_ALERT_CELL).should('have.length', 5); - }); + it('renders alerts column', () => { + cy.get(HOSTS_TABLE_ALERT_CELL).should('have.length', 5); + }); - it('filters by risk classification', () => { - openRiskTableFilterAndSelectTheLowOption(); + it('filters by risk classification', () => { + openRiskTableFilterAndSelectTheLowOption(); - cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); - cy.get(HOSTS_TABLE_ROWS).should('have.length', 1); + cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); + cy.get(HOSTS_TABLE_ROWS).should('have.length', 1); - removeLowFilterAndCloseRiskTableFilter(); - }); + removeLowFilterAndCloseRiskTableFilter(); + }); + + it('filters the host risk table with KQL search bar query', () => { + kqlSearch(`host.name : ${SIEM_KIBANA_HOST_NAME}{enter}`); - it('filters the host risk table with KQL search bar query', () => { - kqlSearch(`host.name : ${SIEM_KIBANA_HOST_NAME}{enter}`); + cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); + cy.get(HOSTS_TABLE_ROWS).should('have.length', 1); - cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); - cy.get(HOSTS_TABLE_ROWS).should('have.length', 1); + clearSearchBar(); + }); - clearSearchBar(); + describe('With alerts data', () => { + before(() => { + createRule(getNewRule()); + }); + + beforeEach(() => { + login(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); + + after(() => { + deleteAlertsAndRules(); + }); + + it('populates alerts column', () => { + cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', SIEM_KIBANA_HOST_ALERTS); + }); + + it('filters the alerts count with time range', () => { + setEndDate(END_DATE); + updateDates(); + + cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', 0); + + // CLEAR DATES + setEndDateNow(); + updateDates(); + }); + + it('opens alerts page when alerts count is clicked', () => { + clickOnFirstHostsAlerts(); + cy.url().should('include', ALERTS_URL); + + cy.get(OPTION_LIST_LABELS).eq(0).should('include.text', 'Status'); + cy.get(OPTION_LIST_VALUES(0)).should('include.text', 'open'); + cy.get(OPTION_LIST_LABELS).eq(1).should('include.text', 'Host'); + cy.get(OPTION_LIST_VALUES(1)).should('include.text', SIEM_KIBANA_HOST_NAME); + }); + }); }); - describe('With alerts data', () => { + describe('With user risk data', () => { before(() => { - createRule(getNewRule()); + cy.task('esArchiverLoad', { archiveName: 'risk_users' }); }); beforeEach(() => { login(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); visitWithTimeRange(ENTITY_ANALYTICS_URL); }); after(() => { - deleteAlertsAndRules(); + cy.task('esArchiverUnload', 'risk_users'); + }); + + it('renders donut chart', () => { + cy.get(USERS_DONUT_CHART).should('include.text', '7Total'); + }); + + it('renders table', () => { + cy.get(USERS_TABLE).should('be.visible'); + cy.get(USERS_TABLE_ROWS).should('have.length', 5); }); - it('populates alerts column', () => { - cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', SIEM_KIBANA_HOST_ALERTS); + it('renders alerts column', () => { + cy.get(USERS_TABLE_ALERT_CELL).should('have.length', 5); }); - it('filters the alerts count with time range', () => { - setEndDate(END_DATE); - updateDates(); + it('filters by risk classification', () => { + openRiskTableFilterAndSelectTheLowOption(); - cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', 0); + cy.get(USERS_DONUT_CHART).should('include.text', '2Total'); + cy.get(USERS_TABLE_ROWS).should('have.length', 2); - // CLEAR DATES - setEndDateNow(); - updateDates(); + removeLowFilterAndCloseRiskTableFilter(); }); - it('opens alerts page when alerts count is clicked', () => { - clickOnFirstHostsAlerts(); - cy.url().should('include', ALERTS_URL); + it('filters the host risk table with KQL search bar query', () => { + kqlSearch(`user.name : ${TEST_USER_NAME}{enter}`); + + cy.get(USERS_DONUT_CHART).should('include.text', '1Total'); + cy.get(USERS_TABLE_ROWS).should('have.length', 1); - cy.get(OPTION_LIST_LABELS).eq(0).should('include.text', 'Status'); - cy.get(OPTION_LIST_VALUES(0)).should('include.text', 'open'); - cy.get(OPTION_LIST_LABELS).eq(1).should('include.text', 'Host'); - cy.get(OPTION_LIST_VALUES(1)).should('include.text', SIEM_KIBANA_HOST_NAME); + clearSearchBar(); + }); + + describe('With alerts data', () => { + before(() => { + createRule(getNewRule()); + }); + + beforeEach(() => { + login(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); + + after(() => { + deleteAlertsAndRules(); + }); + + it('populates alerts column', () => { + cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', TEST_USER_ALERTS); + }); + + it('filters the alerts count with time range', () => { + setEndDate(END_DATE); + updateDates(); + + cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', 0); + + // CLEAR DATES + setEndDateNow(); + updateDates(); + }); + + it('opens alerts page when alerts count is clicked', () => { + clickOnFirstUsersAlerts(); + + cy.url().should('include', ALERTS_URL); + + cy.get(OPTION_LIST_LABELS).eq(0).should('include.text', 'Status'); + cy.get(OPTION_LIST_VALUES(0)).should('include.text', 'open'); + cy.get(OPTION_LIST_LABELS).eq(1).should('include.text', 'User'); + cy.get(OPTION_LIST_VALUES(1)).should('include.text', TEST_USER_NAME); + }); }); }); }); - describe('With user risk data', () => { - before(() => { - cy.task('esArchiverLoad', { archiveName: 'risk_users' }); - }); + describe('new risk score', () => { + describe('Without data', () => { + beforeEach(() => { + login(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); - beforeEach(() => { - login(); - visitWithTimeRange(ENTITY_ANALYTICS_URL); - }); + it('shows enable host and user risk button', () => { + cy.get(ENABLE_HOST_RISK_SCORE_BUTTON).should('be.visible'); - after(() => { - cy.task('esArchiverUnload', 'risk_users'); + cy.get(ENABLE_USER_RISK_SCORE_BUTTON).should('be.visible'); + }); }); - it('renders donut chart', () => { - cy.get(USERS_DONUT_CHART).should('include.text', '7Total'); - }); + describe('Risk Score enabled but still no data', () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new_no_data' }); + }); - it('renders table', () => { - cy.get(USERS_TABLE).should('be.visible'); - cy.get(USERS_TABLE_ROWS).should('have.length', 5); - }); + beforeEach(() => { + login(); + enableRiskEngine(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); + + afterEach(() => { + deleteRiskEngineConfiguration(); + }); + + after(() => { + cy.task('esArchiverUnload', 'risk_scores_new_no_data'); + }); - it('renders alerts column', () => { - cy.get(USERS_TABLE_ALERT_CELL).should('have.length', 5); + it('shows no data detected prompt for host and user risk scores', () => { + cy.get(HOST_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + cy.get(USER_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + }); }); - it('filters by risk classification', () => { - openRiskTableFilterAndSelectTheLowOption(); + describe('With host risk data', () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); + login(); + enableRiskEngine(); + }); + + beforeEach(() => { + login(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); - cy.get(USERS_DONUT_CHART).should('include.text', '2Total'); - cy.get(USERS_TABLE_ROWS).should('have.length', 2); + after(() => { + cy.task('esArchiverUnload', 'risk_scores_new'); + deleteRiskEngineConfiguration(); + }); - removeLowFilterAndCloseRiskTableFilter(); - }); + it('renders donut chart', () => { + cy.get(HOSTS_DONUT_CHART).should('include.text', '6Total'); + }); + + it('renders table', () => { + cy.get(HOSTS_TABLE).should('be.visible'); + cy.get(HOSTS_TABLE_ROWS).should('have.length', 5); + }); - it('filters the host risk table with KQL search bar query', () => { - kqlSearch(`user.name : ${TEST_USER_NAME}{enter}`); + it('renders alerts column', () => { + cy.get(HOSTS_TABLE_ALERT_CELL).should('have.length', 5); + }); - cy.get(USERS_DONUT_CHART).should('include.text', '1Total'); - cy.get(USERS_TABLE_ROWS).should('have.length', 1); + it('filters by risk classification', () => { + cy.get(HOSTS_DONUT_CHART).should('include.text', '6Total'); + openRiskTableFilterAndSelectTheCriticalOption(); + + cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); + cy.get(HOSTS_TABLE_ROWS).should('have.length', 1); + + removeCriticalFilterAndCloseRiskTableFilter(); + }); + + it('filters the host risk table with KQL search bar query', () => { + kqlSearch(`host.name : ${SIEM_KIBANA_HOST_NAME}{enter}`); + + cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); + cy.get(HOSTS_TABLE_ROWS).should('have.length', 1); + + clearSearchBar(); + }); + + describe('With alerts data', () => { + before(() => { + createRule(getNewRule()); + }); - clearSearchBar(); + beforeEach(() => { + login(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); + + after(() => { + deleteAlertsAndRules(); + }); + + it('populates alerts column', () => { + cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', SIEM_KIBANA_HOST_ALERTS); + }); + + it('filters the alerts count with time range', () => { + setEndDate(END_DATE); + updateDates(); + + cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', 0); + + // CLEAR DATES + setEndDateNow(); + updateDates(); + }); + + it('opens alerts page when alerts count is clicked', () => { + clickOnFirstHostsAlerts(); + cy.url().should('include', ALERTS_URL); + + cy.get(OPTION_LIST_LABELS).eq(0).should('include.text', 'Status'); + cy.get(OPTION_LIST_VALUES(0)).should('include.text', 'open'); + cy.get(OPTION_LIST_LABELS).eq(1).should('include.text', 'Host'); + cy.get(OPTION_LIST_VALUES(1)).should('include.text', SIEM_KIBANA_HOST_NAME); + }); + }); }); - describe('With alerts data', () => { + describe('With user risk data', () => { before(() => { - createRule(getNewRule()); + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); + login(); + enableRiskEngine(); }); beforeEach(() => { login(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); visitWithTimeRange(ENTITY_ANALYTICS_URL); }); after(() => { - deleteAlertsAndRules(); + cy.task('esArchiverUnload', 'risk_scores_new'); + deleteRiskEngineConfiguration(); + }); + + it('renders donut chart', () => { + cy.get(USERS_DONUT_CHART).should('include.text', '7Total'); + }); + + it('renders table', () => { + cy.get(USERS_TABLE).should('be.visible'); + cy.get(USERS_TABLE_ROWS).should('have.length', 5); }); - it('populates alerts column', () => { - cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', TEST_USER_ALERTS); + it('renders alerts column', () => { + cy.get(USERS_TABLE_ALERT_CELL).should('have.length', 5); }); - it('filters the alerts count with time range', () => { - setEndDate(END_DATE); - updateDates(); + it('filters by risk classification', () => { + cy.get(USERS_DONUT_CHART).should('include.text', '7Total'); - cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', 0); + openUserRiskTableFilterAndSelectTheLowOption(1); - // CLEAR DATES - setEndDateNow(); - updateDates(); + cy.get(USERS_DONUT_CHART).should('include.text', '1Total'); + cy.get(USERS_TABLE_ROWS).should('have.length', 1); + + removeLowFilterAndCloseUserRiskTableFilter(); + }); + + it('filters the host risk table with KQL search bar query', () => { + kqlSearch(`user.name : ${TEST_USER_NAME}{enter}`); + + cy.get(USERS_DONUT_CHART).should('include.text', '1Total'); + cy.get(USERS_TABLE_ROWS).should('have.length', 1); + + clearSearchBar(); }); - it('opens alerts page when alerts count is clicked', () => { - clickOnFirstUsersAlerts(); + describe('With alerts data', () => { + before(() => { + createRule(getNewRule()); + }); + + beforeEach(() => { + login(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); + + after(() => { + deleteAlertsAndRules(); + }); + + it('populates alerts column', () => { + cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', TEST_USER_ALERTS); + }); + + it('filters the alerts count with time range', () => { + setEndDate(END_DATE); + updateDates(); + + cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', 0); + + // CLEAR DATES + setEndDateNow(); + updateDates(); + }); + + it('opens alerts page when alerts count is clicked', () => { + clickOnFirstUsersAlerts(); - cy.url().should('include', ALERTS_URL); + cy.url().should('include', ALERTS_URL); - cy.get(OPTION_LIST_LABELS).eq(0).should('include.text', 'Status'); - cy.get(OPTION_LIST_VALUES(0)).should('include.text', 'open'); - cy.get(OPTION_LIST_LABELS).eq(1).should('include.text', 'User'); - cy.get(OPTION_LIST_VALUES(1)).should('include.text', TEST_USER_NAME); + cy.get(OPTION_LIST_LABELS).eq(0).should('include.text', 'Status'); + cy.get(OPTION_LIST_VALUES(0)).should('include.text', 'open'); + cy.get(OPTION_LIST_LABELS).eq(1).should('include.text', 'User'); + cy.get(OPTION_LIST_VALUES(1)).should('include.text', TEST_USER_NAME); + }); }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts index c67d12bf2ad9a..e815e9eaa6cb4 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts @@ -7,35 +7,32 @@ import { getNewRule } from '../../../objects/rule'; import { - RISK_SCORE_INSTALLATION_SUCCESS_TOAST, - UPGRADE_HOST_RISK_SCORE_BUTTON, - UPGRADE_USER_RISK_SCORE_BUTTON, - UPGRADE_CANCELLATION_BUTTON, - UPGRADE_CONFIRMATION_MODAL, - RISK_SCORE_DASHBOARDS_INSTALLATION_SUCCESS_TOAST, + UPGRADE_RISK_SCORE_BUTTON, + USERS_TABLE, + HOSTS_TABLE_ROWS, + HOSTS_TABLE, + USERS_TABLE_ROWS, + HOST_RISK_SCORE_NO_DATA_DETECTED, + USER_RISK_SCORE_NO_DATA_DETECTED, } from '../../../screens/entity_analytics'; +import { PAGE_TITLE } from '../../../screens/entity_analytics_management'; import { deleteRiskScore, installLegacyRiskScoreModule, + installRiskScoreModule, } from '../../../tasks/api_calls/risk_scores'; -import { findSavedObjects } from '../../../tasks/api_calls/risk_scores/saved_objects'; +import { clickUpgradeRiskScore } from '../../../tasks/risk_scores'; + import { createRule } from '../../../tasks/api_calls/rules'; import { cleanKibana } from '../../../tasks/common'; import { login } from '../../../tasks/login'; import { visitWithTimeRange } from '../../../tasks/navigation'; -import { - clickUpgradeRiskScore, - clickUpgradeRiskScoreConfirmed, - interceptUpgradeRiskScoreModule, - waitForUpgradeRiskScoreModule, -} from '../../../tasks/risk_scores'; + import { RiskScoreEntity } from '../../../tasks/risk_scores/common'; -import { - getRiskScoreLatestTransformId, - getRiskScorePivotTransformId, - getTransformState, -} from '../../../tasks/risk_scores/transforms'; + import { ENTITY_ANALYTICS_URL } from '../../../urls/navigation'; +import { upgradeRiskEngine } from '../../../tasks/entity_analytics'; +import { deleteRiskEngineConfiguration } from '../../../tasks/api_calls/risk_engine'; const spaceId = 'default'; @@ -44,152 +41,69 @@ describe('Upgrade risk scores', { tags: ['@ess', '@serverless', '@brokenInServer before(() => { cleanKibana(); login(); + deleteRiskEngineConfiguration(); createRule(getNewRule({ rule_id: 'rule1' })); }); - beforeEach(() => { - login(); - deleteRiskScore({ riskScoreEntity: RiskScoreEntity.host, spaceId }); - deleteRiskScore({ riskScoreEntity: RiskScoreEntity.user, spaceId }); - installLegacyRiskScoreModule(RiskScoreEntity.host, spaceId); - installLegacyRiskScoreModule(RiskScoreEntity.user, spaceId); - visitWithTimeRange(ENTITY_ANALYTICS_URL); - }); + describe('show upgrade risk button', () => { + beforeEach(() => { + login(); + deleteRiskScore({ riskScoreEntity: RiskScoreEntity.host, spaceId }); + deleteRiskScore({ riskScoreEntity: RiskScoreEntity.user, spaceId }); + installLegacyRiskScoreModule(RiskScoreEntity.host, spaceId); + installLegacyRiskScoreModule(RiskScoreEntity.user, spaceId); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); - it('shows upgrade risk button for host and user', () => { - cy.get(UPGRADE_HOST_RISK_SCORE_BUTTON).should('be.visible'); - cy.get(UPGRADE_USER_RISK_SCORE_BUTTON).should('be.visible'); - }); + afterEach(() => { + deleteRiskScore({ riskScoreEntity: RiskScoreEntity.host, spaceId }); + deleteRiskScore({ riskScoreEntity: RiskScoreEntity.user, spaceId }); + cy.task('esArchiverUnload', 'risk_hosts'); + cy.task('esArchiverUnload', 'risk_users'); + }); - it( - 'should show a confirmation modal for upgrading host risk score and display a link to host risk score Elastic doc', - { tags: ['@brokenInServerless'] }, - () => { - clickUpgradeRiskScore(RiskScoreEntity.host); - cy.get(UPGRADE_CONFIRMATION_MODAL(RiskScoreEntity.host)).should('exist'); - - cy.get(UPGRADE_CANCELLATION_BUTTON) - .get(`${UPGRADE_CONFIRMATION_MODAL(RiskScoreEntity.host)} a`) - .then((link) => { - expect(link.prop('href')).to.eql( - `https://www.elastic.co/guide/en/security/current/${RiskScoreEntity.host}-risk-score.html` - ); - }); - } - ); - - it( - 'should show a confirmation modal for upgrading user risk score and display a link to user risk score Elastic doc', - { tags: ['@brokenInServerless'] }, - () => { - clickUpgradeRiskScore(RiskScoreEntity.user); - cy.get(UPGRADE_CONFIRMATION_MODAL(RiskScoreEntity.user)).should('exist'); - - cy.get(UPGRADE_CANCELLATION_BUTTON) - .get(`${UPGRADE_CONFIRMATION_MODAL(RiskScoreEntity.user)} a`) - .then((link) => { - expect(link.prop('href')).to.eql( - `https://www.elastic.co/guide/en/security/current/${RiskScoreEntity.user}-risk-score.html` - ); - }); - } - ); -}); + it('shows upgrade panel', () => { + cy.get(UPGRADE_RISK_SCORE_BUTTON).should('be.visible'); + + clickUpgradeRiskScore(); + + cy.get(PAGE_TITLE).should('have.text', 'Entity Risk Score'); + }); + }); -const versions: Array<'8.3' | '8.4'> = ['8.3', '8.4']; -versions.forEach((version) => - describe(`handles version ${version} upgrades`, () => { + describe('upgrade risk engine', () => { before(() => { - cleanKibana(); + cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); + cy.task('esArchiverLoad', { archiveName: 'risk_users' }); }); beforeEach(() => { login(); - createRule(getNewRule({ rule_id: 'rule1' })); - deleteRiskScore({ riskScoreEntity: RiskScoreEntity.host, spaceId }); - deleteRiskScore({ riskScoreEntity: RiskScoreEntity.user, spaceId }); - installLegacyRiskScoreModule(RiskScoreEntity.host, spaceId, version); - installLegacyRiskScoreModule(RiskScoreEntity.user, spaceId, version); + installRiskScoreModule(); visitWithTimeRange(ENTITY_ANALYTICS_URL); }); - afterEach(() => { + after(() => { + cy.task('esArchiverUnload', 'risk_hosts'); + cy.task('esArchiverUnload', 'risk_users'); deleteRiskScore({ riskScoreEntity: RiskScoreEntity.host, spaceId }); deleteRiskScore({ riskScoreEntity: RiskScoreEntity.user, spaceId }); + deleteRiskEngineConfiguration(); }); - it('should upgrade host risk score successfully', () => { - clickUpgradeRiskScore(RiskScoreEntity.host); - - interceptUpgradeRiskScoreModule(RiskScoreEntity.host, version); - - clickUpgradeRiskScoreConfirmed(); - waitForUpgradeRiskScoreModule(); - - cy.get(UPGRADE_HOST_RISK_SCORE_BUTTON).should('be.disabled'); - - cy.get(RISK_SCORE_INSTALLATION_SUCCESS_TOAST(RiskScoreEntity.host)).should('exist'); - cy.get(RISK_SCORE_DASHBOARDS_INSTALLATION_SUCCESS_TOAST(RiskScoreEntity.host)).should( - 'exist' - ); - - cy.get(UPGRADE_HOST_RISK_SCORE_BUTTON).should('not.exist'); - getTransformState(getRiskScorePivotTransformId(RiskScoreEntity.host, spaceId)).then((res) => { - expect(res.status).to.eq(200); - expect(res.body.transforms[0].id).to.eq( - getRiskScorePivotTransformId(RiskScoreEntity.host, spaceId) - ); - expect(res.body.transforms[0].state).to.eq('started'); - }); - getTransformState(getRiskScoreLatestTransformId(RiskScoreEntity.host, spaceId)).then( - (res) => { - expect(res.status).to.eq(200); - expect(res.body.transforms[0].id).to.eq( - getRiskScoreLatestTransformId(RiskScoreEntity.host, spaceId) - ); - expect(res.body.transforms[0].state).to.eq('started'); - } - ); - findSavedObjects(RiskScoreEntity.host, spaceId).then((res) => { - expect(res.status).to.eq(200); - expect(res.body.saved_objects.length).to.eq(11); - }); - }); + it('show old risk score data before upgrade, and hide after', () => { + cy.get(HOSTS_TABLE).should('be.visible'); + cy.get(HOSTS_TABLE_ROWS).should('have.length', 5); + + cy.get(USERS_TABLE).should('be.visible'); + cy.get(USERS_TABLE_ROWS).should('have.length', 5); + + upgradeRiskEngine(); - it('should upgrade user risk score successfully', () => { - clickUpgradeRiskScore(RiskScoreEntity.user); - interceptUpgradeRiskScoreModule(RiskScoreEntity.user); - clickUpgradeRiskScoreConfirmed(); - waitForUpgradeRiskScoreModule(); - cy.get(UPGRADE_USER_RISK_SCORE_BUTTON).should('be.disabled'); - - cy.get(RISK_SCORE_INSTALLATION_SUCCESS_TOAST(RiskScoreEntity.user)).should('exist'); - cy.get(RISK_SCORE_DASHBOARDS_INSTALLATION_SUCCESS_TOAST(RiskScoreEntity.user)).should( - 'exist' - ); - - cy.get(UPGRADE_USER_RISK_SCORE_BUTTON).should('not.exist'); - getTransformState(getRiskScorePivotTransformId(RiskScoreEntity.user, spaceId)).then((res) => { - expect(res.status).to.eq(200); - expect(res.body.transforms[0].id).to.eq( - getRiskScorePivotTransformId(RiskScoreEntity.user, spaceId) - ); - expect(res.body.transforms[0].state).to.eq('started'); - }); - getTransformState(getRiskScoreLatestTransformId(RiskScoreEntity.user, spaceId)).then( - (res) => { - expect(res.status).to.eq(200); - expect(res.body.transforms[0].id).to.eq( - getRiskScoreLatestTransformId(RiskScoreEntity.user, spaceId) - ); - expect(res.body.transforms[0].state).to.eq('started'); - } - ); - - findSavedObjects(RiskScoreEntity.user, spaceId).then((res) => { - expect(res.status).to.eq(200); - expect(res.body.saved_objects.length).to.eq(11); - }); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + + cy.get(HOST_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + cy.get(USER_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); }); - }) -); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/host_details/risk_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/host_details/risk_tab.cy.ts index 5eb5c172f0517..2ef24ae0df1ee 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/host_details/risk_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/host_details/risk_tab.cy.ts @@ -10,43 +10,88 @@ import { visitHostDetailsPage } from '../../../tasks/navigation'; import { cleanKibana, waitForTableToLoad } from '../../../tasks/common'; import { TABLE_CELL, TABLE_ROWS } from '../../../screens/alerts_details'; +import { deleteRiskEngineConfiguration } from '../../../tasks/api_calls/risk_engine'; +import { openRiskInformationFlyout, enableRiskEngine } from '../../../tasks/entity_analytics'; +import { ALERTS_COUNT, ALERT_GRID_CELL } from '../../../screens/alerts'; +import { RISK_INFORMATION_FLYOUT_HEADER } from '../../../screens/entity_analytics'; +import { navigateToHostRiskDetailTab } from '../../../tasks/host_risk'; describe('risk tab', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { - before(() => { - cleanKibana(); - // illegal_argument_exception: unknown setting [index.lifecycle.rollover_alias] - cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); - }); + describe('with legacy risk score', () => { + before(() => { + cleanKibana(); + // illegal_argument_exception: unknown setting [index.lifecycle.rollover_alias] + cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); + }); - beforeEach(() => { - login(); - }); + beforeEach(() => { + login(); + deleteRiskEngineConfiguration(); + }); - after(() => { - cy.task('esArchiverUnload', 'risk_hosts'); - }); + after(() => { + cy.task('esArchiverUnload', 'risk_hosts'); + }); + + it('renders risk tab', () => { + visitHostDetailsPage('siem-kibana'); + navigateToHostRiskDetailTab(); + waitForTableToLoad(); + + cy.get('[data-test-subj="topRiskScoreContributors"]') + .find(TABLE_ROWS) + .within(() => { + cy.get(TABLE_CELL).contains('Unusual Linux Username'); + }); + }); + + it('shows risk information overlay when button is clicked', () => { + visitHostDetailsPage('siem-kibana'); + navigateToHostRiskDetailTab(); + waitForTableToLoad(); - it('renders risk tab', () => { - visitHostDetailsPage('siem-kibana'); - cy.get('[data-test-subj="navigation-hostRisk"]').click(); - waitForTableToLoad(); + openRiskInformationFlyout(); - cy.get('[data-test-subj="topRiskScoreContributors"]') - .find(TABLE_ROWS) - .within(() => { - cy.get(TABLE_CELL).contains('Unusual Linux Username'); - }); + cy.get(RISK_INFORMATION_FLYOUT_HEADER).contains('How is host risk calculated?'); + }); }); - it('shows risk information overlay when button is clicked', () => { - visitHostDetailsPage('siem-kibana'); - cy.get('[data-test-subj="navigation-hostRisk"]').click(); - waitForTableToLoad(); + describe('with new risk score', () => { + before(() => { + cleanKibana(); + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); + cy.task('esArchiverLoad', { archiveName: 'query_alert' }); + login(); + enableRiskEngine(); + }); + + beforeEach(() => { + login(); + }); + + after(() => { + cy.task('esArchiverUnload', 'risk_scores_new'); + cy.task('esArchiverUnload', 'query_alert'); + deleteRiskEngineConfiguration(); + }); + + it('renders risk tab', () => { + visitHostDetailsPage('Host-fwarau82er'); + navigateToHostRiskDetailTab(); + waitForTableToLoad(); + + cy.get(ALERTS_COUNT).should('have.text', '1 alert'); + cy.get(ALERT_GRID_CELL).contains('Endpoint Security'); + }); + + it('shows risk information overlay when button is clicked', () => { + visitHostDetailsPage('siem-kibana'); + navigateToHostRiskDetailTab(); + waitForTableToLoad(); - cy.get('[data-test-subj="open-risk-information-flyout-trigger"]').click(); + openRiskInformationFlyout(); - cy.get('[data-test-subj="open-risk-information-flyout"] .euiFlyoutHeader').contains( - 'How is host risk calculated?' - ); + cy.get(RISK_INFORMATION_FLYOUT_HEADER).contains('How is host risk calculated?'); + }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts index 0c76cdc804997..695f261c599d0 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts @@ -18,53 +18,114 @@ import { HOST_BY_RISK_TABLE_NEXT_PAGE_BUTTON, } from '../../../screens/hosts/host_risk'; import { login } from '../../../tasks/login'; -import { visit } from '../../../tasks/navigation'; +import { visitWithTimeRange } from '../../../tasks/navigation'; import { hostsUrl } from '../../../urls/navigation'; import { clearSearchBar, kqlSearch } from '../../../tasks/security_header'; +import { deleteRiskEngineConfiguration } from '../../../tasks/api_calls/risk_engine'; +import { enableRiskEngine } from '../../../tasks/entity_analytics'; // Tracked by https://github.com/elastic/security-team/issues/7696 -describe.skip('risk tab', { tags: ['@ess', '@brokenInServerless'] }, () => { - before(() => { - cleanKibana(); - cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); - }); +describe('risk tab', { tags: ['@ess', '@brokenInServerless'] }, () => { + describe('with legacy risk score', () => { + before(() => { + cleanKibana(); + login(); + deleteRiskEngineConfiguration(); + cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); + }); - beforeEach(() => { - login(); - visit(hostsUrl('allHosts')); - navigateToHostRiskDetailTab(); - }); + beforeEach(() => { + login(); + visitWithTimeRange(hostsUrl('allHosts')); + // by some reason after navigate to host risk, page is sometimes is reload or go to all host tab + // this fix wait until we fave host in all host table, and then we go to risk tab + cy.contains('siem-kibana'); + navigateToHostRiskDetailTab(); + }); - after(() => { - cy.task('esArchiverUnload', 'risk_hosts'); - }); + after(() => { + cy.task('esArchiverUnload', 'risk_hosts'); + }); - it('renders the table', () => { - kqlSearch('host.name: "siem-kibana" {enter}'); - cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('have.text', 'siem-kibana'); - cy.get(HOST_BY_RISK_TABLE_CELL).eq(4).should('have.text', '21'); - cy.get(HOST_BY_RISK_TABLE_CELL).eq(5).should('have.text', 'Low'); - clearSearchBar(); - }); + it('renders the table', () => { + kqlSearch('host.name: "siem-kibana" {enter}'); + cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('have.text', 'siem-kibana'); + cy.get(HOST_BY_RISK_TABLE_CELL).eq(4).should('have.text', '21'); + cy.get(HOST_BY_RISK_TABLE_CELL).eq(5).should('have.text', 'Low'); + clearSearchBar(); + }); - it.skip('filters the table', () => { - openRiskTableFilterAndSelectTheCriticalOption(); + it.skip('filters the table', () => { + openRiskTableFilterAndSelectTheCriticalOption(); - cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('not.have.text', 'siem-kibana'); + cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('not.have.text', 'siem-kibana'); - removeCriticalFilterAndCloseRiskTableFilter(); - }); + removeCriticalFilterAndCloseRiskTableFilter(); + }); + + // Flaky + it.skip('should be able to change items count per page', () => { + selectFiveItemsPerPageOption(); - // Flaky - it.skip('should be able to change items count per page', () => { - selectFiveItemsPerPageOption(); + cy.get(HOST_BY_RISK_TABLE_HOSTNAME_CELL).should('have.length', 5); + }); - cy.get(HOST_BY_RISK_TABLE_HOSTNAME_CELL).should('have.length', 5); + it('should not allow page change when page is empty', () => { + kqlSearch('host.name: "nonexistent_host" {enter}'); + cy.get(HOST_BY_RISK_TABLE_NEXT_PAGE_BUTTON).should(`not.exist`); + clearSearchBar(); + }); }); - it('should not allow page change when page is empty', () => { - kqlSearch('host.name: "nonexistent_host" {enter}'); - cy.get(HOST_BY_RISK_TABLE_NEXT_PAGE_BUTTON).should(`not.exist`); - clearSearchBar(); + describe('with new risk score', () => { + before(() => { + cleanKibana(); + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); + login(); + enableRiskEngine(); + }); + + beforeEach(() => { + login(); + visitWithTimeRange(hostsUrl('allHosts')); + // by some reason after navigate to host risk, page is sometimes is reload or go to all host tab + // this fix wait until we fave host in all host table, and then we go to risk tab + cy.contains('siem-kibana'); + navigateToHostRiskDetailTab(); + }); + + after(() => { + cy.task('esArchiverUnload', 'risk_scores_new'); + deleteRiskEngineConfiguration(); + }); + + it('renders the table', () => { + kqlSearch('host.name: "siem-kibana" {enter}'); + cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('have.text', 'siem-kibana'); + cy.get(HOST_BY_RISK_TABLE_CELL).eq(4).should('have.text', '90'); + cy.get(HOST_BY_RISK_TABLE_CELL).eq(5).should('have.text', 'Critical'); + clearSearchBar(); + }); + + it.skip('filters the table', () => { + openRiskTableFilterAndSelectTheCriticalOption(); + + cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('not.have.text', 'siem-kibana'); + + removeCriticalFilterAndCloseRiskTableFilter(); + }); + + // Flaky + it.skip('should be able to change items count per page', () => { + selectFiveItemsPerPageOption(); + + cy.get(HOST_BY_RISK_TABLE_HOSTNAME_CELL).should('have.length', 5); + }); + + it('should not allow page change when page is empty', () => { + kqlSearch('host.name: "nonexistent_host" {enter}'); + cy.get(HOST_BY_RISK_TABLE_NEXT_PAGE_BUTTON).should(`not.exist`); + clearSearchBar(); + }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts index 41a0bf4fe0fff..a1bdff9a35072 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts @@ -12,27 +12,58 @@ import { hostsUrl } from '../../../urls/navigation'; import { cleanKibana } from '../../../tasks/common'; import { TABLE_CELL } from '../../../screens/alerts_details'; import { kqlSearch } from '../../../tasks/security_header'; +import { deleteRiskEngineConfiguration } from '../../../tasks/api_calls/risk_engine'; +import { enableRiskEngine } from '../../../tasks/entity_analytics'; describe('All hosts table', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { - before(() => { - cleanKibana(); - // illegal_argument_exception: unknown setting [index.lifecycle.name] - cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); - }); + describe('with legacy risk score', () => { + before(() => { + cleanKibana(); + // illegal_argument_exception: unknown setting [index.lifecycle.name] + cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); + }); - beforeEach(() => { - login(); - }); + beforeEach(() => { + login(); + deleteRiskEngineConfiguration(); + }); + + after(() => { + cy.task('esArchiverUnload', 'risk_hosts'); + }); + + it('it renders risk column', () => { + visitWithTimeRange(hostsUrl('allHosts')); + kqlSearch('host.name: "siem-kibana" {enter}'); - after(() => { - cy.task('esArchiverUnload', 'risk_hosts'); + cy.get('[data-test-subj="tableHeaderCell_node.risk_4"]').should('exist'); + cy.get(`${TABLE_CELL} .euiTableCellContent`).eq(4).should('have.text', 'Low'); + }); }); - it('it renders risk column', () => { - visitWithTimeRange(hostsUrl('allHosts')); - kqlSearch('host.name: "siem-kibana" {enter}'); + describe('with new risk score', () => { + before(() => { + cleanKibana(); + // illegal_argument_exception: unknown setting [index.lifecycle.name] + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); + }); + + beforeEach(() => { + login(); + enableRiskEngine(); + }); + + after(() => { + cy.task('esArchiverUnload', 'risk_scores_new'); + deleteRiskEngineConfiguration(); + }); + + it('it renders risk column', () => { + visitWithTimeRange(hostsUrl('allHosts')); + kqlSearch('host.name: "siem-kibana" {enter}'); - cy.get('[data-test-subj="tableHeaderCell_node.risk_4"]').should('exist'); - cy.get(`${TABLE_CELL} .euiTableCellContent`).eq(4).should('have.text', 'Low'); + cy.get('[data-test-subj="tableHeaderCell_node.risk_4"]').should('exist'); + cy.get(`${TABLE_CELL} .euiTableCellContent`).eq(4).should('have.text', 'Critical'); + }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics.ts b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics.ts index f41ae2a175f05..dccef9c6cfccd 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics.ts @@ -13,6 +13,8 @@ export const UPGRADE_HOST_RISK_SCORE_BUTTON = '[data-test-subj="host-risk-score- export const UPGRADE_USER_RISK_SCORE_BUTTON = '[data-test-subj="user-risk-score-upgrade"]'; +export const UPGRADE_RISK_SCORE_BUTTON = '[data-test-subj="update-risk-score-button"]'; + export const HOST_RISK_SCORE_NO_DATA_DETECTED = '[data-test-subj="host-risk-score-no-data-detected"]'; @@ -68,3 +70,9 @@ export const USERS_TABLE_ALERT_CELL = export const HOSTS_TABLE_ALERT_CELL = '[data-test-subj="entity_analytics_hosts"] [data-test-subj="risk-score-alerts"]'; + +export const OPEN_RISK_INFORMATION_FLYOUT_BUTTON = + '[data-test-subj="open-risk-information-flyout-trigger"]'; + +export const RISK_INFORMATION_FLYOUT_HEADER = + '[data-test-subj="open-risk-information-flyout"] .euiFlyoutHeader'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts index 00bac740fe3c5..e7b67db8399b7 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts @@ -29,7 +29,7 @@ export const RISK_SCORE_UPDATE_CANCEL = '[data-test-subj="risk-score-update-canc export const RISK_SCORE_UPDATE_CONFIRM = '[data-test-subj="risk-score-update-confirm"]'; -export const RISK_SCORE_UDATE_BUTTON = '[data-test-subj="risk-score-update-button"]'; +export const RISK_SCORE_UPDATE_BUTTON = '[data-test-subj="risk-score-update-button"]'; export const RISK_SCORE_STATUS = '[data-test-subj="risk-score-status"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/users/user_risk_score.ts b/x-pack/test/security_solution_cypress/cypress/screens/users/user_risk_score.ts index 816334d7fc197..f16c6e0d6b3b1 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/users/user_risk_score.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/users/user_risk_score.ts @@ -7,3 +7,6 @@ export const RISK_SCORE_TAB = '[data-test-subj="navigation-userRisk"]'; export const RISK_SCORE_TAB_CONTENT = '[data-test-subj="table-userRisk-loading-false"]'; + +export const USER_BY_RISK_TABLE_FILTER = '[data-test-subj="risk-filter-button"]'; +export const USER_BY_RISK_TABLE_FILTER_LOW = '[data-test-subj="risk-filter-item-Low"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_engine.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_engine.ts index 7305bef6f0b88..a8b15aa5e010b 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_engine.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_engine.ts @@ -5,7 +5,7 @@ * 2.0. */ -export const deleteConfiguration = () => { +export const deleteRiskEngineConfiguration = () => { cy.request({ method: 'GET', url: `/api/saved_objects/_find?type=risk-engine-configuration`, diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts index 2d8582198c4e0..31a2ffb2afb5a 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts @@ -10,11 +10,13 @@ import { ANOMALIES_TABLE_ROWS, ANOMALIES_TABLE_ENABLE_JOB_BUTTON, ANOMALIES_TABLE_NEXT_PAGE_BUTTON, + OPEN_RISK_INFORMATION_FLYOUT_BUTTON, } from '../screens/entity_analytics'; -import { ENTITY_ANALYTICS_URL } from '../urls/navigation'; +import { RISK_SCORE_STATUS } from '../screens/entity_analytics_management'; +import { ENTITY_ANALYTICS_URL, ENTITY_ANALYTICS_MANAGEMENT_URL } from '../urls/navigation'; import { RISK_SCORE_UPDATE_CONFIRM, - RISK_SCORE_UDATE_BUTTON, + RISK_SCORE_UPDATE_BUTTON, RISK_SCORE_SWITCH, RISK_PREVIEW_ERROR_BUTTON, } from '../screens/entity_analytics_management'; @@ -42,8 +44,14 @@ export const riskEngineStatusChange = () => { cy.get(RISK_SCORE_SWITCH).click(); }; +export const enableRiskEngine = () => { + cy.visit(ENTITY_ANALYTICS_MANAGEMENT_URL); + cy.get(RISK_SCORE_STATUS).should('have.text', 'Off'); + riskEngineStatusChange(); +}; + export const updateRiskEngine = () => { - cy.get(RISK_SCORE_UDATE_BUTTON).click(); + cy.get(RISK_SCORE_UPDATE_BUTTON).click(); }; export const updateRiskEngineConfirm = () => { @@ -53,3 +61,12 @@ export const updateRiskEngineConfirm = () => { export const previewErrorButtonClick = () => { cy.get(RISK_PREVIEW_ERROR_BUTTON).click(); }; + +export const openRiskInformationFlyout = () => cy.get(OPEN_RISK_INFORMATION_FLYOUT_BUTTON).click(); + +export const upgradeRiskEngine = () => { + visitWithTimeRange(ENTITY_ANALYTICS_MANAGEMENT_URL); + updateRiskEngine(); + updateRiskEngineConfirm(); + cy.get(RISK_SCORE_STATUS).should('have.text', 'On'); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/host_risk.ts b/x-pack/test/security_solution_cypress/cypress/tasks/host_risk.ts index 2bb3c97db95bc..ebf95a1d6aeca 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/host_risk.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/host_risk.ts @@ -21,7 +21,7 @@ export const navigateToHostRiskDetailTab = () => { }; export const openRiskTableFilterAndSelectTheCriticalOption = () => { - cy.get(HOST_BY_RISK_TABLE_FILTER).click(); + cy.get(HOST_BY_RISK_TABLE_FILTER).first().click(); cy.get(HOST_BY_RISK_TABLE_FILTER_CRITICAL).click(); }; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/index.ts b/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/index.ts index d48a23c4f7471..6634eab16ec79 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/index.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/index.ts @@ -10,8 +10,7 @@ import { ENABLE_USER_RISK_SCORE_BUTTON, HOSTS_TABLE_ALERT_CELL, UPGRADE_CONFIRMATION_BUTTON, - UPGRADE_HOST_RISK_SCORE_BUTTON, - UPGRADE_USER_RISK_SCORE_BUTTON, + UPGRADE_RISK_SCORE_BUTTON, USERS_TABLE_ALERT_CELL, } from '../../screens/entity_analytics'; import { @@ -68,13 +67,8 @@ export const clickEnableRiskScore = (riskScoreEntity: RiskScoreEntity) => { cy.get(button).click(); }; -export const clickUpgradeRiskScore = (riskScoreEntity: RiskScoreEntity) => { - const button = - riskScoreEntity === RiskScoreEntity.user - ? UPGRADE_USER_RISK_SCORE_BUTTON - : UPGRADE_HOST_RISK_SCORE_BUTTON; - - cy.get(button).click(); +export const clickUpgradeRiskScore = () => { + cy.get(UPGRADE_RISK_SCORE_BUTTON).click(); }; export const clickUpgradeRiskScoreConfirmed = () => { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/user_risk.ts b/x-pack/test/security_solution_cypress/cypress/tasks/user_risk.ts new file mode 100644 index 0000000000000..dd1150b36faff --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/tasks/user_risk.ts @@ -0,0 +1,21 @@ +/* + * 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 { + USER_BY_RISK_TABLE_FILTER, + USER_BY_RISK_TABLE_FILTER_LOW, +} from '../screens/users/user_risk_score'; + +export const openUserRiskTableFilterAndSelectTheLowOption = (eq = 0) => { + cy.get(USER_BY_RISK_TABLE_FILTER).eq(eq).click(); + cy.get(USER_BY_RISK_TABLE_FILTER_LOW).click(); +}; + +export const removeLowFilterAndCloseUserRiskTableFilter = () => { + cy.get(USER_BY_RISK_TABLE_FILTER_LOW).click(); + cy.get(USER_BY_RISK_TABLE_FILTER).first().click(); +}; diff --git a/x-pack/test/security_solution_cypress/es_archives/query_alert/data.json b/x-pack/test/security_solution_cypress/es_archives/query_alert/data.json index 94328064bd5e4..dc677dd5bf812 100644 --- a/x-pack/test/security_solution_cypress/es_archives/query_alert/data.json +++ b/x-pack/test/security_solution_cypress/es_archives/query_alert/data.json @@ -119,6 +119,9 @@ "path": "C:/fake_malware.exe", "size": 3456 }, + "user": { + "name": "user1" + }, "host": { "architecture": "wtnozeqvub", "hostname": "Host-fwarau82er", diff --git a/x-pack/test/security_solution_cypress/es_archives/risk_scores_new/data.json b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new/data.json new file mode 100644 index 0000000000000..53d13ea650ec2 --- /dev/null +++ b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new/data.json @@ -0,0 +1,485 @@ +{ + "type": "doc", + "value": { + "id": "a4cf452c1e0375c3d4412cb550ad1783358468a3b3b777da4829d72c7d6fb74f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "host": { + "name": "siem-kibana", + "risk": { + "calculated_level": "Critical", + "calculated_score_norm": 90, + "id_field": "host.name", + "id_value": "siem-kibana", + "calculated_score": 150, + "category_1_score": 150, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "62895f54816047b9bf82929a61a6c571f41de9c2361670f6ef0136360e006f58", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "New Rule Test", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + }, + { + "id": "e5bf3da3c855486ac7b40fa1aa33e19cf1380e413b79ed76bddf728f8fec4462", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "New Rule Test", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb71f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "host": { + "name": "fake-1", + "risk": { + "calculated_level": "Moderate", + "calculated_score_norm": 50, + "id_field": "host.name", + "id_value": "fake-1", + "calculated_score": 200, + "category_1_score": 200, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1283358468a3b3b777da4829d72c7d6fb72f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "host": { + "name": "fake-2", + "risk": { + "calculated_level": "Moderate", + "calculated_score_norm": 50, + "id_field": "host.name", + "id_value": "fake-2", + "calculated_score": 220, + "category_1_score": 200, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1782358468a3b3b777da4829d72c7d6fb73f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "host": { + "name": "fake-3", + "risk": { + "calculated_level": "Moderate", + "calculated_score_norm": 50, + "id_field": "host.name", + "id_value": "fake-3", + "calculated_score": 220, + "category_1_score": 220, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb745", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "host": { + "name": "fake-4", + "risk": { + "calculated_level": "Moderate", + "calculated_score_norm": 50, + "id_field": "host.name", + "id_value": "fake-4", + "calculated_score": 220, + "category_1_score": 200, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb752", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "host": { + "name": "fake-5", + "risk": { + "calculated_level": "Moderate", + "calculated_score_norm": 50, + "id_field": "host.name", + "id_value": "fake-5", + "calculated_score": 220, + "category_1_score": 220, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb752", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "host": { + "name": "Host-fwarau82er", + "risk": { + "calculated_level": "Moderate", + "calculated_score_norm": 50, + "id_field": "host.name", + "id_value": "Host-fwarau82er", + "calculated_score": 220, + "category_1_score": 220, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Endpoint Security", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d2fb74f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "user": { + "name": "user2", + "risk": { + "calculated_score_norm": 50, + "calculated_level": "Moderate", + "id_field": "user.name", + "id_value": "user2", + "calculated_score": 150, + "category_1_score": 150, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb72f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "user": { + "name": "user3", + "risk": { + "calculated_score_norm": 50, + "calculated_level": "Moderate", + "id_field": "user.name", + "id_value": "user3", + "calculated_score": 150, + "category_1_score": 150, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb73f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "user": { + "name": "user4", + "risk": { + "calculated_score_norm": 50, + "calculated_level": "Moderate", + "id_field": "user.name", + "id_value": "user4", + "calculated_score": 150, + "category_1_score": 150, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "user": { + "name": "user5", + "risk": { + "calculated_score_norm": 50, + "calculated_level": "Moderate", + "id_field": "user.name", + "id_value": "user6", + "calculated_score": 150, + "category_1_score": 150, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a2cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb75f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "user": { + "name": "user6", + "risk": { + "calculated_score_norm": 50, + "calculated_level": "Moderate", + "id_field": "user.name", + "id_value": "user6", + "calculated_score": 220, + "category_1_score": 220, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a4cf452c1e0375c3d4412cb550bd1783358468b3b3b777da4829d72c7d6fb74f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "user": { + "name": "user1", + "risk": { + "calculated_score_norm": 21, + "calculated_level": "Low", + "id_field": "user.name", + "id_value": "user1", + "calculated_score": 150, + "category_1_score": 150, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Endpoint Security", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a4cf452c1e0375c3d4412cb550bd1783358468b3123314829d72c7df6fb74", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:52:05.766Z", + "user": { + "name": "test", + "risk": { + "calculated_score_norm": 60, + "calculated_level": "High", + "id_field": "user.name", + "id_value": "test", + "calculated_score": 150, + "category_1_score": 150, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} diff --git a/x-pack/test/security_solution_cypress/es_archives/risk_scores_new/mappings.json b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new/mappings.json new file mode 100644 index 0000000000000..0549fb1c08ced --- /dev/null +++ b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new/mappings.json @@ -0,0 +1,135 @@ +{ + "type": "index", + "value": { + "index": "risk-score.risk-score-latest-default", + "mappings": { + "dynamic": "strict", + "properties": { + "@timestamp": { + "type": "date" + }, + "host": { + "properties": { + "name": { + "type": "keyword" + }, + "risk": { + "properties": { + "calculated_level": { + "type": "keyword" + }, + "calculated_score": { + "type": "float" + }, + "calculated_score_norm": { + "type": "float" + }, + "category_1_count": { + "type": "long" + }, + "category_1_score": { + "type": "float" + }, + "id_field": { + "type": "keyword" + }, + "id_value": { + "type": "keyword" + }, + "inputs": { + "properties": { + "category": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "index": { + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "timestamp": { + "type": "date" + } + } + }, + "notes": { + "type": "keyword" + } + } + } + } + }, + "user": { + "properties": { + "name": { + "type": "keyword" + }, + "risk": { + "properties": { + "calculated_level": { + "type": "keyword" + }, + "calculated_score": { + "type": "float" + }, + "calculated_score_norm": { + "type": "float" + }, + "category_1_count": { + "type": "long" + }, + "category_1_score": { + "type": "float" + }, + "id_field": { + "type": "keyword" + }, + "id_value": { + "type": "keyword" + }, + "inputs": { + "properties": { + "category": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "index": { + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "timestamp": { + "type": "date" + } + } + }, + "notes": { + "type": "keyword" + } + } + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } + } diff --git a/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_no_data/data.json b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_no_data/data.json new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_no_data/mappings.json b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_no_data/mappings.json new file mode 100644 index 0000000000000..35cb0031894d7 --- /dev/null +++ b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_no_data/mappings.json @@ -0,0 +1,136 @@ +{ + + "type": "index", + "value": { + "index": "risk-score.risk-score-latest-default", + "mappings": { + "dynamic": "strict", + "properties": { + "@timestamp": { + "type": "date" + }, + "host": { + "properties": { + "name": { + "type": "keyword" + }, + "risk": { + "properties": { + "calculated_level": { + "type": "keyword" + }, + "calculated_score": { + "type": "float" + }, + "calculated_score_norm": { + "type": "float" + }, + "category_1_count": { + "type": "long" + }, + "category_1_score": { + "type": "float" + }, + "id_field": { + "type": "keyword" + }, + "id_value": { + "type": "keyword" + }, + "inputs": { + "properties": { + "category": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "index": { + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "timestamp": { + "type": "date" + } + } + }, + "notes": { + "type": "keyword" + } + } + } + } + }, + "user": { + "properties": { + "name": { + "type": "keyword" + }, + "risk": { + "properties": { + "calculated_level": { + "type": "keyword" + }, + "calculated_score": { + "type": "float" + }, + "calculated_score_norm": { + "type": "float" + }, + "category_1_count": { + "type": "long" + }, + "category_1_score": { + "type": "float" + }, + "id_field": { + "type": "keyword" + }, + "id_value": { + "type": "keyword" + }, + "inputs": { + "properties": { + "category": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "index": { + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "timestamp": { + "type": "date" + } + } + }, + "notes": { + "type": "keyword" + } + } + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } + } \ No newline at end of file diff --git a/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_updated/data.json b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_updated/data.json new file mode 100644 index 0000000000000..058c081b3ee6d --- /dev/null +++ b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_updated/data.json @@ -0,0 +1,67 @@ +{ + "type": "doc", + "value": { + "id": "a4cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:51:05.766Z", + "host": { + "name": "siem-kibana", + "risk": { + "calculated_level": "Low", + "calculated_score_norm": 20, + "id_field": "host.name", + "id_value": "siem-kibana", + "calculated_score": 150, + "category_1_score": 150, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "2e17f189-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "a4cf452c1e0375c3d4412cb550bd1783358468b3123314829d72c7df6fb74", + "index": "risk-score.risk-score-latest-default", + "source": { + "@timestamp": "2021-03-10T14:52:05.766Z", + "user": { + "name": "test", + "risk": { + "calculated_score_norm": 60, + "calculated_level": "High", + "id_field": "user.name", + "id_value": "test", + "calculated_score": 150, + "category_1_score": 150, + "category_1_count": 1, + "notes": [], + "inputs": [ + { + "id": "eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1-d77d-4537-8d84-592e29334493", + "index": ".internal.alerts-security.alerts-default-000001", + "description": "Alert from Rule: Rule 2", + "category": "category_1", + "risk_score": 70, + "timestamp": "2023-08-14T09:08:18.664Z" + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_updated/mappings.json b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_updated/mappings.json new file mode 100644 index 0000000000000..35cb0031894d7 --- /dev/null +++ b/x-pack/test/security_solution_cypress/es_archives/risk_scores_new_updated/mappings.json @@ -0,0 +1,136 @@ +{ + + "type": "index", + "value": { + "index": "risk-score.risk-score-latest-default", + "mappings": { + "dynamic": "strict", + "properties": { + "@timestamp": { + "type": "date" + }, + "host": { + "properties": { + "name": { + "type": "keyword" + }, + "risk": { + "properties": { + "calculated_level": { + "type": "keyword" + }, + "calculated_score": { + "type": "float" + }, + "calculated_score_norm": { + "type": "float" + }, + "category_1_count": { + "type": "long" + }, + "category_1_score": { + "type": "float" + }, + "id_field": { + "type": "keyword" + }, + "id_value": { + "type": "keyword" + }, + "inputs": { + "properties": { + "category": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "index": { + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "timestamp": { + "type": "date" + } + } + }, + "notes": { + "type": "keyword" + } + } + } + } + }, + "user": { + "properties": { + "name": { + "type": "keyword" + }, + "risk": { + "properties": { + "calculated_level": { + "type": "keyword" + }, + "calculated_score": { + "type": "float" + }, + "calculated_score_norm": { + "type": "float" + }, + "category_1_count": { + "type": "long" + }, + "category_1_score": { + "type": "float" + }, + "id_field": { + "type": "keyword" + }, + "id_value": { + "type": "keyword" + }, + "inputs": { + "properties": { + "category": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "index": { + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "timestamp": { + "type": "date" + } + } + }, + "notes": { + "type": "keyword" + } + } + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } + } \ No newline at end of file diff --git a/x-pack/test/security_solution_cypress/serverless_config.ts b/x-pack/test/security_solution_cypress/serverless_config.ts index d0ee1613f6e4c..366e963d1b4eb 100644 --- a/x-pack/test/security_solution_cypress/serverless_config.ts +++ b/x-pack/test/security_solution_cypress/serverless_config.ts @@ -29,6 +29,10 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...svlSharedConfig.get('kbnTestServer.serverArgs'), '--serverless=security', '--xpack.encryptedSavedObjects.encryptionKey="abcdefghijklmnopqrstuvwxyz123456"', + `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'riskScoringRoutesEnabled', + 'riskScoringPersistence', + ])}`, `--xpack.securitySolutionServerless.productTypes=${JSON.stringify([ { product_line: 'security', product_tier: 'complete' }, { product_line: 'endpoint', product_tier: 'complete' },