mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[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:
parent
571b3de667
commit
0dca28b6dd
48 changed files with 333 additions and 535 deletions
|
@ -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());
|
|
@ -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
|
|
@ -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);
|
|
@ -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({
|
|
@ -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);
|
|
@ -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 */
|
||||
|
|
@ -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);
|
|
@ -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(
|
|
@ -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,
|
|
@ -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(
|
|
@ -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);
|
|
@ -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', () => {
|
|
@ -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));
|
||||
};
|
|
@ -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',
|
|
@ -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 */
|
||||
|
||||
/**
|
|
@ -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', () => {
|
|
@ -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', () => {
|
|
@ -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>;
|
|
@ -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', () => {
|
|
@ -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', () => {
|
|
@ -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', () => {
|
|
@ -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', () => {
|
|
@ -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', () => {
|
|
@ -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) => {
|
||||
|
|
|
@ -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']) => {
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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: [],
|
||||
|
|
|
@ -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 = (
|
||||
|
|
|
@ -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));
|
||||
};
|
|
@ -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',
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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', () => {
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue