[SEIM][Detection Engine] Moves the io-ts schemas to the common folder from the server side

## Summary

This moves the io-ts schemas from the common folder from the server side up to the common folder.

### Checklist

- [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios
This commit is contained in:
Frank Hassanabad 2020-06-01 16:30:28 -06:00 committed by GitHub
parent 571b3de667
commit 0dca28b6dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 333 additions and 535 deletions

View file

@ -9,19 +9,10 @@ import { pipe } from 'fp-ts/lib/pipeable';
import { getErrorPayload } from './__mocks__/utils';
import { errorSchema, ErrorSchema } from './error_schema';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags';
import { exactCheck } from '../../../../../../common/exact_check';
import { getPaths, foldLeftRight } from '../../../../../../common/test_utils';
import { exactCheck } from '../../../exact_check';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('error_schema', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
test('it should validate an error with a UUID given for id', () => {
const error = getErrorPayload();
const decoded = errorSchema.decode(getErrorPayload());

View file

@ -7,7 +7,7 @@
import * as t from 'io-ts';
/* eslint-disable @typescript-eslint/camelcase */
import { rule_id, status_code, message } from './schemas';
import { rule_id, status_code, message } from '../common/schemas';
/* eslint-enable @typescript-eslint/camelcase */
// We use id: t.string intentionally and _never_ the id from global schemas as

View file

@ -9,19 +9,10 @@ import { pipe } from 'fp-ts/lib/pipeable';
import { getFindResponseSingle, getBaseResponsePayload } from './__mocks__/utils';
import { left } from 'fp-ts/lib/Either';
import { RulesSchema } from './rules_schema';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags';
import { getPaths, foldLeftRight } from '../../../../../../common/test_utils';
import { exactCheck } from '../../../../../../common/exact_check';
import { exactCheck } from '../../../exact_check';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('find_rules_schema', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
test('it should validate a typical single find rules response', () => {
const payload = getFindResponseSingle();
const decoded = findRulesSchema.decode(payload);

View file

@ -7,7 +7,7 @@
import * as t from 'io-ts';
import { rulesSchema } from './rules_schema';
import { page, perPage, total } from './schemas';
import { page, perPage, total } from '../common/schemas';
export const findRulesSchema = t.exact(
t.type({

View file

@ -8,20 +8,11 @@ import { pipe } from 'fp-ts/lib/pipeable';
import { left, Either } from 'fp-ts/lib/Either';
import { ImportRulesSchema, importRulesSchema } from './import_rules_schema';
import { ErrorSchema } from './error_schema';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags';
import { Errors } from 'io-ts';
import { exactCheck } from '../../../../../../common/exact_check';
import { foldLeftRight, getPaths } from '../../../../../../common/test_utils';
import { exactCheck } from '../../../exact_check';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('import_rules_schema', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
test('it should validate an empty import response with no errors', () => {
const payload: ImportRulesSchema = { success: true, success_count: 0, errors: [] };
const decoded = importRulesSchema.decode(payload);

View file

@ -7,7 +7,7 @@
import * as t from 'io-ts';
/* eslint-disable @typescript-eslint/camelcase */
import { success, success_count } from './schemas';
import { success, success_count } from '../common/schemas';
import { errorSchema } from './error_schema';
/* eslint-enable @typescript-eslint/camelcase */

View file

@ -7,19 +7,10 @@
import { pipe } from 'fp-ts/lib/pipeable';
import { left } from 'fp-ts/lib/Either';
import { PrePackagedRulesSchema, prePackagedRulesSchema } from './prepackaged_rules_schema';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags';
import { exactCheck } from '../../../../../../common/exact_check';
import { getPaths, foldLeftRight } from '../../../../../../common/test_utils';
import { exactCheck } from '../../../exact_check';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('prepackaged_rules_schema', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
test('it should validate an empty prepackaged response with defaults', () => {
const payload: PrePackagedRulesSchema = { rules_installed: 0, rules_updated: 0 };
const decoded = prePackagedRulesSchema.decode(payload);

View file

@ -7,7 +7,7 @@
import * as t from 'io-ts';
/* eslint-disable @typescript-eslint/camelcase */
import { rules_installed, rules_updated } from './schemas';
import { rules_installed, rules_updated } from '../common/schemas';
/* eslint-enable @typescript-eslint/camelcase */
export const prePackagedRulesSchema = t.exact(

View file

@ -10,19 +10,10 @@ import {
PrePackagedRulesStatusSchema,
prePackagedRulesStatusSchema,
} from './prepackaged_rules_status_schema';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags';
import { exactCheck } from '../../../../../../common/exact_check';
import { foldLeftRight, getPaths } from '../../../../../../common/test_utils';
import { exactCheck } from '../../../exact_check';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('prepackaged_rules_schema', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
test('it should validate an empty prepackaged response with defaults', () => {
const payload: PrePackagedRulesStatusSchema = {
rules_installed: 0,

View file

@ -12,7 +12,7 @@ import {
rules_custom_installed,
rules_not_installed,
rules_not_updated,
} from './schemas';
} from '../common/schemas';
/* eslint-enable @typescript-eslint/camelcase */
export const prePackagedRulesStatusSchema = t.exact(

View file

@ -11,19 +11,10 @@ import { getBaseResponsePayload, getErrorPayload } from './__mocks__/utils';
import { RulesBulkSchema, rulesBulkSchema } from './rules_bulk_schema';
import { RulesSchema } from './rules_schema';
import { ErrorSchema } from './error_schema';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags';
import { exactCheck } from '../../../../../../common/exact_check';
import { foldLeftRight, getPaths } from '../../../../../../common/test_utils';
import { exactCheck } from '../../../exact_check';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('prepackaged_rule_schema', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
test('it should validate a regular message and and error together with a uuid', () => {
const payload: RulesBulkSchema = [getBaseResponsePayload(), getErrorPayload()];
const decoded = rulesBulkSchema.decode(payload);

View file

@ -4,32 +4,209 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { left } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import * as t from 'io-ts';
import {
rulesSchema,
RulesSchema,
checkTypeDependents,
getDependents,
addSavedId,
addTimelineTitle,
addQueryFields,
addTimelineTitle,
addMlFields,
} from './check_type_dependents';
} from './rules_schema';
import { getBaseResponsePayload, getMlRuleResponsePayload } from './__mocks__/utils';
import { left } from 'fp-ts/lib/Either';
import { RulesSchema } from './rules_schema';
import { exactCheck } from '../../../exact_check';
import { foldLeftRight, getPaths } from '../../../test_utils';
import { TypeAndTimelineOnly } from './type_timeline_only_schema';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags';
import { exactCheck } from '../../../../../../common/exact_check';
import { foldLeftRight, getPaths } from '../../../../../../common/test_utils';
describe('check_type_dependents', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
export const ANCHOR_DATE = '2020-02-20T03:57:54.037Z';
describe('rules_schema', () => {
test('it should validate a type of "query" without anything extra', () => {
const payload = getBaseResponsePayload();
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
const expected = getBaseResponsePayload();
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(expected);
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
test('it should NOT validate a type of "query" when it has extra data', () => {
const payload: RulesSchema & { invalid_extra_data?: string } = getBaseResponsePayload();
payload.invalid_extra_data = 'invalid_extra_data';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']);
expect(message.schema).toEqual({});
});
test('it should NOT validate invalid_data for the type', () => {
const payload: Omit<RulesSchema, 'type'> & { type: string } = getBaseResponsePayload();
payload.type = 'invalid_data';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "invalid_data" supplied to "type"',
]);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "query" with a saved_id together', () => {
const payload = getBaseResponsePayload();
payload.type = 'query';
payload.saved_id = 'save id 123';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "saved_id"']);
expect(message.schema).toEqual({});
});
test('it should validate a type of "saved_query" with a "saved_id" dependent', () => {
const payload = getBaseResponsePayload();
payload.type = 'saved_query';
payload.saved_id = 'save id 123';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
const expected = getBaseResponsePayload();
expected.type = 'saved_query';
expected.saved_id = 'save id 123';
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(expected);
});
test('it should NOT validate a type of "saved_query" without a "saved_id" dependent', () => {
const payload = getBaseResponsePayload();
payload.type = 'saved_query';
delete payload.saved_id;
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "undefined" supplied to "saved_id"',
]);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "saved_query" when it has extra data', () => {
const payload: RulesSchema & { invalid_extra_data?: string } = getBaseResponsePayload();
payload.type = 'saved_query';
payload.saved_id = 'save id 123';
payload.invalid_extra_data = 'invalid_extra_data';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']);
expect(message.schema).toEqual({});
});
test('it should validate a type of "timeline_id" if there is a "timeline_title" dependent', () => {
const payload = getBaseResponsePayload();
payload.timeline_id = 'some timeline id';
payload.timeline_title = 'some timeline title';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
const expected = getBaseResponsePayload();
expected.timeline_id = 'some timeline id';
expected.timeline_title = 'some timeline title';
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(expected);
});
test('it should NOT validate a type of "timeline_id" if there is "timeline_title" dependent when it has extra invalid data', () => {
const payload: RulesSchema & { invalid_extra_data?: string } = getBaseResponsePayload();
payload.timeline_id = 'some timeline id';
payload.timeline_title = 'some timeline title';
payload.invalid_extra_data = 'invalid_extra_data';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "timeline_id" if there is NOT a "timeline_title" dependent', () => {
const payload = getBaseResponsePayload();
payload.timeline_id = 'some timeline id';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "undefined" supplied to "timeline_title"',
]);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "timeline_title" if there is NOT a "timeline_id" dependent', () => {
const payload = getBaseResponsePayload();
payload.timeline_title = 'some timeline title';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "timeline_title"']);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "saved_query" with a "saved_id" dependent and a "timeline_title" but there is NOT a "timeline_id"', () => {
const payload = getBaseResponsePayload();
payload.saved_id = 'some saved id';
payload.type = 'saved_query';
payload.timeline_title = 'some timeline title';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "timeline_title"']);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "saved_query" with a "saved_id" dependent and a "timeline_id" but there is NOT a "timeline_title"', () => {
const payload = getBaseResponsePayload();
payload.saved_id = 'some saved id';
payload.type = 'saved_query';
payload.timeline_id = 'some timeline id';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "undefined" supplied to "timeline_title"',
]);
expect(message.schema).toEqual({});
});
describe('checkTypeDependents', () => {

View file

@ -7,10 +7,11 @@
/* eslint-disable @typescript-eslint/camelcase */
import * as t from 'io-ts';
import { isObject } from 'lodash/fp';
import { Either, fold, right, left } from 'fp-ts/lib/Either';
import { Either, left, fold } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import { checkTypeDependents } from './check_type_dependents';
import { typeAndTimelineOnlySchema, TypeAndTimelineOnly } from './type_timeline_only_schema';
import { isMlRule } from '../../../machine_learning/helpers';
import {
actions,
anomaly_threshold,
@ -54,9 +55,8 @@ import {
filters,
meta,
note,
} from './schemas';
} from '../common/schemas';
import { ListsDefaultArray } from '../types/lists_default_array';
import { hasListsFeature } from '../../../feature_flags';
/**
* This is the required fields for the rules schema response. Put all required properties on
@ -155,32 +155,92 @@ export const rulesSchema = new t.Type<
'RulesSchema',
(input: unknown): input is RulesWithoutTypeDependentsSchema => isObject(input),
(input): Either<t.Errors, RulesWithoutTypeDependentsSchema> => {
const output = checkTypeDependents(input);
if (!hasListsFeature()) {
// TODO: (LIST-FEATURE) Remove this after the lists feature is an accepted feature for a particular release
return removeList(output);
} else {
return output;
}
return checkTypeDependents(input);
},
t.identity
);
// TODO: (LIST-FEATURE) Remove this after the lists feature is an accepted feature for a particular release
export const removeList = (
decoded: Either<t.Errors, RequiredRulesSchema>
): Either<t.Errors, RequiredRulesSchema> => {
const onLeft = (errors: t.Errors): Either<t.Errors, RequiredRulesSchema> => left(errors);
const onRight = (decodedValue: RequiredRulesSchema): Either<t.Errors, RequiredRulesSchema> => {
delete decodedValue.exceptions_list;
return right(decodedValue);
};
const folded = fold(onLeft, onRight);
return pipe(decoded, folded);
};
/**
* This is the correct type you want to use for Rules that are outputted from the
* REST interface. This has all base and all optional properties merged together.
*/
export type RulesSchema = t.TypeOf<typeof rulesSchema>;
export const addSavedId = (typeAndTimelineOnly: TypeAndTimelineOnly): t.Mixed[] => {
if (typeAndTimelineOnly.type === 'saved_query') {
return [t.exact(t.type({ saved_id: dependentRulesSchema.props.saved_id }))];
} else {
return [];
}
};
export const addTimelineTitle = (typeAndTimelineOnly: TypeAndTimelineOnly): t.Mixed[] => {
if (typeAndTimelineOnly.timeline_id != null) {
return [
t.exact(t.type({ timeline_title: dependentRulesSchema.props.timeline_title })),
t.exact(t.type({ timeline_id: dependentRulesSchema.props.timeline_id })),
];
} else {
return [];
}
};
export const addQueryFields = (typeAndTimelineOnly: TypeAndTimelineOnly): t.Mixed[] => {
if (typeAndTimelineOnly.type === 'query' || typeAndTimelineOnly.type === 'saved_query') {
return [
t.exact(t.type({ query: dependentRulesSchema.props.query })),
t.exact(t.type({ language: dependentRulesSchema.props.language })),
];
} else {
return [];
}
};
export const addMlFields = (typeAndTimelineOnly: TypeAndTimelineOnly): t.Mixed[] => {
if (isMlRule(typeAndTimelineOnly.type)) {
return [
t.exact(t.type({ anomaly_threshold: dependentRulesSchema.props.anomaly_threshold })),
t.exact(
t.type({ machine_learning_job_id: dependentRulesSchema.props.machine_learning_job_id })
),
];
} else {
return [];
}
};
export const getDependents = (typeAndTimelineOnly: TypeAndTimelineOnly): t.Mixed => {
const dependents: t.Mixed[] = [
t.exact(requiredRulesSchema),
t.exact(partialRulesSchema),
...addSavedId(typeAndTimelineOnly),
...addTimelineTitle(typeAndTimelineOnly),
...addQueryFields(typeAndTimelineOnly),
...addMlFields(typeAndTimelineOnly),
];
if (dependents.length > 1) {
// This unsafe cast is because t.intersection does not use an array but rather a set of
// tuples and really does not look like they expected us to ever dynamically build up
// intersections, but here we are doing that. Looking at their code, although they limit
// the array elements to 5, it looks like you have N number of intersections
const unsafeCast: [t.Mixed, t.Mixed] = dependents as [t.Mixed, t.Mixed];
return t.intersection(unsafeCast);
} else {
// We are not allowed to call t.intersection with a single value so we return without
// it here normally.
return dependents[0];
}
};
export const checkTypeDependents = (input: unknown): Either<t.Errors, RequiredRulesSchema> => {
const typeOnlyDecoded = typeAndTimelineOnlySchema.decode(input);
const onLeft = (errors: t.Errors): Either<t.Errors, RequiredRulesSchema> => left(errors);
const onRight = (
typeAndTimelineOnly: TypeAndTimelineOnly
): Either<t.Errors, RequiredRulesSchema> => {
const intersections = getDependents(typeAndTimelineOnly);
return intersections.decode(input);
};
return pipe(typeOnlyDecoded, fold(onLeft, onRight));
};

View file

@ -8,19 +8,10 @@ import { left } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import { TypeAndTimelineOnly, typeAndTimelineOnlySchema } from './type_timeline_only_schema';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags';
import { exactCheck } from '../../../../../../common/exact_check';
import { foldLeftRight, getPaths } from '../../../../../../common/test_utils';
import { exactCheck } from '../../../exact_check';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('prepackaged_rule_schema', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
test('it should validate a a type and timeline_id together', () => {
const payload: TypeAndTimelineOnly = {
type: 'query',

View file

@ -7,7 +7,7 @@
import * as t from 'io-ts';
/* eslint-disable @typescript-eslint/camelcase */
import { timeline_id, type } from './schemas';
import { timeline_id, type } from '../common/schemas';
/* eslint-enable @typescript-eslint/camelcase */
/**

View file

@ -7,7 +7,7 @@
import { IsoDateString } from './iso_date_string';
import { pipe } from 'fp-ts/lib/pipeable';
import { left } from 'fp-ts/lib/Either';
import { getPaths, foldLeftRight } from '../../../../../../common/test_utils';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('ios_date_string', () => {
test('it should validate a iso string', () => {

View file

@ -7,7 +7,7 @@
import { ListsDefaultArray } from './lists_default_array';
import { pipe } from 'fp-ts/lib/pipeable';
import { left } from 'fp-ts/lib/Either';
import { getPaths, foldLeftRight } from '../../../../../../common/test_utils';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('lists_default_array', () => {
test('it should validate an empty array', () => {

View file

@ -11,7 +11,7 @@ import {
list_and as listAnd,
list_values as listValues,
list_values_operator as listOperator,
} from '../response/schemas';
} from '../common/schemas';
export type ListsDefaultArrayC = t.Type<List[], List[], unknown>;
export type List = t.TypeOf<typeof listAnd>;

View file

@ -7,7 +7,7 @@
import { PositiveIntegerGreaterThanZero } from './positive_integer_greater_than_zero';
import { pipe } from 'fp-ts/lib/pipeable';
import { left } from 'fp-ts/lib/Either';
import { getPaths, foldLeftRight } from '../../../../../../common/test_utils';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('positive_integer_greater_than_zero', () => {
test('it should validate a positive number', () => {

View file

@ -7,7 +7,7 @@
import { PositiveInteger } from './positive_integer';
import { pipe } from 'fp-ts/lib/pipeable';
import { left } from 'fp-ts/lib/Either';
import { foldLeftRight, getPaths } from '../../../../../../common/test_utils';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('positive_integer_greater_than_zero', () => {
test('it should validate a positive number', () => {

View file

@ -7,7 +7,7 @@
import { ReferencesDefaultArray } from './references_default_array';
import { pipe } from 'fp-ts/lib/pipeable';
import { left } from 'fp-ts/lib/Either';
import { getPaths, foldLeftRight } from '../../../../../../common/test_utils';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('references_default_array', () => {
test('it should validate an empty array', () => {

View file

@ -7,7 +7,7 @@
import { RiskScore } from './risk_score';
import { pipe } from 'fp-ts/lib/pipeable';
import { left } from 'fp-ts/lib/Either';
import { foldLeftRight, getPaths } from '../../../../../../common/test_utils';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('risk_score', () => {
test('it should validate a positive number', () => {

View file

@ -7,7 +7,7 @@
import { UUID } from './uuid';
import { pipe } from 'fp-ts/lib/pipeable';
import { left } from 'fp-ts/lib/Either';
import { foldLeftRight, getPaths } from '../../../../../../common/test_utils';
import { foldLeftRight, getPaths } from '../../../test_utils';
describe('uuid', () => {
test('it should validate a uuid', () => {

View file

@ -4,6 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import {
PrePackagedRulesSchema,
prePackagedRulesSchema,
} from '../../../../../common/detection_engine/schemas/response/prepackaged_rules_schema';
import { IRouter } from '../../../../../../../../src/core/server';
import { DETECTION_ENGINE_PREPACKAGED_URL } from '../../../../../common/constants';
import { getIndexExists } from '../../index/get_index_exists';
@ -14,10 +18,6 @@ import { updatePrepackagedRules } from '../../rules/update_prepacked_rules';
import { getRulesToInstall } from '../../rules/get_rules_to_install';
import { getRulesToUpdate } from '../../rules/get_rules_to_update';
import { getExistingPrepackagedRules } from '../../rules/get_existing_prepackaged_rules';
import {
PrePackagedRulesSchema,
prePackagedRulesSchema,
} from '../schemas/response/prepackaged_rules_schema';
import { validate } from './validate';
export const addPrepackedRulesRoute = (router: IRouter) => {

View file

@ -6,6 +6,7 @@
import uuid from 'uuid';
import { rulesBulkSchema } from '../../../../../common/detection_engine/schemas/response/rules_bulk_schema';
import { IRouter } from '../../../../../../../../src/core/server';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import { SetupPlugins } from '../../../../plugin';
@ -24,7 +25,6 @@ import {
buildSiemResponse,
} from '../utils';
import { createRulesBulkSchema } from '../schemas/create_rules_bulk_schema';
import { rulesBulkSchema } from '../schemas/response/rules_bulk_schema';
import { updateRulesNotifications } from '../../rules/update_rules_notifications';
export const createRulesBulkRoute = (router: IRouter, ml: SetupPlugins['ml']) => {

View file

@ -4,10 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { rulesBulkSchema } from '../../../../../common/detection_engine/schemas/response/rules_bulk_schema';
import { IRouter, RouteConfig, RequestHandler } from '../../../../../../../../src/core/server';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import { queryRulesBulkSchema } from '../schemas/query_rules_bulk_schema';
import { rulesBulkSchema } from '../schemas/response/rules_bulk_schema';
import { getIdBulkError } from './utils';
import { transformValidateBulkError, validate } from './validate';
import { transformBulkError, buildRouteValidation, buildSiemResponse } from '../utils';

View file

@ -4,6 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import {
PrePackagedRulesStatusSchema,
prePackagedRulesStatusSchema,
} from '../../../../../common/detection_engine/schemas/response/prepackaged_rules_status_schema';
import { IRouter } from '../../../../../../../../src/core/server';
import { DETECTION_ENGINE_PREPACKAGED_URL } from '../../../../../common/constants';
import { transformError, buildSiemResponse } from '../utils';
@ -12,10 +16,6 @@ import { getRulesToInstall } from '../../rules/get_rules_to_install';
import { getRulesToUpdate } from '../../rules/get_rules_to_update';
import { findRules } from '../../rules/find_rules';
import { getExistingPrepackagedRules } from '../../rules/get_existing_prepackaged_rules';
import {
PrePackagedRulesStatusSchema,
prePackagedRulesStatusSchema,
} from '../schemas/response/prepackaged_rules_status_schema';
import { validate } from './validate';
export const getPrepackagedRulesStatusRoute = (router: IRouter) => {

View file

@ -7,6 +7,10 @@
import { chunk } from 'lodash/fp';
import { extname } from 'path';
import {
ImportRulesSchema,
importRulesSchema,
} from '../../../../../common/detection_engine/schemas/response/import_rules_schema';
import { IRouter } from '../../../../../../../../src/core/server';
import { createPromiseFromStreams } from '../../../../../../../../src/legacy/utils/streams';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
@ -31,7 +35,6 @@ import {
import { ImportRuleAlertRest } from '../../types';
import { patchRules } from '../../rules/patch_rules';
import { importRulesQuerySchema, importRulesPayloadSchema } from '../schemas/import_rules_schema';
import { ImportRulesSchema, importRulesSchema } from '../schemas/response/import_rules_schema';
import { getTupleDuplicateErrorsAndUniqueRules } from './utils';
import { validate } from './validate';
import { createRulesStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson';

View file

@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { rulesBulkSchema } from '../../../../../common/detection_engine/schemas/response/rules_bulk_schema';
import { IRouter } from '../../../../../../../../src/core/server';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import { SetupPlugins } from '../../../../plugin';
@ -14,7 +15,6 @@ import { transformBulkError, buildRouteValidation, buildSiemResponse } from '../
import { getIdBulkError } from './utils';
import { transformValidateBulkError, validate } from './validate';
import { patchRulesBulkSchema } from '../schemas/patch_rules_bulk_schema';
import { rulesBulkSchema } from '../schemas/response/rules_bulk_schema';
import { patchRules } from '../../rules/patch_rules';
import { updateRulesNotifications } from '../../rules/update_rules_notifications';
import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client';

View file

@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { rulesBulkSchema } from '../../../../../common/detection_engine/schemas/response/rules_bulk_schema';
import { IRouter } from '../../../../../../../../src/core/server';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import { SetupPlugins } from '../../../../plugin';
@ -15,7 +16,6 @@ import { transformValidateBulkError, validate } from './validate';
import { buildRouteValidation, transformBulkError, buildSiemResponse } from '../utils';
import { updateRulesBulkSchema } from '../schemas/update_rules_bulk_schema';
import { updateRules } from '../../rules/update_rules';
import { rulesBulkSchema } from '../schemas/response/rules_bulk_schema';
import { updateRulesNotifications } from '../../rules/update_rules_notifications';
import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client';

View file

@ -14,9 +14,9 @@ import {
} from './validate';
import { getResult } from '../__mocks__/request_responses';
import { FindResult } from '../../../../../../alerting/server';
import { RulesSchema } from '../schemas/response/rules_schema';
import { BulkError } from '../utils';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import { RulesSchema } from '../../../../../common/detection_engine/schemas/response/rules_schema';
export const ruleOutput: RulesSchema = {
actions: [],

View file

@ -9,6 +9,11 @@ import { fold } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import * as t from 'io-ts';
import { findRulesSchema } from '../../../../../common/detection_engine/schemas/response/find_rules_schema';
import {
RulesSchema,
rulesSchema,
} from '../../../../../common/detection_engine/schemas/response/rules_schema';
import { formatErrors } from '../../../../../common/format_errors';
import { exactCheck } from '../../../../../common/exact_check';
import { PartialAlert, FindResult } from '../../../../../../alerting/server';
@ -19,9 +24,7 @@ import {
} from '../../rules/types';
import { OutputRuleAlertRest } from '../../types';
import { createBulkErrorObject, BulkError } from '../utils';
import { rulesSchema, RulesSchema } from '../schemas/response/rules_schema';
import { transformFindAlerts, transform, transformAlertToRule } from './utils';
import { findRulesSchema } from '../schemas/response/find_rules_schema';
import { RuleActions } from '../../rule_actions/types';
export const transformValidateFindAlerts = (

View file

@ -1,97 +0,0 @@
/*
* 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 * as t from 'io-ts';
import { Either, left, fold } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import { isMlRule } from '../../../../../../common/machine_learning/helpers';
import {
dependentRulesSchema,
RequiredRulesSchema,
partialRulesSchema,
requiredRulesSchema,
} from './rules_schema';
import { typeAndTimelineOnlySchema, TypeAndTimelineOnly } from './type_timeline_only_schema';
export const addSavedId = (typeAndTimelineOnly: TypeAndTimelineOnly): t.Mixed[] => {
if (typeAndTimelineOnly.type === 'saved_query') {
return [t.exact(t.type({ saved_id: dependentRulesSchema.props.saved_id }))];
} else {
return [];
}
};
export const addTimelineTitle = (typeAndTimelineOnly: TypeAndTimelineOnly): t.Mixed[] => {
if (typeAndTimelineOnly.timeline_id != null) {
return [
t.exact(t.type({ timeline_title: dependentRulesSchema.props.timeline_title })),
t.exact(t.type({ timeline_id: dependentRulesSchema.props.timeline_id })),
];
} else {
return [];
}
};
export const addQueryFields = (typeAndTimelineOnly: TypeAndTimelineOnly): t.Mixed[] => {
if (typeAndTimelineOnly.type === 'query' || typeAndTimelineOnly.type === 'saved_query') {
return [
t.exact(t.type({ query: dependentRulesSchema.props.query })),
t.exact(t.type({ language: dependentRulesSchema.props.language })),
];
} else {
return [];
}
};
export const addMlFields = (typeAndTimelineOnly: TypeAndTimelineOnly): t.Mixed[] => {
if (isMlRule(typeAndTimelineOnly.type)) {
return [
t.exact(t.type({ anomaly_threshold: dependentRulesSchema.props.anomaly_threshold })),
t.exact(
t.type({ machine_learning_job_id: dependentRulesSchema.props.machine_learning_job_id })
),
];
} else {
return [];
}
};
export const getDependents = (typeAndTimelineOnly: TypeAndTimelineOnly): t.Mixed => {
const dependents: t.Mixed[] = [
t.exact(requiredRulesSchema),
t.exact(partialRulesSchema),
...addSavedId(typeAndTimelineOnly),
...addTimelineTitle(typeAndTimelineOnly),
...addQueryFields(typeAndTimelineOnly),
...addMlFields(typeAndTimelineOnly),
];
if (dependents.length > 1) {
// This unsafe cast is because t.intersection does not use an array but rather a set of
// tuples and really does not look like they expected us to ever dynamically build up
// intersections, but here we are doing that. Looking at their code, although they limit
// the array elements to 5, it looks like you have N number of intersections
const unsafeCast: [t.Mixed, t.Mixed] = dependents as [t.Mixed, t.Mixed];
return t.intersection(unsafeCast);
} else {
// We are not allowed to call t.intersection with a single value so we return without
// it here normally.
return dependents[0];
}
};
export const checkTypeDependents = (input: unknown): Either<t.Errors, RequiredRulesSchema> => {
const typeOnlyDecoded = typeAndTimelineOnlySchema.decode(input);
const onLeft = (errors: t.Errors): Either<t.Errors, RequiredRulesSchema> => left(errors);
const onRight = (
typeAndTimelineOnly: TypeAndTimelineOnly
): Either<t.Errors, RequiredRulesSchema> => {
const intersections = getDependents(typeAndTimelineOnly);
return intersections.decode(input);
};
return pipe(typeOnlyDecoded, fold(onLeft, onRight));
};

View file

@ -1,289 +0,0 @@
/*
* 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 { left } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import { rulesSchema, RulesSchema, removeList } from './rules_schema';
import { getBaseResponsePayload } from './__mocks__/utils';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags';
import { foldLeftRight, getPaths } from '../../../../../../common/test_utils';
import { exactCheck } from '../../../../../../common/exact_check';
export const ANCHOR_DATE = '2020-02-20T03:57:54.037Z';
describe('rules_schema', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
test('it should validate a type of "query" without anything extra', () => {
const payload = getBaseResponsePayload();
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
const expected = getBaseResponsePayload();
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(expected);
});
test('it should NOT validate a type of "query" when it has extra data', () => {
const payload: RulesSchema & { invalid_extra_data?: string } = getBaseResponsePayload();
payload.invalid_extra_data = 'invalid_extra_data';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']);
expect(message.schema).toEqual({});
});
test('it should NOT validate invalid_data for the type', () => {
const payload: Omit<RulesSchema, 'type'> & { type: string } = getBaseResponsePayload();
payload.type = 'invalid_data';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "invalid_data" supplied to "type"',
]);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "query" with a saved_id together', () => {
const payload = getBaseResponsePayload();
payload.type = 'query';
payload.saved_id = 'save id 123';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "saved_id"']);
expect(message.schema).toEqual({});
});
test('it should validate a type of "saved_query" with a "saved_id" dependent', () => {
const payload = getBaseResponsePayload();
payload.type = 'saved_query';
payload.saved_id = 'save id 123';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
const expected = getBaseResponsePayload();
expected.type = 'saved_query';
expected.saved_id = 'save id 123';
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(expected);
});
test('it should NOT validate a type of "saved_query" without a "saved_id" dependent', () => {
const payload = getBaseResponsePayload();
payload.type = 'saved_query';
delete payload.saved_id;
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "undefined" supplied to "saved_id"',
]);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "saved_query" when it has extra data', () => {
const payload: RulesSchema & { invalid_extra_data?: string } = getBaseResponsePayload();
payload.type = 'saved_query';
payload.saved_id = 'save id 123';
payload.invalid_extra_data = 'invalid_extra_data';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']);
expect(message.schema).toEqual({});
});
test('it should validate a type of "timeline_id" if there is a "timeline_title" dependent', () => {
const payload = getBaseResponsePayload();
payload.timeline_id = 'some timeline id';
payload.timeline_title = 'some timeline title';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
const expected = getBaseResponsePayload();
expected.timeline_id = 'some timeline id';
expected.timeline_title = 'some timeline title';
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(expected);
});
test('it should NOT validate a type of "timeline_id" if there is "timeline_title" dependent when it has extra invalid data', () => {
const payload: RulesSchema & { invalid_extra_data?: string } = getBaseResponsePayload();
payload.timeline_id = 'some timeline id';
payload.timeline_title = 'some timeline title';
payload.invalid_extra_data = 'invalid_extra_data';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "timeline_id" if there is NOT a "timeline_title" dependent', () => {
const payload = getBaseResponsePayload();
payload.timeline_id = 'some timeline id';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "undefined" supplied to "timeline_title"',
]);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "timeline_title" if there is NOT a "timeline_id" dependent', () => {
const payload = getBaseResponsePayload();
payload.timeline_title = 'some timeline title';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "timeline_title"']);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "saved_query" with a "saved_id" dependent and a "timeline_title" but there is NOT a "timeline_id"', () => {
const payload = getBaseResponsePayload();
payload.saved_id = 'some saved id';
payload.type = 'saved_query';
payload.timeline_title = 'some timeline title';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual(['invalid keys "timeline_title"']);
expect(message.schema).toEqual({});
});
test('it should NOT validate a type of "saved_query" with a "saved_id" dependent and a "timeline_id" but there is NOT a "timeline_title"', () => {
const payload = getBaseResponsePayload();
payload.saved_id = 'some saved id';
payload.type = 'saved_query';
payload.timeline_id = 'some timeline id';
const decoded = rulesSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "undefined" supplied to "timeline_title"',
]);
expect(message.schema).toEqual({});
});
// TODO: (LIST-FEATURE) Remove this test once the feature flag is deployed
test('it should remove exceptions_list when we need it to be removed because the feature is off but there exists a list in the data', () => {
const payload = getBaseResponsePayload();
const decoded = rulesSchema.decode(payload);
const listRemoved = removeList(decoded);
const message = pipe(listRemoved, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual({
id: '7a7065d7-6e8b-4aae-8d20-c93613dec9f9',
created_at: '2020-02-20T03:57:54.037Z',
updated_at: '2020-02-20T03:57:54.037Z',
created_by: 'elastic',
description: 'some description',
enabled: true,
false_positives: ['false positive 1', 'false positive 2'],
from: 'now-6m',
immutable: false,
name: 'Query with a rule id',
query: 'user.name: root or user.name: admin',
references: ['test 1', 'test 2'],
severity: 'high',
updated_by: 'elastic_kibana',
tags: [],
to: 'now',
type: 'query',
threat: [],
version: 1,
output_index: '.siem-signals-hassanabad-frank-default',
max_signals: 100,
risk_score: 55,
language: 'kuery',
rule_id: 'query-rule-id',
interval: '5m',
status: 'succeeded',
status_date: '2020-02-22T16:47:50.047Z',
last_success_at: '2020-02-22T16:47:50.047Z',
last_success_message: 'succeeded',
});
});
test('it should work with exceptions_list that are not there and not cause invalidation or errors', () => {
const payload = getBaseResponsePayload();
const { exceptions_list, ...payloadWithoutLists } = payload;
const decoded = rulesSchema.decode(payloadWithoutLists);
const listRemoved = removeList(decoded);
const message = pipe(listRemoved, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual({
id: '7a7065d7-6e8b-4aae-8d20-c93613dec9f9',
created_at: '2020-02-20T03:57:54.037Z',
updated_at: '2020-02-20T03:57:54.037Z',
created_by: 'elastic',
description: 'some description',
enabled: true,
false_positives: ['false positive 1', 'false positive 2'],
from: 'now-6m',
immutable: false,
name: 'Query with a rule id',
query: 'user.name: root or user.name: admin',
references: ['test 1', 'test 2'],
severity: 'high',
updated_by: 'elastic_kibana',
tags: [],
to: 'now',
type: 'query',
threat: [],
version: 1,
output_index: '.siem-signals-hassanabad-frank-default',
max_signals: 100,
risk_score: 55,
language: 'kuery',
rule_id: 'query-rule-id',
interval: '5m',
status: 'succeeded',
status_date: '2020-02-22T16:47:50.047Z',
last_success_at: '2020-02-22T16:47:50.047Z',
last_success_message: 'succeeded',
});
});
});

View file

@ -15,7 +15,7 @@ import {
formatQuery,
getLanguageBooleanOperator,
} from './build_exceptions_query';
import { List } from '../routes/schemas/types/lists_default_array';
import { List } from '../../../../common/detection_engine/schemas/types/lists_default_array';
describe('build_exceptions_query', () => {
describe('getLanguageBooleanOperator', () => {

View file

@ -3,8 +3,12 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import {
ListOperator,
ListValues,
List,
} from '../../../../common/detection_engine/schemas/types/lists_default_array';
import { Query } from '../../../../../../../src/plugins/data/server';
import { List, ListOperator, ListValues } from '../routes/schemas/types/lists_default_array';
import { RuleAlertParams, Language } from '../types';
type Operators = 'and' | 'or' | 'not';

View file

@ -6,11 +6,11 @@
import { get } from 'lodash/fp';
import { Logger } from 'src/core/server';
import { List } from '../../../../common/detection_engine/schemas/types/lists_default_array';
import { type } from '../../../../../lists/common/schemas/common';
import { ListClient } from '../../../../../lists/server';
import { SignalSearchResponse, SearchTypes } from './types';
import { RuleAlertParams } from '../types';
import { List } from '../routes/schemas/types/lists_default_array';
interface FilterEventsAgainstList {
listClient: ListClient;

View file

@ -4,10 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { ListsDefaultArraySchema } from '../../../common/detection_engine/schemas/types/lists_default_array';
import { CallAPIOptions } from '../../../../../../src/core/server';
import { Filter } from '../../../../../../src/plugins/data/server';
import { IRuleStatusAttributes } from './rules/types';
import { ListsDefaultArraySchema } from './routes/schemas/types/lists_default_array';
import { RuleAlertAction, RuleType } from '../../../common/detection_engine/types';
export type PartialFilter = Partial<Filter>;

View file

@ -7,6 +7,7 @@
import { extname } from 'path';
import { chunk, omit } from 'lodash/fp';
import { importRulesSchema } from '../../../../common/detection_engine/schemas/response/import_rules_schema';
import { createPromiseFromStreams } from '../../../../../../../src/legacy/utils';
import { IRouter } from '../../../../../../../src/core/server';
@ -16,7 +17,6 @@ import { SetupPlugins } from '../../../plugin';
import { ConfigType } from '../../../config';
import { buildRouteValidation } from '../../../utils/build_validation/route_validation';
import { importRulesSchema } from '../../detection_engine/routes/schemas/response/import_rules_schema';
import { validate } from '../../detection_engine/routes/rules/validate';
import {
buildSiemResponse,