[Security Solution][Detections] Adds more granular validation for nested fields (#92041)

This commit is contained in:
Davis Plumlee 2021-02-19 19:16:14 -05:00 committed by GitHub
parent 52c4deceaa
commit 087449cbf6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 10 deletions

View file

@ -12,7 +12,8 @@ import { entriesMatchAny } from './entry_match_any';
import { entriesMatch } from './entry_match';
import { entriesExists } from './entry_exists';
export const nestedEntriesArray = t.array(t.union([entriesMatch, entriesMatchAny, entriesExists]));
export const nestedEntryItem = t.union([entriesMatch, entriesMatchAny, entriesExists]);
export const nestedEntriesArray = t.array(nestedEntryItem);
export type NestedEntriesArray = t.TypeOf<typeof nestedEntriesArray>;
/**

View file

@ -36,6 +36,7 @@ export {
listSchema,
entry,
entriesNested,
nestedEntryItem,
entriesMatch,
entriesMatchAny,
entriesExists,

View file

@ -35,6 +35,7 @@ export {
listSchema,
entry,
entriesNested,
nestedEntryItem,
entriesMatch,
entriesMatchAny,
entriesExists,

View file

@ -326,6 +326,52 @@ describe('Exception helpers', () => {
expect(output).toEqual([{ ...getExceptionListItemSchemaMock() }]);
});
test('it removes the "nested" entry entries with "value" of empty string', () => {
const { entries, ...rest } = { ...getExceptionListItemSchemaMock() };
const mockEmptyException: EntryNested = {
field: 'host.name',
type: OperatorTypeEnum.NESTED,
entries: [getEntryMatchMock(), { ...getEntryMatchMock(), value: '' }],
};
const output: Array<
ExceptionListItemSchema | CreateExceptionListItemSchema
> = filterExceptionItems([
{
...rest,
entries: [...entries, mockEmptyException],
},
]);
expect(output).toEqual([
{
...getExceptionListItemSchemaMock(),
entries: [
...getExceptionListItemSchemaMock().entries,
{ ...mockEmptyException, entries: [getEntryMatchMock()] },
],
},
]);
});
test('it removes the "nested" entry item if all its entries are invalid', () => {
const { entries, ...rest } = { ...getExceptionListItemSchemaMock() };
const mockEmptyException: EntryNested = {
field: 'host.name',
type: OperatorTypeEnum.NESTED,
entries: [{ ...getEntryMatchMock(), value: '' }],
};
const output: Array<
ExceptionListItemSchema | CreateExceptionListItemSchema
> = filterExceptionItems([
{
...rest,
entries: [...entries, mockEmptyException],
},
]);
expect(output).toEqual([{ ...getExceptionListItemSchemaMock() }]);
});
test('it removes `temporaryId` from items', () => {
const { meta, ...rest } = getNewExceptionItem({
listId: '123',

View file

@ -32,6 +32,7 @@ import {
comment,
entry,
entriesNested,
nestedEntryItem,
createExceptionListItemSchema,
exceptionListItemSchema,
UpdateExceptionListItemSchema,
@ -173,16 +174,31 @@ export const filterExceptionItems = (
): Array<ExceptionListItemSchema | CreateExceptionListItemSchema> => {
return exceptions.reduce<Array<ExceptionListItemSchema | CreateExceptionListItemSchema>>(
(acc, exception) => {
const entries = exception.entries.filter((t) => {
const [validatedEntry] = validate(t, entry);
const [validatedNestedEntry] = validate(t, entriesNested);
const entries = exception.entries.reduce<BuilderEntry[]>((nestedAcc, singleEntry) => {
if (singleEntry.type === 'nested') {
const nestedEntriesArray = singleEntry.entries.filter((singleNestedEntry) => {
const [validatedNestedEntry] = validate(singleNestedEntry, nestedEntryItem);
return validatedNestedEntry != null;
});
if (validatedEntry != null || validatedNestedEntry != null) {
return true;
const [validatedNestedEntry] = validate(
{ ...singleEntry, entries: nestedEntriesArray },
entriesNested
);
if (validatedNestedEntry != null) {
return [...nestedAcc, validatedNestedEntry];
}
return nestedAcc;
} else {
const [validatedEntry] = validate(singleEntry, entry);
if (validatedEntry != null) {
return [...nestedAcc, validatedEntry];
}
return nestedAcc;
}
return false;
});
}, []);
const item = { ...exception, entries };
@ -401,7 +417,7 @@ export const getCodeSignatureValue = (
return codeSignature.map((signature) => {
return {
subjectName: signature.subject_name ?? '',
trusted: signature.trusted ?? '',
trusted: signature.trusted.toString() ?? '',
};
});
} else {