Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Security Solution][Exceptions] - Require non empty entries and non empty string values in exception list items #72748

Merged
merged 5 commits into from
Jul 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ describe('create_endpoint_list_item_schema', () => {
expect(message.schema).toEqual({});
});

test('it should validate an undefined for "entries" but return an array', () => {
test('it should NOT validate an undefined for "entries"', () => {
const inputPayload = getCreateEndpointListItemSchemaMock();
const outputPayload = getCreateEndpointListItemSchemaMock();
delete inputPayload.entries;
Expand All @@ -151,8 +151,10 @@ describe('create_endpoint_list_item_schema', () => {
const checked = exactCheck(inputPayload, decoded);
const message = pipe(checked, foldLeftRight);
delete (message.schema as CreateEndpointListItemSchema).item_id;
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(outputPayload);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "undefined" supplied to "entries"',
]);
expect(message.schema).toEqual({});
});

test('it should validate an undefined for "tags" but return an array and generate a correct body not counting the auto generated uuid', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ import {
tags,
} from '../common/schemas';
import { RequiredKeepUndefined } from '../../types';
import { CreateCommentsArray, DefaultCreateCommentsArray, DefaultEntryArray } from '../types';
import { CreateCommentsArray, DefaultCreateCommentsArray, nonEmptyEntriesArray } from '../types';
import { EntriesArray } from '../types/entries';
import { DefaultUuid } from '../../siem_common_deps';

export const createEndpointListItemSchema = t.intersection([
t.exact(
t.type({
description,
entries: nonEmptyEntriesArray,
name,
type: exceptionListItemType,
})
Expand All @@ -36,7 +37,6 @@ export const createEndpointListItemSchema = t.intersection([
t.partial({
_tags, // defaults to empty array if not set during decode
comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode
entries: DefaultEntryArray, // defaults to empty array if not set during decode
item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode
meta, // defaults to undefined if not set during decode
tags, // defaults to empty array if not set during decode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ describe('create_exception_list_item_schema', () => {
expect(message.schema).toEqual({});
});

test('it should validate an undefined for "entries" but return an array', () => {
test('it should NOT validate an undefined for "entries"', () => {
const inputPayload = getCreateExceptionListItemSchemaMock();
const outputPayload = getCreateExceptionListItemSchemaMock();
delete inputPayload.entries;
Expand All @@ -139,8 +139,10 @@ describe('create_exception_list_item_schema', () => {
const checked = exactCheck(inputPayload, decoded);
const message = pipe(checked, foldLeftRight);
delete (message.schema as CreateExceptionListItemSchema).item_id;
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(outputPayload);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "undefined" supplied to "entries"',
]);
expect(message.schema).toEqual({});
});

test('it should validate an undefined for "namespace_type" but return enum "single" and generate a correct body not counting the auto generated uuid', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import { RequiredKeepUndefined } from '../../types';
import {
CreateCommentsArray,
DefaultCreateCommentsArray,
DefaultEntryArray,
NamespaceType,
nonEmptyEntriesArray,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: these seem to normally be exported as uppercase constants. I know you're exporting TypeOf with that name, but maybe we need a convention for that if there isn't one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, spoke with @FrankHassanabad about that earlier today. He'd suggested going lowercase here to differentiate as throughout we tend to use the lowercase for io-ts. Def something we should discuss to settle on one way or the other.

} from '../types';
import { EntriesArray } from '../types/entries';
import { DefaultUuid } from '../../siem_common_deps';
Expand All @@ -35,6 +35,7 @@ export const createExceptionListItemSchema = t.intersection([
t.exact(
t.type({
description,
entries: nonEmptyEntriesArray,
list_id,
name,
type: exceptionListItemType,
Expand All @@ -44,7 +45,6 @@ export const createExceptionListItemSchema = t.intersection([
t.partial({
_tags, // defaults to empty array if not set during decode
comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode
entries: DefaultEntryArray, // defaults to empty array if not set during decode
item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode
meta, // defaults to undefined if not set during decode
namespace_type, // defaults to 'single' if not set during decode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,18 @@ describe('update_endpoint_list_item_schema', () => {
expect(message.schema).toEqual(outputPayload);
});

test('it should accept an undefined for "entries" but return an array', () => {
test('it should NOT accept an undefined for "entries"', () => {
const inputPayload = getUpdateEndpointListItemSchemaMock();
const outputPayload = getUpdateEndpointListItemSchemaMock();
delete inputPayload.entries;
outputPayload.entries = [];
const decoded = updateEndpointListItemSchema.decode(inputPayload);
const checked = exactCheck(inputPayload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(outputPayload);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "undefined" supplied to "entries"',
]);
expect(message.schema).toEqual({});
});

test('it should accept an undefined for "tags" but return an array', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,17 @@ import {
} from '../common/schemas';
import { RequiredKeepUndefined } from '../../types';
import {
DefaultEntryArray,
DefaultUpdateCommentsArray,
EntriesArray,
UpdateCommentsArray,
nonEmptyEntriesArray,
} from '../types';

export const updateEndpointListItemSchema = t.intersection([
t.exact(
t.type({
description,
entries: nonEmptyEntriesArray,
name,
type: exceptionListItemType,
})
Expand All @@ -41,7 +42,6 @@ export const updateEndpointListItemSchema = t.intersection([
_tags, // defaults to empty array if not set during decode
_version, // defaults to undefined if not set during decode
comments: DefaultUpdateCommentsArray, // defaults to empty array if not set during decode
entries: DefaultEntryArray, // defaults to empty array if not set during decode
id, // defaults to undefined if not set during decode
item_id: t.union([t.string, t.undefined]),
meta, // defaults to undefined if not set during decode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,18 @@ describe('update_exception_list_item_schema', () => {
expect(message.schema).toEqual(outputPayload);
});

test('it should accept an undefined for "entries" but return an array', () => {
test('it should NOT accept an undefined for "entries"', () => {
const inputPayload = getUpdateExceptionListItemSchemaMock();
const outputPayload = getUpdateExceptionListItemSchemaMock();
delete inputPayload.entries;
outputPayload.entries = [];
const decoded = updateExceptionListItemSchema.decode(inputPayload);
const checked = exactCheck(inputPayload, decoded);
const message = pipe(checked, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(outputPayload);
expect(getPaths(left(message.errors))).toEqual([
'Invalid value "undefined" supplied to "entries"',
]);
expect(message.schema).toEqual({});
});

test('it should accept an undefined for "namespace_type" but return enum "single"', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@ import {
} from '../common/schemas';
import { RequiredKeepUndefined } from '../../types';
import {
DefaultEntryArray,
DefaultUpdateCommentsArray,
EntriesArray,
NamespaceType,
UpdateCommentsArray,
nonEmptyEntriesArray,
} from '../types';

export const updateExceptionListItemSchema = t.intersection([
t.exact(
t.type({
description,
entries: nonEmptyEntriesArray,
name,
type: exceptionListItemType,
})
Expand All @@ -43,7 +44,6 @@ export const updateExceptionListItemSchema = t.intersection([
_tags, // defaults to empty array if not set during decode
_version, // defaults to undefined if not set during decode
comments: DefaultUpdateCommentsArray, // defaults to empty array if not set during decode
entries: DefaultEntryArray, // defaults to empty array if not set during decode
id, // defaults to undefined if not set during decode
item_id: t.union([t.string, t.undefined]),
meta, // defaults to undefined if not set during decode
Expand Down

This file was deleted.

22 changes: 0 additions & 22 deletions x-pack/plugins/lists/common/schemas/types/default_entries_array.ts

This file was deleted.

70 changes: 11 additions & 59 deletions x-pack/plugins/lists/common/schemas/types/entries.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,65 +4,17 @@
* you may not use this file except in compliance with the Elastic License.
*/

import {
ENTRY_VALUE,
EXISTS,
FIELD,
LIST,
LIST_ID,
MATCH,
MATCH_ANY,
NESTED,
OPERATOR,
TYPE,
} from '../../constants.mock';

import {
EntriesArray,
EntryExists,
EntryList,
EntryMatch,
EntryMatchAny,
EntryNested,
} from './entries';

export const getEntryMatchMock = (): EntryMatch => ({
field: FIELD,
operator: OPERATOR,
type: MATCH,
value: ENTRY_VALUE,
});

export const getEntryMatchAnyMock = (): EntryMatchAny => ({
field: FIELD,
operator: OPERATOR,
type: MATCH_ANY,
value: [ENTRY_VALUE],
});

export const getEntryListMock = (): EntryList => ({
field: FIELD,
list: { id: LIST_ID, type: TYPE },
operator: OPERATOR,
type: LIST,
});

export const getEntryExistsMock = (): EntryExists => ({
field: FIELD,
operator: OPERATOR,
type: EXISTS,
});

export const getEntryNestedMock = (): EntryNested => ({
entries: [getEntryMatchMock(), getEntryMatchMock()],
field: FIELD,
type: NESTED,
});
import { EntriesArray } from './entries';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

import { getEntryMatchMock } from './entry_match.mock';
import { getEntryMatchAnyMock } from './entry_match_any.mock';
import { getEntryListMock } from './entry_list.mock';
import { getEntryExistsMock } from './entry_exists.mock';
import { getEntryNestedMock } from './entry_nested.mock';

export const getEntriesArrayMock = (): EntriesArray => [
getEntryMatchMock(),
getEntryMatchAnyMock(),
getEntryListMock(),
getEntryExistsMock(),
getEntryNestedMock(),
{ ...getEntryMatchMock() },
yctercero marked this conversation as resolved.
Show resolved Hide resolved
yctercero marked this conversation as resolved.
Show resolved Hide resolved
{ ...getEntryMatchAnyMock() },
{ ...getEntryListMock() },
{ ...getEntryExistsMock() },
{ ...getEntryNestedMock() },
];
Loading