diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx index 417ce415d0b57d..76b6c355cf35cf 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx @@ -52,6 +52,7 @@ const alwaysDisplayedFields: EventSummaryField[] = [ { id: 'agent.id', overrideField: AGENT_STATUS_FIELD_NAME, label: i18n.AGENT_STATUS }, { id: SENTINEL_ONE_AGENT_ID_FIELD, + overrideField: AGENT_STATUS_FIELD_NAME, label: i18n.AGENT_STATUS, }, // ** // diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx index 957aa11cdf6bca..8c2bb6bb20dccf 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx @@ -1777,6 +1777,7 @@ describe('Exception helpers', () => { }, { id: 'observer.serial_number', + overrideField: 'agent.status', label: 'Agent status', }, { @@ -1801,6 +1802,7 @@ describe('Exception helpers', () => { }, { id: 'observer.serial_number', + overrideField: 'agent.status', label: 'Agent status', }, { diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/sentinel_one_agent_status.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/sentinel_one_agent_status.tsx index 4f40b338544a36..3d643dffc51cc9 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/sentinel_one_agent_status.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/host_isolation/sentinel_one_agent_status.tsx @@ -45,7 +45,7 @@ const EuiFlexGroupStyled = styled(EuiFlexGroup)` `; export const SentinelOneAgentStatus = React.memo( - ({ agentId, dataTestSubj }: { agentId: string; dataTestSubj?: string }) => { + ({ agentId, 'data-test-subj': dataTestSubj }: { agentId: string; 'data-test-subj'?: string }) => { const { data, isFetched } = useSentinelOneAgentData({ agentId }); const label = useMemo(() => { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields.tsx index 5e6bcb2add4413..059de0cc1f7362 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields.tsx @@ -35,6 +35,10 @@ export interface HighlightedFieldsTableRow { * Highlighted field name (overrideField or if null, falls back to id) */ field: string; + /** + * Highlighted field's original name, when the field is overridden + */ + originalField?: string; /** * Highlighted field value */ @@ -74,6 +78,7 @@ const columns: Array> = [ width: '70%', render: (description: { field: string; + originalField?: string; values: string[] | null | undefined; scopeId: string; isPreview: boolean; @@ -94,7 +99,11 @@ const columns: Array> = [ : [] } > - + ), }, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx index 0112e06cb489f9..b5a1e0f3642814 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx @@ -20,8 +20,10 @@ import { LeftPanelInsightsTab, DocumentDetailsLeftPanelKey } from '../../left'; import { TestProviders } from '../../../../common/mock'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { useGetEndpointDetails } from '../../../../management/hooks'; +import { useSentinelOneAgentData } from '../../../../detections/components/host_isolation/use_sentinelone_host_isolation'; jest.mock('../../../../management/hooks'); +jest.mock('../../../../detections/components/host_isolation/use_sentinelone_host_isolation'); const flyoutContextValue = { openLeftPanel: jest.fn(), @@ -86,7 +88,22 @@ describe('', () => { expect(getByTestId(HIGHLIGHTED_FIELDS_AGENT_STATUS_CELL_TEST_ID)).toBeInTheDocument(); }); - it('should render agent status component if override field is agent.status', () => { + it('should render sentinelone agent status cell if field is agent.status and origialField is observer.serial_number', () => { + (useSentinelOneAgentData as jest.Mock).mockReturnValue({ isFetched: true }); + const { getByTestId } = render( + + + + ); + + expect(getByTestId(HIGHLIGHTED_FIELDS_AGENT_STATUS_CELL_TEST_ID)).toBeInTheDocument(); + }); + + it('should not render if values is null', () => { const { container } = render(); expect(container).toBeEmptyDOMElement(); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx index 9833d050acfe78..3e2570f8f87378 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx @@ -66,6 +66,10 @@ export interface HighlightedFieldsCellProps { * Highlighted field's name used to know what component to display */ field: string; + /** + * Highlighted field's original name, when the field is overridden + */ + originalField?: string; /** * Highlighted field's value to display */ @@ -75,7 +79,11 @@ export interface HighlightedFieldsCellProps { /** * Renders a component in the highlighted fields table cell based on the field name */ -export const HighlightedFieldsCell: VFC = ({ values, field }) => ( +export const HighlightedFieldsCell: VFC = ({ + values, + field, + originalField, +}) => ( <> {values != null && values.map((value, i) => { @@ -87,13 +95,17 @@ export const HighlightedFieldsCell: VFC = ({ values, > {field === HOST_NAME_FIELD_NAME || field === USER_NAME_FIELD_NAME ? ( + ) : field === AGENT_STATUS_FIELD_NAME && + originalField === SENTINEL_ONE_AGENT_ID_FIELD ? ( + ) : field === AGENT_STATUS_FIELD_NAME ? ( - ) : field === SENTINEL_ONE_AGENT_ID_FIELD ? ( - ) : ( {value} )} diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx index b45af8ea45d179..5c551d928cad9d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx @@ -9,6 +9,7 @@ import { renderHook } from '@testing-library/react-hooks'; import { mockDataFormattedForFieldBrowser } from '../mocks/mock_data_formatted_for_field_browser'; import { useHighlightedFields } from './use_highlighted_fields'; +import { SENTINEL_ONE_AGENT_ID_FIELD } from '../../../../common/utils/sentinelone_alert_check'; const dataFormattedForFieldBrowser = mockDataFormattedForFieldBrowser; @@ -21,4 +22,112 @@ describe('useHighlightedFields', () => { }, }); }); + + it('should omit endpoint agent id field if data is not s1 alert', () => { + const hookResult = renderHook(() => + useHighlightedFields({ + dataFormattedForFieldBrowser: dataFormattedForFieldBrowser.concat({ + category: 'agent', + field: 'agent.id', + values: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], + originalValue: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], + isObjectArray: false, + }), + investigationFields: ['agent.status', 'agent.id'], + }) + ); + + expect(hookResult.result.current).toEqual({ + 'kibana.alert.rule.type': { + values: ['query'], + }, + }); + }); + + it('should return endpoint agent id field if data is s1 alert', () => { + const hookResult = renderHook(() => + useHighlightedFields({ + dataFormattedForFieldBrowser: dataFormattedForFieldBrowser.concat([ + { + category: 'agent', + field: 'agent.type', + values: ['endpoint'], + originalValue: ['endpoint'], + isObjectArray: false, + }, + { + category: 'agent', + field: 'agent.id', + values: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], + originalValue: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], + isObjectArray: false, + }, + ]), + investigationFields: ['agent.status', 'agent.id'], + }) + ); + + expect(hookResult.result.current).toEqual({ + 'kibana.alert.rule.type': { + values: ['query'], + }, + 'agent.id': { + values: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], + }, + }); + }); + + it('should omit sentinelone agent id field if data is not s1 alert', () => { + const hookResult = renderHook(() => + useHighlightedFields({ + dataFormattedForFieldBrowser: dataFormattedForFieldBrowser.concat({ + category: 'observer', + field: `observer.${SENTINEL_ONE_AGENT_ID_FIELD}`, + values: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], + originalValue: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], + isObjectArray: false, + }), + investigationFields: ['agent.status', 'observer.serial_number'], + }) + ); + + expect(hookResult.result.current).toEqual({ + 'kibana.alert.rule.type': { + values: ['query'], + }, + }); + }); + + it('should return sentinelone agent id field if data is s1 alert', () => { + const hookResult = renderHook(() => + useHighlightedFields({ + dataFormattedForFieldBrowser: dataFormattedForFieldBrowser.concat([ + { + category: 'event', + field: 'event.module', + values: ['sentinel_one'], + originalValue: ['sentinel_one'], + isObjectArray: false, + }, + { + category: 'observer', + field: SENTINEL_ONE_AGENT_ID_FIELD, + values: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], + originalValue: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], + isObjectArray: false, + }, + ]), + investigationFields: ['agent.status', 'observer.serial_number'], + }) + ); + + expect(hookResult.result.current).toEqual({ + 'kibana.alert.rule.type': { + values: ['query'], + }, + 'observer.serial_number': { + values: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], + }, + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts index 72526c904bbb2c..986bbb7604d0e6 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts @@ -8,6 +8,10 @@ import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import { find, isEmpty } from 'lodash/fp'; import { ALERT_RULE_TYPE } from '@kbn/rule-data-utils'; +import { + SENTINEL_ONE_AGENT_ID_FIELD, + isAlertFromSentinelOneEvent, +} from '../../../../common/utils/sentinelone_alert_check'; import { isAlertFromEndpointEvent } from '../../../../common/utils/endpoint_alert_check'; import { getEventCategoriesFromData, @@ -99,6 +103,14 @@ export const useHighlightedFields = ({ return acc; } + // if the field is observer.serial_number and the event is not a sentinel one event we skip it + if ( + field.id === SENTINEL_ONE_AGENT_ID_FIELD && + !isAlertFromSentinelOneEvent({ data: dataFormattedForFieldBrowser }) + ) { + return acc; + } + return { ...acc, [field.id]: { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.test.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.test.ts index 1565837f90fc2e..2fe057b8a6e1d8 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.test.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.test.ts @@ -45,6 +45,7 @@ describe('convertHighlightedFieldsToTableRow', () => { field: 'host.name-override', description: { field: 'host.name-override', + originalField: 'host.name', values: ['host-1'], scopeId: 'scopeId', isPreview, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.ts index 6cf1ec9291efe7..0ffbd0923dde9f 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.ts @@ -29,6 +29,7 @@ export const convertHighlightedFieldsToTableRow = ( field, description: { field, + ...(overrideFieldName ? { originalField: fieldName } : {}), values, scopeId, isPreview,