Skip to content

Commit

Permalink
[Security Solution][Detection Engine] Remove RuleTypeSchema in favor …
Browse files Browse the repository at this point in the history
…of Type for TypeScript (#76586)

## Summary

Removes RuleTypeSchema in favor of Type for TypeScript. Does break out one function called `parseScheduleDates` into its own file to remove a circular ref issue.
  • Loading branch information
FrankHassanabad authored Sep 3, 2020
1 parent aab8d3c commit 2f017b0
Show file tree
Hide file tree
Showing 20 changed files with 77 additions and 80 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import moment from 'moment';
import dateMath from '@elastic/datemath';

export const parseScheduleDates = (time: string): moment.Moment | null => {
const isValidDateString = !isNaN(Date.parse(time));
const isValidInput = isValidDateString || time.trim().startsWith('now');
const formattedDate = isValidDateString
? moment(time)
: isValidInput
? dateMath.parse(time)
: null;

return formattedDate ?? null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { UUID } from '../types/uuid';
import { IsoDateString } from '../types/iso_date_string';
import { PositiveIntegerGreaterThanZero } from '../types/positive_integer_greater_than_zero';
import { PositiveInteger } from '../types/positive_integer';
import { parseScheduleDates } from '../../utils';
import { parseScheduleDates } from '../../parse_schedule_dates';

export const author = t.array(t.string);
export type Author = t.TypeOf<typeof author>;
Expand Down
10 changes: 0 additions & 10 deletions x-pack/plugins/security_solution/common/detection_engine/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,8 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as t from 'io-ts';

import { AlertAction } from '../../../alerts/common';

export type RuleAlertAction = Omit<AlertAction, 'actionTypeId'> & {
action_type_id: string;
};

export const RuleTypeSchema = t.keyof({
query: null,
saved_query: null,
machine_learning: null,
threshold: null,
});
export type RuleType = t.TypeOf<typeof RuleTypeSchema>;
19 changes: 2 additions & 17 deletions x-pack/plugins/security_solution/common/detection_engine/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

import moment from 'moment';
import dateMath from '@elastic/datemath';

import { EntriesArray } from '../shared_imports';
import { RuleType } from './types';
import { Type } from './schemas/common/schemas';

export const hasLargeValueList = (entries: EntriesArray): boolean => {
const found = entries.filter(({ type }) => type === 'list');
Expand All @@ -20,16 +17,4 @@ export const hasNestedEntry = (entries: EntriesArray): boolean => {
return found.length > 0;
};

export const isThresholdRule = (ruleType: RuleType) => ruleType === 'threshold';

export const parseScheduleDates = (time: string): moment.Moment | null => {
const isValidDateString = !isNaN(Date.parse(time));
const isValidInput = isValidDateString || time.trim().startsWith('now');
const formattedDate = isValidDateString
? moment(time)
: isValidInput
? dateMath.parse(time)
: null;

return formattedDate ?? null;
};
export const isThresholdRule = (ruleType: Type) => ruleType === 'threshold';
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { RuleType } from '../detection_engine/types';
import { Type } from '../detection_engine/schemas/common/schemas';

// Based on ML Job/Datafeed States from x-pack/legacy/plugins/ml/common/constants/states.js
const enabledStates = ['started', 'opened'];
Expand All @@ -23,4 +23,4 @@ export const isJobFailed = (jobState: string, datafeedState: string): boolean =>
return failureStates.includes(jobState) || failureStates.includes(datafeedState);
};

export const isMlRule = (ruleType: RuleType) => ruleType === 'machine_learning';
export const isMlRule = (ruleType: Type) => ruleType === 'machine_learning';
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ import styled from 'styled-components';

import { TimelineId } from '../../../../../common/types/timeline';
import { DEFAULT_INDEX_PATTERN } from '../../../../../common/constants';
import { Status } from '../../../../../common/detection_engine/schemas/common/schemas';
import { Status, Type } from '../../../../../common/detection_engine/schemas/common/schemas';
import { isThresholdRule } from '../../../../../common/detection_engine/utils';
import { RuleType } from '../../../../../common/detection_engine/types';
import { isMlRule } from '../../../../../common/machine_learning/helpers';
import { timelineActions } from '../../../../timelines/store/timeline';
import { EventsTd, EventsTdContent } from '../../../../timelines/components/timeline/styles';
Expand Down Expand Up @@ -409,7 +408,7 @@ const AlertContextMenuComponent: React.FC<AlertContextMenuProps> = ({
data: nonEcsRowData,
fieldName: 'signal.rule.type',
});
const [ruleType] = ruleTypes as RuleType[];
const [ruleType] = ruleTypes as Type[];
return !isMlRule(ruleType) && !isThresholdRule(ruleType);
}, [nonEcsRowData]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import styled from 'styled-components';
import { assertUnreachable } from '../../../../../common/utility_types';
import * as i18nSeverity from '../severity_mapping/translations';
import * as i18nRiskScore from '../risk_score_mapping/translations';
import { Threshold } from '../../../../../common/detection_engine/schemas/common/schemas';
import { RuleType } from '../../../../../common/detection_engine/types';
import { Threshold, Type } from '../../../../../common/detection_engine/schemas/common/schemas';
import { esFilters } from '../../../../../../../../src/plugins/data/public';

import { tacticsOptions, techniquesOptions } from '../../../mitre/mitre_tactics_techniques';
Expand Down Expand Up @@ -357,7 +356,7 @@ export const buildNoteDescription = (label: string, note: string): ListItems[] =
return [];
};

export const buildRuleTypeDescription = (label: string, ruleType: RuleType): ListItems[] => {
export const buildRuleTypeDescription = (label: string, ruleType: Type): ListItems[] => {
switch (ruleType) {
case 'machine_learning': {
return [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { isEmpty, chunk, get, pick, isNumber } from 'lodash/fp';
import React, { memo, useState } from 'react';
import styled from 'styled-components';

import { RuleType } from '../../../../../common/detection_engine/types';
import {
IIndexPattern,
Filter,
Expand Down Expand Up @@ -42,6 +41,7 @@ import { useSecurityJobs } from '../../../../common/components/ml_popover/hooks/
import { buildMlJobDescription } from './ml_job_description';
import { buildActionsDescription } from './actions_description';
import { buildThrottleDescription } from './throttle_description';
import { Type } from '../../../../../common/detection_engine/schemas/common/schemas';

const DescriptionListContainer = styled(EuiDescriptionList)`
&.euiDescriptionList--column .euiDescriptionList__title {
Expand Down Expand Up @@ -211,7 +211,7 @@ export const getDescriptionItem = (
const val: string = get(field, data);
return buildNoteDescription(label, val);
} else if (field === 'ruleType') {
const ruleType: RuleType = get(field, data);
const ruleType: Type = get(field, data);
return buildRuleTypeDescription(label, ruleType);
} else if (field === 'kibanaSiemAppUrl') {
return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import { EuiCard, EuiFlexGrid, EuiFlexItem, EuiFormRow, EuiIcon } from '@elastic

import { isMlRule } from '../../../../../common/machine_learning/helpers';
import { isThresholdRule } from '../../../../../common/detection_engine/utils';
import { RuleType } from '../../../../../common/detection_engine/types';
import { FieldHook } from '../../../../shared_imports';
import { useKibana } from '../../../../common/lib/kibana';
import * as i18n from './translations';
import { MlCardDescription } from './ml_card_description';
import { Type } from '../../../../../common/detection_engine/schemas/common/schemas';

interface SelectRuleTypeProps {
describedByIds?: string[];
Expand All @@ -30,9 +30,9 @@ export const SelectRuleType: React.FC<SelectRuleTypeProps> = ({
hasValidLicense = false,
isMlAdmin = false,
}) => {
const ruleType = field.value as RuleType;
const ruleType = field.value as Type;
const setType = useCallback(
(type: RuleType) => {
(type: Type) => {
field.setValue(type);
},
[field]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import * as t from 'io-ts';

import { RuleTypeSchema } from '../../../../../common/detection_engine/types';
import {
author,
building_block_type,
Expand All @@ -16,6 +15,7 @@ import {
severity_mapping,
timestamp_override,
threshold,
type,
} from '../../../../../common/detection_engine/schemas/common/schemas';
import {
listArray,
Expand Down Expand Up @@ -44,7 +44,7 @@ export const NewRuleSchema = t.intersection([
name: t.string,
risk_score: t.number,
severity: t.string,
type: RuleTypeSchema,
type,
}),
t.partial({
actions: t.array(action),
Expand Down Expand Up @@ -117,7 +117,7 @@ export const RuleSchema = t.intersection([
severity: t.string,
severity_mapping,
tags: t.array(t.string),
type: RuleTypeSchema,
type,
to: t.string,
threat: t.array(t.unknown),
updated_at: t.string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import deepmerge from 'deepmerge';

import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../../../common/constants';
import { transformAlertToRuleAction } from '../../../../../../common/detection_engine/transform_actions';
import { RuleType } from '../../../../../../common/detection_engine/types';
import { isMlRule } from '../../../../../../common/machine_learning/helpers';
import { isThresholdRule } from '../../../../../../common/detection_engine/utils';
import { List } from '../../../../../../common/detection_engine/schemas/types';
import { ENDPOINT_LIST_ID } from '../../../../../shared_imports';
import { NewRule, Rule } from '../../../../containers/detection_engine/rules';
import { Type } from '../../../../../../common/detection_engine/schemas/common/schemas';

import {
AboutStepRule,
Expand Down Expand Up @@ -68,7 +68,7 @@ const isThresholdFields = <T>(
fields: QueryRuleFields<T> | MlRuleFields<T> | ThresholdRuleFields<T>
): fields is ThresholdRuleFields<T> => has('threshold', fields);

export const filterRuleFieldsForType = <T extends RuleFields>(fields: T, type: RuleType) => {
export const filterRuleFieldsForType = <T extends RuleFields>(fields: T, type: Type) => {
if (isMlRule(type)) {
const { index, queryBar, threshold, ...mlRuleFields } = fields;
return mlRuleFields;
Expand Down Expand Up @@ -119,7 +119,7 @@ export const formatDefineStepData = (defineStepData: DefineStepRule): DefineStep
query: ruleFields.queryBar?.query?.query as string,
saved_id: ruleFields.queryBar?.saved_id,
...(ruleType === 'query' &&
ruleFields.queryBar?.saved_id && { type: 'saved_query' as RuleType }),
ruleFields.queryBar?.saved_id && { type: 'saved_query' as Type }),
};

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import memoizeOne from 'memoize-one';
import { useLocation } from 'react-router-dom';

import { ActionVariable } from '../../../../../../triggers_actions_ui/public';
import { RuleAlertAction, RuleType } from '../../../../../common/detection_engine/types';
import { RuleAlertAction } from '../../../../../common/detection_engine/types';
import { isMlRule } from '../../../../../common/machine_learning/helpers';
import { transformRuleToAlertAction } from '../../../../../common/detection_engine/transform_actions';
import { Filter } from '../../../../../../../../src/plugins/data/public';
Expand All @@ -24,7 +24,10 @@ import {
ScheduleStepRule,
ActionsStepRule,
} from './types';
import { SeverityMapping } from '../../../../../common/detection_engine/schemas/common/schemas';
import {
SeverityMapping,
Type,
} from '../../../../../common/detection_engine/schemas/common/schemas';
import { severityOptions } from '../../../components/rules/step_about_rule/data';

export interface GetStepsData {
Expand Down Expand Up @@ -307,7 +310,7 @@ export const redirectToDetections = (
hasEncryptionKey === false ||
needsListsConfiguration;

const getRuleSpecificRuleParamKeys = (ruleType: RuleType) => {
const getRuleSpecificRuleParamKeys = (ruleType: Type) => {
const queryRuleParams = ['index', 'filters', 'language', 'query', 'saved_id'];

if (isMlRule(ruleType)) {
Expand All @@ -321,7 +324,7 @@ const getRuleSpecificRuleParamKeys = (ruleType: RuleType) => {
return queryRuleParams;
};

export const getActionMessageRuleParams = (ruleType: RuleType): string[] => {
export const getActionMessageRuleParams = (ruleType: Type): string[] => {
const commonRuleParamsKeys = [
'id',
'name',
Expand Down Expand Up @@ -349,23 +352,21 @@ export const getActionMessageRuleParams = (ruleType: RuleType): string[] => {
return ruleParamsKeys;
};

export const getActionMessageParams = memoizeOne(
(ruleType: RuleType | undefined): ActionVariable[] => {
if (!ruleType) {
return [];
}
const actionMessageRuleParams = getActionMessageRuleParams(ruleType);

return [
{ name: 'state.signals_count', description: 'state.signals_count' },
{ name: '{context.results_link}', description: 'context.results_link' },
...actionMessageRuleParams.map((param) => {
const extendedParam = `context.rule.${param}`;
return { name: extendedParam, description: extendedParam };
}),
];
export const getActionMessageParams = memoizeOne((ruleType: Type | undefined): ActionVariable[] => {
if (!ruleType) {
return [];
}
);
const actionMessageRuleParams = getActionMessageRuleParams(ruleType);

return [
{ name: 'state.signals_count', description: 'state.signals_count' },
{ name: '{context.results_link}', description: 'context.results_link' },
...actionMessageRuleParams.map((param) => {
const extendedParam = `context.rule.${param}`;
return { name: extendedParam, description: extendedParam };
}),
];
});

// typed as null not undefined as the initial state for this value is null.
export const userHasNoPermissions = (canUserCRUD: boolean | null): boolean =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { RuleAlertAction, RuleType } from '../../../../../common/detection_engine/types';
import { RuleAlertAction } from '../../../../../common/detection_engine/types';
import { AlertAction } from '../../../../../../alerts/common';
import { Filter } from '../../../../../../../../src/plugins/data/common';
import { FormData, FormHook } from '../../../../shared_imports';
Expand All @@ -19,6 +19,7 @@ import {
RuleNameOverride,
SeverityMapping,
TimestampOverride,
Type,
} from '../../../../../common/detection_engine/schemas/common/schemas';
import { List } from '../../../../../common/detection_engine/schemas/types';

Expand Down Expand Up @@ -102,7 +103,7 @@ export interface DefineStepRule extends StepRuleData {
index: string[];
machineLearningJobId: string;
queryBar: FieldValueQueryBar;
ruleType: RuleType;
ruleType: Type;
timeline: FieldValueTimeline;
threshold: FieldValueThreshold;
}
Expand Down Expand Up @@ -134,7 +135,7 @@ export interface DefineStepRuleJson {
};
timeline_id?: string;
timeline_title?: string;
type: RuleType;
type: Type;
}

export interface AboutStepRuleJson {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { RuleAlertAttributes } from '../signals/types';
import { siemRuleActionGroups } from '../signals/siem_rule_action_groups';
import { scheduleNotificationActions } from './schedule_notification_actions';
import { getNotificationResultsLink } from './utils';
import { parseScheduleDates } from '../../../../common/detection_engine/utils';
import { parseScheduleDates } from '../../../../common/detection_engine/parse_schedule_dates';

export const rulesNotificationAlertType = ({
logger,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
getExceptions,
sortExceptionItems,
} from './utils';
import { parseScheduleDates } from '../../../../common/detection_engine/utils';
import { parseScheduleDates } from '../../../../common/detection_engine/parse_schedule_dates';
import { RuleExecutorOptions } from './types';
import { searchAfterAndBulkCreate } from './search_after_bulk_create';
import { scheduleNotificationActions } from '../notifications/schedule_notification_actions';
Expand All @@ -38,6 +38,7 @@ jest.mock('../notifications/schedule_notification_actions');
jest.mock('./find_ml_signals');
jest.mock('./bulk_create_ml_signals');
jest.mock('./../../../../common/detection_engine/utils');
jest.mock('../../../../common/detection_engine/parse_schedule_dates');

const getPayload = (ruleAlert: RuleAlertType, services: AlertServicesMock) => ({
alertId: ruleAlert.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
SERVER_APP_ID,
} from '../../../../common/constants';
import { isJobStarted, isMlRule } from '../../../../common/machine_learning/helpers';
import { parseScheduleDates } from '../../../../common/detection_engine/utils';
import { parseScheduleDates } from '../../../../common/detection_engine/parse_schedule_dates';
import { SetupPlugins } from '../../../plugin';
import { getInputIndex } from './get_input_output_index';
import {
Expand Down
Loading

0 comments on commit 2f017b0

Please sign in to comment.