mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Security Solution][Detections] Updates RuleDetails to query alerts by RuleId instead of Rule SO ID (#120053) (#120710)
* Switches RuleDetails to query alerts by ruleId instead of SO id * Increases integrity of test outputs * Cleans up duplicate RuleRegistry functions * Removes support for rule.id for alerts filter and updates exceptions to use new filter
This commit is contained in:
parent
32ff2d11e9
commit
3de8da3964
14 changed files with 102 additions and 294 deletions
|
@ -24,6 +24,7 @@ const VERSION = `${KIBANA_NAMESPACE}.version` as const;
|
|||
|
||||
// Fields pertaining to the alert
|
||||
const ALERT_ACTION_GROUP = `${ALERT_NAMESPACE}.action_group` as const;
|
||||
const ALERT_BUILDING_BLOCK_TYPE = `${ALERT_NAMESPACE}.building_block_type` as const;
|
||||
const ALERT_DURATION = `${ALERT_NAMESPACE}.duration.us` as const;
|
||||
const ALERT_END = `${ALERT_NAMESPACE}.end` as const;
|
||||
const ALERT_EVALUATION_THRESHOLD = `${ALERT_NAMESPACE}.evaluation.threshold` as const;
|
||||
|
@ -91,6 +92,7 @@ const fields = {
|
|||
TAGS,
|
||||
TIMESTAMP,
|
||||
ALERT_ACTION_GROUP,
|
||||
ALERT_BUILDING_BLOCK_TYPE,
|
||||
ALERT_DURATION,
|
||||
ALERT_END,
|
||||
ALERT_EVALUATION_THRESHOLD,
|
||||
|
@ -141,6 +143,7 @@ const fields = {
|
|||
|
||||
export {
|
||||
ALERT_ACTION_GROUP,
|
||||
ALERT_BUILDING_BLOCK_TYPE,
|
||||
ALERT_DURATION,
|
||||
ALERT_END,
|
||||
ALERT_EVALUATION_THRESHOLD,
|
||||
|
|
|
@ -327,11 +327,16 @@ export const AddExceptionModal = memo(function AddExceptionModal({
|
|||
const alertIdToClose = shouldCloseAlert && alertData ? alertData._id : undefined;
|
||||
const bulkCloseIndex =
|
||||
shouldBulkCloseAlert && signalIndexName != null ? [signalIndexName] : undefined;
|
||||
addOrUpdateExceptionItems(ruleId, enrichExceptionItems(), alertIdToClose, bulkCloseIndex);
|
||||
addOrUpdateExceptionItems(
|
||||
maybeRule?.rule_id ?? '',
|
||||
enrichExceptionItems(),
|
||||
alertIdToClose,
|
||||
bulkCloseIndex
|
||||
);
|
||||
}
|
||||
}, [
|
||||
addOrUpdateExceptionItems,
|
||||
ruleId,
|
||||
maybeRule,
|
||||
enrichExceptionItems,
|
||||
shouldCloseAlert,
|
||||
shouldBulkCloseAlert,
|
||||
|
|
|
@ -267,11 +267,16 @@ export const EditExceptionModal = memo(function EditExceptionModal({
|
|||
if (addOrUpdateExceptionItems !== null) {
|
||||
const bulkCloseIndex =
|
||||
shouldBulkCloseAlert && signalIndexName !== null ? [signalIndexName] : undefined;
|
||||
addOrUpdateExceptionItems(ruleId, enrichExceptionItems(), undefined, bulkCloseIndex);
|
||||
addOrUpdateExceptionItems(
|
||||
maybeRule?.rule_id ?? '',
|
||||
enrichExceptionItems(),
|
||||
undefined,
|
||||
bulkCloseIndex
|
||||
);
|
||||
}
|
||||
}, [
|
||||
addOrUpdateExceptionItems,
|
||||
ruleId,
|
||||
maybeRule,
|
||||
enrichExceptionItems,
|
||||
shouldBulkCloseAlert,
|
||||
signalIndexName,
|
||||
|
|
|
@ -44,16 +44,14 @@ describe('useAddOrUpdateException', () => {
|
|||
let updateExceptionListItem: jest.SpyInstance<Promise<ExceptionListItemSchema>>;
|
||||
let getQueryFilter: jest.SpyInstance<ReturnType<typeof getQueryFilterHelper.getQueryFilter>>;
|
||||
let buildAlertStatusesFilter: jest.SpyInstance<
|
||||
ReturnType<typeof buildFilterHelpers.buildAlertStatusesFilterRuleRegistry>
|
||||
>;
|
||||
let buildAlertsRuleIdFilter: jest.SpyInstance<
|
||||
ReturnType<typeof buildFilterHelpers.buildAlertsRuleIdFilter>
|
||||
ReturnType<typeof buildFilterHelpers.buildAlertStatusesFilter>
|
||||
>;
|
||||
let buildAlertsFilter: jest.SpyInstance<ReturnType<typeof buildFilterHelpers.buildAlertsFilter>>;
|
||||
let addOrUpdateItemsArgs: Parameters<AddOrUpdateExceptionItemsFunc>;
|
||||
let render: () => RenderHookResult<UseAddOrUpdateExceptionProps, ReturnUseAddOrUpdateException>;
|
||||
const onError = jest.fn();
|
||||
const onSuccess = jest.fn();
|
||||
const ruleId = 'rule-id';
|
||||
const ruleStaticId = 'rule-id';
|
||||
const alertIdToClose = 'idToClose';
|
||||
const bulkCloseIndex = ['.custom'];
|
||||
const itemsToAdd: CreateExceptionListItemSchema[] = [
|
||||
|
@ -128,14 +126,11 @@ describe('useAddOrUpdateException', () => {
|
|||
|
||||
getQueryFilter = jest.spyOn(getQueryFilterHelper, 'getQueryFilter');
|
||||
|
||||
buildAlertStatusesFilter = jest.spyOn(
|
||||
buildFilterHelpers,
|
||||
'buildAlertStatusesFilterRuleRegistry'
|
||||
);
|
||||
buildAlertStatusesFilter = jest.spyOn(buildFilterHelpers, 'buildAlertStatusesFilter');
|
||||
|
||||
buildAlertsRuleIdFilter = jest.spyOn(buildFilterHelpers, 'buildAlertsRuleIdFilter');
|
||||
buildAlertsFilter = jest.spyOn(buildFilterHelpers, 'buildAlertsFilter');
|
||||
|
||||
addOrUpdateItemsArgs = [ruleId, itemsToAddOrUpdate];
|
||||
addOrUpdateItemsArgs = [ruleStaticId, itemsToAddOrUpdate];
|
||||
render = () =>
|
||||
renderHook<UseAddOrUpdateExceptionProps, ReturnUseAddOrUpdateException>(
|
||||
() =>
|
||||
|
@ -262,7 +257,7 @@ describe('useAddOrUpdateException', () => {
|
|||
|
||||
describe('when alertIdToClose is passed in', () => {
|
||||
beforeEach(() => {
|
||||
addOrUpdateItemsArgs = [ruleId, itemsToAddOrUpdate, alertIdToClose];
|
||||
addOrUpdateItemsArgs = [ruleStaticId, itemsToAddOrUpdate, alertIdToClose];
|
||||
});
|
||||
it('should update the alert status', async () => {
|
||||
await act(async () => {
|
||||
|
@ -317,7 +312,7 @@ describe('useAddOrUpdateException', () => {
|
|||
|
||||
describe('when bulkCloseIndex is passed in', () => {
|
||||
beforeEach(() => {
|
||||
addOrUpdateItemsArgs = [ruleId, itemsToAddOrUpdate, undefined, bulkCloseIndex];
|
||||
addOrUpdateItemsArgs = [ruleStaticId, itemsToAddOrUpdate, undefined, bulkCloseIndex];
|
||||
});
|
||||
it('should update the status of only alerts that are open', async () => {
|
||||
await act(async () => {
|
||||
|
@ -351,8 +346,8 @@ describe('useAddOrUpdateException', () => {
|
|||
addOrUpdateItems(...addOrUpdateItemsArgs);
|
||||
}
|
||||
await waitForNextUpdate();
|
||||
expect(buildAlertsRuleIdFilter).toHaveBeenCalledTimes(1);
|
||||
expect(buildAlertsRuleIdFilter.mock.calls[0][0]).toEqual(ruleId);
|
||||
expect(buildAlertsFilter).toHaveBeenCalledTimes(1);
|
||||
expect(buildAlertsFilter.mock.calls[0][0]).toEqual(ruleStaticId);
|
||||
});
|
||||
});
|
||||
it('should generate the query filter using exceptions', async () => {
|
||||
|
|
|
@ -17,27 +17,25 @@ import { HttpStart } from '../../../../../../../src/core/public';
|
|||
import { updateAlertStatus } from '../../../detections/containers/detection_engine/alerts/api';
|
||||
import { getUpdateAlertsQuery } from '../../../detections/components/alerts_table/actions';
|
||||
import {
|
||||
buildAlertsRuleIdFilter,
|
||||
buildAlertsFilter,
|
||||
buildAlertStatusesFilter,
|
||||
buildAlertStatusesFilterRuleRegistry,
|
||||
} from '../../../detections/components/alerts_table/default_config';
|
||||
import { getQueryFilter } from '../../../../common/detection_engine/get_query_filter';
|
||||
import { Index } from '../../../../common/detection_engine/schemas/common/schemas';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features';
|
||||
import { formatExceptionItemForUpdate, prepareExceptionItemsForBulkClose } from './helpers';
|
||||
import { useKibana } from '../../lib/kibana';
|
||||
|
||||
/**
|
||||
* Adds exception items to the list. Also optionally closes alerts.
|
||||
*
|
||||
* @param ruleId id of the rule where the exception updates will be applied
|
||||
* @param ruleStaticId static id of the rule (rule.ruleId, not rule.id) where the exception updates will be applied
|
||||
* @param exceptionItemsToAddOrUpdate array of ExceptionListItemSchema to add or update
|
||||
* @param alertIdToClose - optional string representing alert to close
|
||||
* @param bulkCloseIndex - optional index used to create bulk close query
|
||||
*
|
||||
*/
|
||||
export type AddOrUpdateExceptionItemsFunc = (
|
||||
ruleId: string,
|
||||
ruleStaticId: string,
|
||||
exceptionItemsToAddOrUpdate: Array<ExceptionListItemSchema | CreateExceptionListItemSchema>,
|
||||
alertIdToClose?: string,
|
||||
bulkCloseIndex?: Index
|
||||
|
@ -72,10 +70,10 @@ export const useAddOrUpdateException = ({
|
|||
const addOrUpdateExceptionRef = useRef<AddOrUpdateExceptionItemsFunc | null>(null);
|
||||
const { addExceptionListItem, updateExceptionListItem } = useApi(services.http);
|
||||
const addOrUpdateException = useCallback<AddOrUpdateExceptionItemsFunc>(
|
||||
async (ruleId, exceptionItemsToAddOrUpdate, alertIdToClose, bulkCloseIndex) => {
|
||||
async (ruleStaticId, exceptionItemsToAddOrUpdate, alertIdToClose, bulkCloseIndex) => {
|
||||
if (addOrUpdateExceptionRef.current != null) {
|
||||
addOrUpdateExceptionRef.current(
|
||||
ruleId,
|
||||
ruleStaticId,
|
||||
exceptionItemsToAddOrUpdate,
|
||||
alertIdToClose,
|
||||
bulkCloseIndex
|
||||
|
@ -84,15 +82,13 @@ export const useAddOrUpdateException = ({
|
|||
},
|
||||
[]
|
||||
);
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled');
|
||||
|
||||
useEffect(() => {
|
||||
let isSubscribed = true;
|
||||
const abortCtrl = new AbortController();
|
||||
|
||||
const onUpdateExceptionItemsAndAlertStatus: AddOrUpdateExceptionItemsFunc = async (
|
||||
ruleId,
|
||||
ruleStaticId,
|
||||
exceptionItemsToAddOrUpdate,
|
||||
alertIdToClose,
|
||||
bulkCloseIndex
|
||||
|
@ -131,15 +127,16 @@ export const useAddOrUpdateException = ({
|
|||
}
|
||||
|
||||
if (bulkCloseIndex != null) {
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
const alertStatusFilter = ruleRegistryEnabled
|
||||
? buildAlertStatusesFilterRuleRegistry(['open', 'acknowledged', 'in-progress'])
|
||||
: buildAlertStatusesFilter(['open', 'acknowledged', 'in-progress']);
|
||||
const alertStatusFilter = buildAlertStatusesFilter([
|
||||
'open',
|
||||
'acknowledged',
|
||||
'in-progress',
|
||||
]);
|
||||
|
||||
const filter = getQueryFilter(
|
||||
'',
|
||||
'kuery',
|
||||
[...buildAlertsRuleIdFilter(ruleId), ...alertStatusFilter],
|
||||
[...buildAlertsFilter(ruleStaticId), ...alertStatusFilter],
|
||||
bulkCloseIndex,
|
||||
prepareExceptionItemsForBulkClose(exceptionItemsToAddOrUpdate),
|
||||
false
|
||||
|
@ -185,14 +182,7 @@ export const useAddOrUpdateException = ({
|
|||
isSubscribed = false;
|
||||
abortCtrl.abort();
|
||||
};
|
||||
}, [
|
||||
addExceptionListItem,
|
||||
http,
|
||||
onSuccess,
|
||||
onError,
|
||||
ruleRegistryEnabled,
|
||||
updateExceptionListItem,
|
||||
]);
|
||||
}, [addExceptionListItem, http, onSuccess, onError, updateExceptionListItem]);
|
||||
|
||||
return [{ isLoading }, addOrUpdateException];
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { ExistsFilter, Filter } from '@kbn/es-query';
|
||||
import {
|
||||
buildAlertsRuleIdFilter,
|
||||
buildAlertsFilter,
|
||||
buildAlertStatusesFilter,
|
||||
buildAlertStatusFilter,
|
||||
buildThreatMatchFilter,
|
||||
|
@ -18,21 +18,21 @@ jest.mock('./actions');
|
|||
describe('alerts default_config', () => {
|
||||
describe('buildAlertsRuleIdFilter', () => {
|
||||
test('given a rule id this will return an array with a single filter', () => {
|
||||
const filters: Filter[] = buildAlertsRuleIdFilter('rule-id-1');
|
||||
const filters: Filter[] = buildAlertsFilter('rule-id-1');
|
||||
const expectedFilter: Filter = {
|
||||
meta: {
|
||||
alias: null,
|
||||
negate: false,
|
||||
disabled: false,
|
||||
type: 'phrase',
|
||||
key: 'kibana.alert.rule.uuid',
|
||||
key: 'kibana.alert.rule.rule_id',
|
||||
params: {
|
||||
query: 'rule-id-1',
|
||||
},
|
||||
},
|
||||
query: {
|
||||
match_phrase: {
|
||||
'kibana.alert.rule.uuid': 'rule-id-1',
|
||||
'kibana.alert.rule.rule_id': 'rule-id-1',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -6,21 +6,13 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
ALERT_DURATION,
|
||||
ALERT_RULE_PRODUCER,
|
||||
ALERT_START,
|
||||
ALERT_BUILDING_BLOCK_TYPE,
|
||||
ALERT_WORKFLOW_STATUS,
|
||||
ALERT_UUID,
|
||||
ALERT_RULE_UUID,
|
||||
ALERT_RULE_NAME,
|
||||
ALERT_RULE_CATEGORY,
|
||||
ALERT_RULE_SEVERITY,
|
||||
ALERT_RULE_RISK_SCORE,
|
||||
ALERT_RULE_RULE_ID,
|
||||
} from '@kbn/rule-data-utils/technical_field_names';
|
||||
|
||||
import type { Filter } from '@kbn/es-query';
|
||||
import { defaultColumnHeaderType } from '../../../timelines/components/timeline/body/column_headers/default_headers';
|
||||
import { ColumnHeaderOptions, RowRendererId } from '../../../../common/types/timeline';
|
||||
import { RowRendererId } from '../../../../common/types/timeline';
|
||||
import { Status } from '../../../../common/detection_engine/schemas/common/schemas';
|
||||
import { SubsetTimelineModel } from '../../../timelines/store/timeline/model';
|
||||
import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
|
||||
|
@ -34,12 +26,12 @@ export const buildAlertStatusFilter = (status: Status): Filter[] => {
|
|||
should: [
|
||||
{
|
||||
term: {
|
||||
'kibana.alert.workflow_status': status,
|
||||
[ALERT_WORKFLOW_STATUS]: status,
|
||||
},
|
||||
},
|
||||
{
|
||||
term: {
|
||||
'kibana.alert.workflow_status': 'in-progress',
|
||||
[ALERT_WORKFLOW_STATUS]: 'in-progress',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -47,7 +39,7 @@ export const buildAlertStatusFilter = (status: Status): Filter[] => {
|
|||
}
|
||||
: {
|
||||
term: {
|
||||
'kibana.alert.workflow_status': status,
|
||||
[ALERT_WORKFLOW_STATUS]: status,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -58,7 +50,7 @@ export const buildAlertStatusFilter = (status: Status): Filter[] => {
|
|||
negate: false,
|
||||
disabled: false,
|
||||
type: 'phrase',
|
||||
key: 'kibana.alert.workflow_status',
|
||||
key: ALERT_WORKFLOW_STATUS,
|
||||
params: {
|
||||
query: status,
|
||||
},
|
||||
|
@ -76,7 +68,7 @@ export const buildAlertStatusesFilter = (statuses: Status[]): Filter[] => {
|
|||
bool: {
|
||||
should: statuses.map((status) => ({
|
||||
term: {
|
||||
'kibana.alert.workflow_status': status,
|
||||
[ALERT_WORKFLOW_STATUS]: status,
|
||||
},
|
||||
})),
|
||||
},
|
||||
|
@ -94,8 +86,15 @@ export const buildAlertStatusesFilter = (statuses: Status[]): Filter[] => {
|
|||
];
|
||||
};
|
||||
|
||||
export const buildAlertsRuleIdFilter = (ruleId: string | null): Filter[] =>
|
||||
ruleId
|
||||
/**
|
||||
* Builds Kuery filter for fetching alerts for a specific rule. Takes the rule's
|
||||
* static id, i.e. `rule.ruleId` (not rule.id), so that alerts for _all
|
||||
* historical instances_ of the rule are returned.
|
||||
*
|
||||
* @param ruleStaticId Rule's static id: `rule.ruleId`
|
||||
*/
|
||||
export const buildAlertsFilter = (ruleStaticId: string | null): Filter[] =>
|
||||
ruleStaticId
|
||||
? [
|
||||
{
|
||||
meta: {
|
||||
|
@ -103,14 +102,14 @@ export const buildAlertsRuleIdFilter = (ruleId: string | null): Filter[] =>
|
|||
negate: false,
|
||||
disabled: false,
|
||||
type: 'phrase',
|
||||
key: 'kibana.alert.rule.uuid',
|
||||
key: ALERT_RULE_RULE_ID,
|
||||
params: {
|
||||
query: ruleId,
|
||||
query: ruleStaticId,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
match_phrase: {
|
||||
'kibana.alert.rule.uuid': ruleId,
|
||||
[ALERT_RULE_RULE_ID]: ruleStaticId,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -127,10 +126,10 @@ export const buildShowBuildingBlockFilter = (showBuildingBlockAlerts: boolean):
|
|||
negate: true,
|
||||
disabled: false,
|
||||
type: 'exists',
|
||||
key: 'kibana.alert.building_block_type',
|
||||
key: ALERT_BUILDING_BLOCK_TYPE,
|
||||
value: 'exists',
|
||||
},
|
||||
query: { exists: { field: 'kibana.alert.building_block_type' } },
|
||||
query: { exists: { field: ALERT_BUILDING_BLOCK_TYPE } },
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -183,121 +182,3 @@ export const requiredFieldsForActions = [
|
|||
'host.os.family',
|
||||
'event.code',
|
||||
];
|
||||
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
export const buildAlertStatusFilterRuleRegistry = (status: Status): Filter[] => {
|
||||
const combinedQuery =
|
||||
status === 'acknowledged'
|
||||
? {
|
||||
bool: {
|
||||
should: [
|
||||
{
|
||||
term: {
|
||||
[ALERT_WORKFLOW_STATUS]: status,
|
||||
},
|
||||
},
|
||||
{
|
||||
term: {
|
||||
[ALERT_WORKFLOW_STATUS]: 'in-progress',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
: {
|
||||
term: {
|
||||
[ALERT_WORKFLOW_STATUS]: status,
|
||||
},
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
meta: {
|
||||
alias: null,
|
||||
negate: false,
|
||||
disabled: false,
|
||||
type: 'phrase',
|
||||
key: ALERT_WORKFLOW_STATUS,
|
||||
params: {
|
||||
query: status,
|
||||
},
|
||||
},
|
||||
query: combinedQuery,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
export const buildAlertStatusesFilterRuleRegistry = (statuses: Status[]): Filter[] => {
|
||||
const combinedQuery = {
|
||||
bool: {
|
||||
should: statuses.map((status) => ({
|
||||
term: {
|
||||
[ALERT_WORKFLOW_STATUS]: status,
|
||||
},
|
||||
})),
|
||||
},
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
meta: {
|
||||
alias: null,
|
||||
negate: false,
|
||||
disabled: false,
|
||||
},
|
||||
query: combinedQuery,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export const buildShowBuildingBlockFilterRuleRegistry = (
|
||||
showBuildingBlockAlerts: boolean
|
||||
): Filter[] =>
|
||||
showBuildingBlockAlerts
|
||||
? []
|
||||
: [
|
||||
{
|
||||
meta: {
|
||||
alias: null,
|
||||
negate: true,
|
||||
disabled: false,
|
||||
type: 'exists',
|
||||
key: 'kibana.alert.building_block_type',
|
||||
value: 'exists',
|
||||
},
|
||||
query: { exists: { field: 'kibana.alert.building_block_type' } },
|
||||
},
|
||||
];
|
||||
|
||||
export const requiredFieldMappingsForActionsRuleRegistry = {
|
||||
'@timestamp': '@timestamp',
|
||||
'event.kind': 'event.kind',
|
||||
'rule.severity': ALERT_RULE_SEVERITY,
|
||||
'rule.risk_score': ALERT_RULE_RISK_SCORE,
|
||||
'alert.uuid': ALERT_UUID,
|
||||
'alert.start': ALERT_START,
|
||||
'event.action': 'event.action',
|
||||
'alert.workflow_status': ALERT_WORKFLOW_STATUS,
|
||||
'alert.duration.us': ALERT_DURATION,
|
||||
'rule.uuid': ALERT_RULE_UUID,
|
||||
'rule.name': ALERT_RULE_NAME,
|
||||
'rule.category': ALERT_RULE_CATEGORY,
|
||||
producer: ALERT_RULE_PRODUCER,
|
||||
tags: 'tags',
|
||||
};
|
||||
|
||||
export const alertsHeadersRuleRegistry: ColumnHeaderOptions[] = Object.entries(
|
||||
requiredFieldMappingsForActionsRuleRegistry
|
||||
).map<ColumnHeaderOptions>(([alias, field]) => ({
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
displayAsText: alias,
|
||||
id: field,
|
||||
}));
|
||||
|
||||
export const alertsDefaultModelRuleRegistry: SubsetTimelineModel = {
|
||||
...timelineDefaults,
|
||||
columns: alertsHeadersRuleRegistry,
|
||||
showCheckboxes: true,
|
||||
excludedRowRendererIds: Object.values(RowRendererId),
|
||||
};
|
||||
|
|
|
@ -40,9 +40,7 @@ import { updateAlertStatusAction } from './actions';
|
|||
import { AditionalFiltersAction, AlertsUtilityBar } from './alerts_utility_bar';
|
||||
import {
|
||||
alertsDefaultModel,
|
||||
alertsDefaultModelRuleRegistry,
|
||||
buildAlertStatusFilter,
|
||||
buildAlertStatusFilterRuleRegistry,
|
||||
requiredFieldsForActions,
|
||||
} from './default_config';
|
||||
import { buildTimeRangeFilter } from './helpers';
|
||||
|
@ -106,8 +104,6 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
const kibana = useKibana();
|
||||
const [, dispatchToaster] = useStateToaster();
|
||||
const { addWarning } = useAppToasts();
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled');
|
||||
const ACTION_BUTTON_COUNT = 4;
|
||||
|
||||
const getGlobalQuery = useCallback(
|
||||
|
@ -247,14 +243,9 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
refetchQuery: inputsModel.Refetch,
|
||||
{ status, selectedStatus }: UpdateAlertsStatusProps
|
||||
) => {
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
const currentStatusFilter = ruleRegistryEnabled
|
||||
? buildAlertStatusFilterRuleRegistry(status)
|
||||
: buildAlertStatusFilter(status);
|
||||
|
||||
await updateAlertStatusAction({
|
||||
query: showClearSelectionAction
|
||||
? getGlobalQuery(currentStatusFilter)?.filterQuery
|
||||
? getGlobalQuery(buildAlertStatusFilter(status))?.filterQuery
|
||||
: undefined,
|
||||
alertIds: Object.keys(selectedEventIds),
|
||||
selectedStatus,
|
||||
|
@ -273,7 +264,6 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
showClearSelectionAction,
|
||||
onAlertStatusUpdateSuccess,
|
||||
onAlertStatusUpdateFailure,
|
||||
ruleRegistryEnabled,
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -327,24 +317,16 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
);
|
||||
|
||||
const defaultFiltersMemo = useMemo(() => {
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
const alertStatusFilter = ruleRegistryEnabled
|
||||
? buildAlertStatusFilterRuleRegistry(filterGroup)
|
||||
: buildAlertStatusFilter(filterGroup);
|
||||
const alertStatusFilter = buildAlertStatusFilter(filterGroup);
|
||||
|
||||
if (isEmpty(defaultFilters)) {
|
||||
return alertStatusFilter;
|
||||
} else if (defaultFilters != null && !isEmpty(defaultFilters)) {
|
||||
return [...defaultFilters, ...alertStatusFilter];
|
||||
}
|
||||
}, [defaultFilters, filterGroup, ruleRegistryEnabled]);
|
||||
}, [defaultFilters, filterGroup]);
|
||||
const { filterManager } = useKibana().services.data.query;
|
||||
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
const defaultTimelineModel = ruleRegistryEnabled
|
||||
? alertsDefaultModelRuleRegistry
|
||||
: alertsDefaultModel;
|
||||
|
||||
const tGridEnabled = useIsExperimentalFeatureEnabled('tGridEnabled');
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -359,7 +341,7 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
: c
|
||||
),
|
||||
documentType: i18n.ALERTS_DOCUMENT_TYPE,
|
||||
excludedRowRendererIds: defaultTimelineModel.excludedRowRendererIds as RowRendererId[],
|
||||
excludedRowRendererIds: alertsDefaultModel.excludedRowRendererIds as RowRendererId[],
|
||||
filterManager,
|
||||
footerText: i18n.TOTAL_COUNT_OF_ALERTS,
|
||||
id: timelineId,
|
||||
|
@ -370,7 +352,7 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
showCheckboxes: true,
|
||||
})
|
||||
);
|
||||
}, [dispatch, defaultTimelineModel, filterManager, tGridEnabled, timelineId]);
|
||||
}, [dispatch, filterManager, tGridEnabled, timelineId]);
|
||||
|
||||
const leadingControlColumns = useMemo(() => getDefaultControlColumn(ACTION_BUTTON_COUNT), []);
|
||||
|
||||
|
@ -383,7 +365,7 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
additionalFilters={additionalFiltersComponent}
|
||||
currentFilter={filterGroup}
|
||||
defaultCellActions={defaultCellActions}
|
||||
defaultModel={defaultTimelineModel}
|
||||
defaultModel={alertsDefaultModel}
|
||||
end={to}
|
||||
entityType="events"
|
||||
hasAlertsCrud={hasIndexWrite && hasIndexMaintenance}
|
||||
|
|
|
@ -24,7 +24,6 @@ import { connect, ConnectedProps, useDispatch } from 'react-redux';
|
|||
import { Dispatch } from 'redux';
|
||||
|
||||
import { Status } from '../../../../common/detection_engine/schemas/common/schemas';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
|
||||
import { isTab } from '../../../../../timelines/public';
|
||||
import { useDeepEqualSelector, useShallowEqualSelector } from '../../../common/hooks/use_selector';
|
||||
import { SecurityPageName } from '../../../app/types';
|
||||
|
@ -61,9 +60,7 @@ import { timelineActions, timelineSelectors } from '../../../timelines/store/tim
|
|||
import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
|
||||
import {
|
||||
buildAlertStatusFilter,
|
||||
buildAlertStatusFilterRuleRegistry,
|
||||
buildShowBuildingBlockFilter,
|
||||
buildShowBuildingBlockFilterRuleRegistry,
|
||||
buildThreatMatchFilter,
|
||||
} from '../../components/alerts_table/default_config';
|
||||
import { useSourcererDataView } from '../../../common/containers/sourcerer';
|
||||
|
@ -115,8 +112,6 @@ const DetectionEnginePageComponent: React.FC<DetectionEngineComponentProps> = ({
|
|||
const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []);
|
||||
const query = useDeepEqualSelector(getGlobalQuerySelector);
|
||||
const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector);
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled');
|
||||
|
||||
const { to, from } = useGlobalTime();
|
||||
const { globalFullScreen } = useGlobalFullScreen();
|
||||
|
@ -187,39 +182,20 @@ const DetectionEnginePageComponent: React.FC<DetectionEngineComponentProps> = ({
|
|||
const alertsHistogramDefaultFilters = useMemo(
|
||||
() => [
|
||||
...filters,
|
||||
...(ruleRegistryEnabled
|
||||
? [
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
...buildShowBuildingBlockFilterRuleRegistry(showBuildingBlockAlerts),
|
||||
...buildAlertStatusFilterRuleRegistry(filterGroup),
|
||||
]
|
||||
: [
|
||||
...buildShowBuildingBlockFilter(showBuildingBlockAlerts),
|
||||
...buildAlertStatusFilter(filterGroup),
|
||||
]),
|
||||
...buildShowBuildingBlockFilter(showBuildingBlockAlerts),
|
||||
...buildAlertStatusFilter(filterGroup),
|
||||
...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts),
|
||||
],
|
||||
[
|
||||
filters,
|
||||
ruleRegistryEnabled,
|
||||
showBuildingBlockAlerts,
|
||||
showOnlyThreatIndicatorAlerts,
|
||||
filterGroup,
|
||||
]
|
||||
[filters, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts, filterGroup]
|
||||
);
|
||||
|
||||
// AlertsTable manages global filters itself, so not including `filters`
|
||||
const alertsTableDefaultFilters = useMemo(
|
||||
() => [
|
||||
...(ruleRegistryEnabled
|
||||
? [
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
...buildShowBuildingBlockFilterRuleRegistry(showBuildingBlockAlerts),
|
||||
]
|
||||
: [...buildShowBuildingBlockFilter(showBuildingBlockAlerts)]),
|
||||
...buildShowBuildingBlockFilter(showBuildingBlockAlerts),
|
||||
...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts),
|
||||
],
|
||||
[ruleRegistryEnabled, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts]
|
||||
[showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts]
|
||||
);
|
||||
|
||||
const onShowBuildingBlockAlertsChangedCallback = useCallback(
|
||||
|
|
|
@ -63,11 +63,9 @@ import { useUserData } from '../../../../components/user_info';
|
|||
import { StepDefineRule } from '../../../../components/rules/step_define_rule';
|
||||
import { StepScheduleRule } from '../../../../components/rules/step_schedule_rule';
|
||||
import {
|
||||
buildAlertsRuleIdFilter,
|
||||
buildAlertsFilter,
|
||||
buildAlertStatusFilter,
|
||||
buildAlertStatusFilterRuleRegistry,
|
||||
buildShowBuildingBlockFilter,
|
||||
buildShowBuildingBlockFilterRuleRegistry,
|
||||
buildThreatMatchFilter,
|
||||
} from '../../../../components/alerts_table/default_config';
|
||||
import { RuleSwitch } from '../../../../components/rules/rule_switch';
|
||||
|
@ -250,9 +248,6 @@ const RuleDetailsPageComponent: React.FC<DetectionEngineComponentProps> = ({
|
|||
const { globalFullScreen } = useGlobalFullScreen();
|
||||
const [filterGroup, setFilterGroup] = useState<Status>(FILTER_OPEN);
|
||||
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled');
|
||||
|
||||
// TODO: Steph/ueba remove when past experimental
|
||||
const uebaEnabled = useIsExperimentalFeatureEnabled('uebaEnabled');
|
||||
|
||||
|
@ -416,39 +411,21 @@ const RuleDetailsPageComponent: React.FC<DetectionEngineComponentProps> = ({
|
|||
|
||||
const alertDefaultFilters = useMemo(
|
||||
() => [
|
||||
...buildAlertsRuleIdFilter(ruleId),
|
||||
...(ruleRegistryEnabled
|
||||
? [
|
||||
...buildShowBuildingBlockFilterRuleRegistry(showBuildingBlockAlerts), // TODO: Once we are past experimental phase this code should be removed
|
||||
...buildAlertStatusFilterRuleRegistry(filterGroup),
|
||||
]
|
||||
: [
|
||||
...buildShowBuildingBlockFilter(showBuildingBlockAlerts),
|
||||
...buildAlertStatusFilter(filterGroup),
|
||||
]),
|
||||
...buildAlertsFilter(rule?.rule_id ?? ''),
|
||||
...buildShowBuildingBlockFilter(showBuildingBlockAlerts),
|
||||
...buildAlertStatusFilter(filterGroup),
|
||||
...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts),
|
||||
],
|
||||
[
|
||||
ruleId,
|
||||
ruleRegistryEnabled,
|
||||
showBuildingBlockAlerts,
|
||||
showOnlyThreatIndicatorAlerts,
|
||||
filterGroup,
|
||||
]
|
||||
[rule, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts, filterGroup]
|
||||
);
|
||||
|
||||
const alertsTableDefaultFilters = useMemo(
|
||||
() => [
|
||||
...buildAlertsRuleIdFilter(ruleId),
|
||||
...(ruleRegistryEnabled
|
||||
? [
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
...buildShowBuildingBlockFilterRuleRegistry(showBuildingBlockAlerts),
|
||||
]
|
||||
: [...buildShowBuildingBlockFilter(showBuildingBlockAlerts)]),
|
||||
...buildAlertsFilter(rule?.rule_id ?? ''),
|
||||
...buildShowBuildingBlockFilter(showBuildingBlockAlerts),
|
||||
...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts),
|
||||
],
|
||||
[ruleId, ruleRegistryEnabled, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts]
|
||||
[rule, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts]
|
||||
);
|
||||
|
||||
const alertMergedFilters = useMemo(
|
||||
|
|
|
@ -8,11 +8,7 @@
|
|||
import { useMemo } from 'react';
|
||||
import type { Filter } from '@kbn/es-query';
|
||||
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
|
||||
import {
|
||||
buildShowBuildingBlockFilter,
|
||||
buildShowBuildingBlockFilterRuleRegistry,
|
||||
} from '../../../detections/components/alerts_table/default_config';
|
||||
import { buildShowBuildingBlockFilter } from '../../../detections/components/alerts_table/default_config';
|
||||
|
||||
// On the Overview page, in the Detection Alert Trend, we never show
|
||||
// "building block" alerts to remove noise from the Overview UI.
|
||||
|
@ -20,17 +16,9 @@ import {
|
|||
const SHOW_BUILDING_BLOCK_ALERTS = false;
|
||||
|
||||
export const useFiltersForSignalsByCategory = (baseFilters: Filter[]) => {
|
||||
// TODO: Once we are past experimental phase this code should be removed
|
||||
const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled');
|
||||
|
||||
const resultingFilters = useMemo(
|
||||
() => [
|
||||
...baseFilters,
|
||||
...(ruleRegistryEnabled
|
||||
? buildShowBuildingBlockFilterRuleRegistry(SHOW_BUILDING_BLOCK_ALERTS) // TODO: Once we are past experimental phase this code should be removed
|
||||
: buildShowBuildingBlockFilter(SHOW_BUILDING_BLOCK_ALERTS)),
|
||||
],
|
||||
[baseFilters, ruleRegistryEnabled]
|
||||
() => [...baseFilters, ...buildShowBuildingBlockFilter(SHOW_BUILDING_BLOCK_ALERTS)],
|
||||
[baseFilters]
|
||||
);
|
||||
|
||||
return resultingFilters;
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
getAlertMock,
|
||||
getRuleExecutionStatusSucceeded,
|
||||
getRuleExecutionStatusFailed,
|
||||
resolveAlertMock,
|
||||
} from '../__mocks__/request_responses';
|
||||
import { serverMock, requestContextMock, requestMock } from '../__mocks__';
|
||||
import { findRuleStatusInternalRoute } from './find_rule_status_internal_route';
|
||||
|
@ -38,6 +39,9 @@ describe.each([
|
|||
clients.rulesClient.get.mockResolvedValue(
|
||||
getAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
|
||||
);
|
||||
clients.rulesClient.resolve.mockResolvedValue(
|
||||
resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
|
||||
);
|
||||
|
||||
findRuleStatusInternalRoute(server.router);
|
||||
});
|
||||
|
@ -70,7 +74,7 @@ describe.each([
|
|||
test('returns success if rule status client writes an error status', async () => {
|
||||
// 0. task manager tried to run the rule but couldn't, so the alerting framework
|
||||
// wrote an error to the executionStatus.
|
||||
const failingExecutionRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
|
||||
const failingExecutionRule = resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
|
||||
failingExecutionRule.executionStatus = {
|
||||
status: 'error',
|
||||
lastExecutionDate: failingExecutionRule.executionStatus.lastExecutionDate,
|
||||
|
@ -81,7 +85,7 @@ describe.each([
|
|||
};
|
||||
|
||||
// 1. getFailingRules api found a rule where the executionStatus was 'error'
|
||||
clients.rulesClient.get.mockResolvedValue({
|
||||
clients.rulesClient.resolve.mockResolvedValue({
|
||||
...failingExecutionRule,
|
||||
});
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
} from './utils';
|
||||
import { responseMock } from './__mocks__';
|
||||
import { exampleRuleStatus } from '../signals/__mocks__/es_results';
|
||||
import { getAlertMock } from './__mocks__/request_responses';
|
||||
import { resolveAlertMock } from './__mocks__/request_responses';
|
||||
import { AlertExecutionStatusErrorReasons } from '../../../../../alerting/common';
|
||||
import { getQueryRuleParams } from '../schemas/rule_schemas.mock';
|
||||
import { RuleExecutionStatus } from '../../../../common/detection_engine/schemas/common/schemas';
|
||||
|
@ -223,12 +223,14 @@ describe.each([
|
|||
rulesClient = rulesClientMock.create();
|
||||
});
|
||||
it('getFailingRules finds no failing rules', async () => {
|
||||
rulesClient.get.mockResolvedValue(getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()));
|
||||
rulesClient.resolve.mockResolvedValue(
|
||||
resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams())
|
||||
);
|
||||
const res = await getFailingRules(['my-fake-id'], rulesClient);
|
||||
expect(res).toEqual({});
|
||||
});
|
||||
it('getFailingRules finds a failing rule', async () => {
|
||||
const foundRule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
|
||||
const foundRule = resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
|
||||
foundRule.executionStatus = {
|
||||
status: 'error',
|
||||
lastExecutionDate: foundRule.executionStatus.lastExecutionDate,
|
||||
|
@ -237,12 +239,12 @@ describe.each([
|
|||
message: 'oops',
|
||||
},
|
||||
};
|
||||
rulesClient.get.mockResolvedValue(foundRule);
|
||||
rulesClient.resolve.mockResolvedValue(foundRule);
|
||||
const res = await getFailingRules([foundRule.id], rulesClient);
|
||||
expect(res).toEqual({ [foundRule.id]: foundRule });
|
||||
});
|
||||
it('getFailingRules throws an error', async () => {
|
||||
rulesClient.get.mockImplementation(() => {
|
||||
rulesClient.resolve.mockImplementation(() => {
|
||||
throw new Error('my test error');
|
||||
});
|
||||
let error;
|
||||
|
|
|
@ -238,7 +238,7 @@ export const getFailingRules = async (
|
|||
try {
|
||||
const errorRules = await Promise.all(
|
||||
ids.map(async (id) =>
|
||||
rulesClient.get({
|
||||
rulesClient.resolve({
|
||||
id,
|
||||
})
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue