Skip to content

Commit

Permalink
[Security Solution][RAC] Threshold Rule Fixes (#117571)
Browse files Browse the repository at this point in the history
* Remove unused code

* Fix threshold field refs

* Fix import

* UI fixes for Rules

* Threshold Cypress test fixes

* Type fixes

* Threshold signal test fixes

* Handle legacy schema optionally

* Fix threshold integration test

* More test fixes
  • Loading branch information
madirey authored Nov 9, 2021
1 parent 56bfd0e commit c44dd6e
Show file tree
Hide file tree
Showing 16 changed files with 40 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ describe('Detection rules, threshold', () => {
waitForAlertsIndexToBeCreated();
});

it.skip('Creates and activates a new threshold rule', () => {
it('Creates and activates a new threshold rule', () => {
goToManageAlertsDetectionRules();
waitForRulesTableToBeLoaded();
goToCreateNewRule();
Expand Down Expand Up @@ -171,9 +171,7 @@ describe('Detection rules, threshold', () => {
waitForAlertsToPopulate();

cy.get(NUMBER_OF_ALERTS).should(($count) => expect(+$count.text().split(' ')[0]).to.be.lt(100));
cy.get(ALERT_GRID_CELL).eq(3).contains(rule.name);
cy.get(ALERT_GRID_CELL).eq(4).contains(rule.severity.toLowerCase());
cy.get(ALERT_GRID_CELL).eq(5).contains(rule.riskScore);
cy.get(ALERT_GRID_CELL).contains(rule.name);
});

it('Preview results of keyword using "host.name"', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ const InvestigateInTimelineActionComponent = (alertIds: string[]) => {
alertIds={alertIds}
key="investigate-in-timeline"
ecsRowData={null}
nonEcsRowData={[]}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ describe('alert actions', () => {
await sendAlertToTimelineAction({
createTimeline,
ecsData: mockEcsDataWithAlert,
nonEcsData: [],
updateTimelineIsLoading,
searchStrategyClient,
});
Expand All @@ -92,7 +91,6 @@ describe('alert actions', () => {
await sendAlertToTimelineAction({
createTimeline,
ecsData: mockEcsDataWithAlert,
nonEcsData: [],
updateTimelineIsLoading,
searchStrategyClient,
});
Expand Down Expand Up @@ -249,7 +247,6 @@ describe('alert actions', () => {
await sendAlertToTimelineAction({
createTimeline,
ecsData: mockEcsDataWithAlert,
nonEcsData: [],
updateTimelineIsLoading,
searchStrategyClient,
});
Expand All @@ -267,7 +264,6 @@ describe('alert actions', () => {
await sendAlertToTimelineAction({
createTimeline,
ecsData: mockEcsDataWithAlert,
nonEcsData: [],
updateTimelineIsLoading,
searchStrategyClient,
});
Expand Down Expand Up @@ -301,7 +297,6 @@ describe('alert actions', () => {
await sendAlertToTimelineAction({
createTimeline,
ecsData: ecsDataMock,
nonEcsData: [],
updateTimelineIsLoading,
searchStrategyClient,
});
Expand All @@ -327,7 +322,6 @@ describe('alert actions', () => {
await sendAlertToTimelineAction({
createTimeline,
ecsData: ecsDataMock,
nonEcsData: [],
updateTimelineIsLoading,
searchStrategyClient,
});
Expand Down Expand Up @@ -357,7 +351,6 @@ describe('alert actions', () => {
await sendAlertToTimelineAction({
createTimeline,
ecsData: ecsDataMock,
nonEcsData: [],
updateTimelineIsLoading,
searchStrategyClient,
});
Expand Down Expand Up @@ -398,7 +391,6 @@ describe('alert actions', () => {
await sendAlertToTimelineAction({
createTimeline,
ecsData: ecsDataMock,
nonEcsData: [],
updateTimelineIsLoading,
searchStrategyClient,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

/* eslint-disable complexity */

import { get, getOr, isEmpty } from 'lodash/fp';
import { getOr, isEmpty } from 'lodash/fp';
import moment from 'moment';

import dateMath from '@elastic/datemath';
Expand Down Expand Up @@ -37,7 +37,6 @@ import {
} from './types';
import { Ecs } from '../../../../common/ecs';
import {
TimelineNonEcsData,
TimelineEventsDetailsItem,
TimelineEventsDetailsRequestOptions,
TimelineEventsDetailsStrategyResponse,
Expand Down Expand Up @@ -75,26 +74,6 @@ export const getUpdateAlertsQuery = (eventIds: Readonly<string[]>) => {
};
};

export const getFilterAndRuleBounds = (
data: TimelineNonEcsData[][]
): [string[], number, number] => {
const stringFilter =
data?.[0].filter(
(d) => d.field === 'signal.rule.filters' || d.field === 'kibana.alert.rule.filters'
)?.[0]?.value ?? [];

const eventTimes = data
.flatMap(
(alert) =>
alert.filter(
(d) => d.field === 'signal.original_time' || d.field === 'kibana.alert.original_time'
)?.[0]?.value ?? []
)
.map((d) => moment(d));

return [stringFilter, moment.min(eventTimes).valueOf(), moment.max(eventTimes).valueOf()];
};

export const updateAlertStatusAction = async ({
query,
alertIds,
Expand Down Expand Up @@ -174,11 +153,7 @@ const getFiltersFromRule = (filters: string[]): Filter[] =>
}
}, [] as Filter[]);

export const getThresholdAggregationData = (
ecsData: Ecs | Ecs[],
nonEcsData: TimelineNonEcsData[]
): ThresholdAggregationData => {
// TODO: AAD fields
export const getThresholdAggregationData = (ecsData: Ecs | Ecs[]): ThresholdAggregationData => {
const thresholdEcsData: Ecs[] = Array.isArray(ecsData) ? ecsData : [ecsData];
return thresholdEcsData.reduce<ThresholdAggregationData>(
(outerAcc, thresholdData) => {
Expand All @@ -195,11 +170,9 @@ export const getThresholdAggregationData = (
};

try {
try {
thresholdResult = JSON.parse((thresholdData.signal?.threshold_result as string[])[0]);
} catch (err) {
thresholdResult = JSON.parse((get(ALERT_THRESHOLD_RESULT, thresholdData) as string[])[0]);
}
thresholdResult = JSON.parse(
(getField(thresholdData, ALERT_THRESHOLD_RESULT) as string[])[0]
);
aggField = JSON.parse(threshold[0]).field;
} catch (err) {
// Legacy support
Expand Down Expand Up @@ -401,7 +374,6 @@ export const buildEqlDataProviderOrFilter = (
export const sendAlertToTimelineAction = async ({
createTimeline,
ecsData: ecs,
nonEcsData,
updateTimelineIsLoading,
searchStrategyClient,
}: SendAlertToTimelineActionProps) => {
Expand Down Expand Up @@ -498,10 +470,7 @@ export const sendAlertToTimelineAction = async ({
}

if (isThresholdRule(ecsData)) {
const { thresholdFrom, thresholdTo, dataProviders } = getThresholdAggregationData(
ecsData,
nonEcsData
);
const { thresholdFrom, thresholdTo, dataProviders } = getThresholdAggregationData(ecsData);

return createTimeline({
from: thresholdFrom,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import React from 'react';

import { Ecs } from '../../../../../common/ecs';
import { TimelineNonEcsData } from '../../../../../common/search_strategy/timeline';
import { ActionIconItem } from '../../../../timelines/components/timeline/body/actions/action_icon_item';

import {
Expand All @@ -19,7 +18,6 @@ import { useInvestigateInTimeline } from './use_investigate_in_timeline';

interface InvestigateInTimelineActionProps {
ecsRowData?: Ecs | Ecs[] | null;
nonEcsRowData?: TimelineNonEcsData[];
ariaLabel?: string;
alertIds?: string[];
buttonType?: 'text' | 'icon';
Expand All @@ -30,13 +28,11 @@ const InvestigateInTimelineActionComponent: React.FC<InvestigateInTimelineAction
ariaLabel = ACTION_INVESTIGATE_IN_TIMELINE_ARIA_LABEL,
alertIds,
ecsRowData,
nonEcsRowData,
buttonType,
onInvestigateInTimelineAlertClick,
}) => {
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({
ecsRowData,
nonEcsRowData,
alertIds,
onInvestigateInTimelineAlertClick,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ interface UseInvestigateInTimelineActionProps {

export const useInvestigateInTimeline = ({
ecsRowData,
nonEcsRowData,
alertIds,
onInvestigateInTimelineAlertClick,
}: UseInvestigateInTimelineActionProps) => {
Expand Down Expand Up @@ -90,7 +89,6 @@ export const useInvestigateInTimeline = ({
await sendAlertToTimelineAction({
createTimeline,
ecsData: alertsEcsData,
nonEcsData: nonEcsRowData ?? [],
searchStrategyClient,
updateTimelineIsLoading,
});
Expand All @@ -100,7 +98,6 @@ export const useInvestigateInTimeline = ({
await sendAlertToTimelineAction({
createTimeline,
ecsData: ecsRowData,
nonEcsData: nonEcsRowData ?? [],
searchStrategyClient,
updateTimelineIsLoading,
});
Expand All @@ -109,7 +106,6 @@ export const useInvestigateInTimeline = ({
alertsEcsData,
createTimeline,
ecsRowData,
nonEcsRowData,
onInvestigateInTimelineAlertClick,
searchStrategyClient,
updateTimelineIsLoading,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import { ISearchStart } from '../../../../../../../src/plugins/data/public';
import { Status } from '../../../../common/detection_engine/schemas/common/schemas';
import { Ecs } from '../../../../common/ecs';
import { TimelineNonEcsData } from '../../../../common/search_strategy/timeline';
import { NoteResult } from '../../../../common/types/timeline/note';
import { DataProvider } from '../../../timelines/components/timeline/data_providers/data_provider';
import { TimelineModel } from '../../../timelines/store/timeline/model';
Expand Down Expand Up @@ -54,7 +53,6 @@ export interface UpdateAlertStatusActionProps {
export interface SendAlertToTimelineActionProps {
createTimeline: CreateTimeline;
ecsData: Ecs | Ecs[];
nonEcsData: TimelineNonEcsData[];
updateTimelineIsLoading: UpdateTimelineLoading;
searchStrategyClient: ISearchStart;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export const RuleSchema = t.intersection([
timestamp_override,
note: t.string,
exceptions_list: listArray,
uuid: t.string,
version: t.number,
}),
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,13 @@ interface AlertHit {
_index: string;
_source: {
'@timestamp': string;
signal: {
rule: Rule;
signal?: {
rule?: Rule;
};
kibana?: {
alert?: {
rule?: Rule;
};
};
};
}
Expand Down Expand Up @@ -77,7 +82,10 @@ export const useRuleWithFallback = (ruleId: string): UseRuleWithFallback => {
}, [addError, error]);

const rule = useMemo<Rule | undefined>(() => {
const result = isExistingRule ? ruleData : alertsData?.hits.hits[0]?._source.signal.rule;
const hit = alertsData?.hits.hits[0];
const result = isExistingRule
? ruleData
: hit?._source.signal?.rule ?? hit?._source.kibana?.alert?.rule;
if (result) {
return transformInput(result);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ const ActionsComponent: React.FC<ActionProps> = ({
ariaLabel={i18n.SEND_ALERT_TO_TIMELINE_FOR_ROW({ ariaRowindex, columnValues })}
key="investigate-in-timeline"
ecsRowData={ecsData}
nonEcsRowData={data}
/>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
ALERT_ANCESTORS,
ALERT_DEPTH,
ALERT_ORIGINAL_TIME,
ALERT_THRESHOLD_RESULT,
ALERT_ORIGINAL_EVENT,
} from '../../../../../../common/field_maps/field_names';

Expand All @@ -59,10 +60,10 @@ export const buildParent = (doc: SimpleHit): Ancestor => {
id: doc._id,
type: isSignal ? 'signal' : 'event',
index: doc._index,
depth: isSignal ? getField(doc, 'signal.depth') ?? 1 : 0,
depth: isSignal ? getField(doc, ALERT_DEPTH) ?? 1 : 0,
};
if (isSignal) {
parent.rule = getField(doc, 'signal.rule.id');
parent.rule = getField(doc, ALERT_RULE_UUID);
}
return parent;
};
Expand All @@ -73,9 +74,8 @@ export const buildParent = (doc: SimpleHit): Ancestor => {
* @param doc The parent event for which to extend the ancestry.
*/
export const buildAncestors = (doc: SimpleHit): Ancestor[] => {
// TODO: handle alerts-on-legacy-alerts
const newAncestor = buildParent(doc);
const existingAncestors: Ancestor[] = getField(doc, 'signal.ancestors') ?? [];
const existingAncestors: Ancestor[] = getField(doc, ALERT_ANCESTORS) ?? [];
return [...existingAncestors, newAncestor];
};

Expand Down Expand Up @@ -130,7 +130,7 @@ export const additionalAlertFields = (doc: BaseSignalHit) => {
});
const additionalFields: Record<string, unknown> = {
[ALERT_ORIGINAL_TIME]: originalTime != null ? originalTime.toISOString() : undefined,
...(thresholdResult != null ? { threshold_result: thresholdResult } : {}),
...(thresholdResult != null ? { [ALERT_THRESHOLD_RESULT]: thresholdResult } : {}),
};

for (const [key, val] of Object.entries(doc._source ?? {})) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@
* 2.0.
*/

import { ALERT_THRESHOLD_RESULT } from '../../../../../../common/field_maps/field_names';
import { SignalSourceHit } from '../../../signals/types';
import { RACAlert } from '../../types';

export const filterSource = (doc: SignalSourceHit): Partial<RACAlert> => {
const docSource = doc._source ?? {};
const {
event,
threshold_result: thresholdResult,
threshold_result: siemSignalsThresholdResult,
[ALERT_THRESHOLD_RESULT]: alertThresholdResult,
...filteredSource
} = docSource || {
event: null,
threshold_result: null,
[ALERT_THRESHOLD_RESULT]: null,
};

return filteredSource;
Expand Down
Loading

0 comments on commit c44dd6e

Please sign in to comment.