Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution][RAC] Fixes Threshold Rule functionality for post-rule-migration 8.0 #117571

Merged
merged 13 commits into from
Nov 9, 2021
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