Skip to content

Commit

Permalink
[sentinel_one] Fix agent status field name in Alert details highlight…
Browse files Browse the repository at this point in the history
…ed fields (#174421)

## Summary

Fixes #174235

<img width="1809" alt="image"
src="https://github.com/elastic/kibana/assets/5188868/43f120c7-8bbd-4e5a-9824-5db4fda9f35c">
  • Loading branch information
patrykkopycinski authored Jan 12, 2024
1 parent ba26c1e commit 5344f86
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
// ** //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1777,6 +1777,7 @@ describe('Exception helpers', () => {
},
{
id: 'observer.serial_number',
overrideField: 'agent.status',
label: 'Agent status',
},
{
Expand All @@ -1801,6 +1802,7 @@ describe('Exception helpers', () => {
},
{
id: 'observer.serial_number',
overrideField: 'agent.status',
label: 'Agent status',
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -74,6 +78,7 @@ const columns: Array<EuiBasicTableColumn<HighlightedFieldsTableRow>> = [
width: '70%',
render: (description: {
field: string;
originalField?: string;
values: string[] | null | undefined;
scopeId: string;
isPreview: boolean;
Expand All @@ -94,7 +99,11 @@ const columns: Array<EuiBasicTableColumn<HighlightedFieldsTableRow>> = [
: []
}
>
<HighlightedFieldsCell values={description.values} field={description.field} />
<HighlightedFieldsCell
values={description.values}
field={description.field}
originalField={description.originalField}
/>
</SecurityCellActions>
),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -86,7 +88,22 @@ describe('<HighlightedFieldsCell />', () => {
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(
<TestProviders>
<HighlightedFieldsCell
values={['value']}
field={'agent.status'}
originalField="observer.serial_number"
/>
</TestProviders>
);

expect(getByTestId(HIGHLIGHTED_FIELDS_AGENT_STATUS_CELL_TEST_ID)).toBeInTheDocument();
});

it('should not render if values is null', () => {
const { container } = render(<HighlightedFieldsCell values={null} field={'field'} />);

expect(container).toBeEmptyDOMElement();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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<HighlightedFieldsCellProps> = ({ values, field }) => (
export const HighlightedFieldsCell: VFC<HighlightedFieldsCellProps> = ({
values,
field,
originalField,
}) => (
<>
{values != null &&
values.map((value, i) => {
Expand All @@ -87,13 +95,17 @@ export const HighlightedFieldsCell: VFC<HighlightedFieldsCellProps> = ({ values,
>
{field === HOST_NAME_FIELD_NAME || field === USER_NAME_FIELD_NAME ? (
<LinkFieldCell value={value} />
) : field === AGENT_STATUS_FIELD_NAME &&
originalField === SENTINEL_ONE_AGENT_ID_FIELD ? (
<SentinelOneAgentStatus
agentId={String(value ?? '')}
data-test-subj={HIGHLIGHTED_FIELDS_AGENT_STATUS_CELL_TEST_ID}
/>
) : field === AGENT_STATUS_FIELD_NAME ? (
<EndpointAgentStatusById
endpointAgentId={String(value ?? '')}
data-test-subj={HIGHLIGHTED_FIELDS_AGENT_STATUS_CELL_TEST_ID}
/>
) : field === SENTINEL_ONE_AGENT_ID_FIELD ? (
<SentinelOneAgentStatus agentId={String(value ?? '')} />
) : (
<span data-test-subj={HIGHLIGHTED_FIELDS_BASIC_CELL_TEST_ID}>{value}</span>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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'],
},
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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]: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe('convertHighlightedFieldsToTableRow', () => {
field: 'host.name-override',
description: {
field: 'host.name-override',
originalField: 'host.name',
values: ['host-1'],
scopeId: 'scopeId',
isPreview,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const convertHighlightedFieldsToTableRow = (
field,
description: {
field,
...(overrideFieldName ? { originalField: fieldName } : {}),
values,
scopeId,
isPreview,
Expand Down

0 comments on commit 5344f86

Please sign in to comment.