Skip to content

Commit

Permalink
[Security Solution] [Detections] Fixes EQL shell alert missing common…
Browse files Browse the repository at this point in the history
… fields (elastic#166751)

## Summary

Fixes: elastic#163960

---------

Co-authored-by: Ryland Herrick <[email protected]>
  • Loading branch information
dhurley14 and rylnd authored Sep 21, 2023
1 parent bb4e6fc commit 7ac9650
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ describe('buildAlert', () => {
jest.clearAllMocks();
});

test('it builds an alert composed of a sequence', () => {
expect(true).toEqual(true);
});

test('it builds an alert as expected without original_event if event does not exist', () => {
const completeRule = getCompleteRuleMock<QueryRuleParams>(getQueryRuleParams());
const eqlSequence = {
Expand Down Expand Up @@ -146,6 +142,64 @@ describe('buildAlert', () => {
});

describe('recursive intersection between objects', () => {
describe('objectPairIntersection', () => {
test('returns the intersection of fields with identically-valued arrays', () => {
const a = {
field1: [1],
};
const b = {
field1: [1],
};
const intersection = objectPairIntersection(a, b);
const expected = {
field1: [1],
};
expect(intersection).toEqual(expected);
});

test('returns the intersection of arrays with differing lengths', () => {
const a = {
field1: 1,
};
const b = {
field1: [1, 2, 3],
};
const intersection = objectPairIntersection(a, b);
const expected = {
field1: [1],
};
expect(intersection).toEqual(expected);
});

test('should work with arrays with same lengths but only one intersecting element', () => {
const a = {
field1: [3, 4, 5],
};
const b = {
field1: [1, 2, 3],
};
const intersection = objectPairIntersection(a, b);
const expected = {
field1: [3],
};
expect(intersection).toEqual(expected);
});

test('should work with arrays with differing lengths and two intersecting elements', () => {
const a = {
field1: [3, 4, 5],
};
const b = {
field1: [1, 2, 3, 4],
};
const intersection = objectPairIntersection(a, b);
const expected = {
field1: [3, 4],
};
expect(intersection).toEqual(expected);
});
});

test('should treat numbers and strings as unequal', () => {
const a = {
field1: 1,
Expand Down Expand Up @@ -217,7 +271,7 @@ describe('buildAlert', () => {
expect(intersection).toEqual(expected);
});

test('should strip arrays out regardless of whether they are equal', () => {
test('returns the intersection of values for fields containing arrays', () => {
const a = {
array_field1: [1, 2],
array_field2: [1, 2],
Expand All @@ -227,7 +281,7 @@ describe('buildAlert', () => {
array_field2: [3, 4],
};
const intersection = objectPairIntersection(a, b);
const expected = undefined;
const expected = { array_field1: [1, 2], array_field2: [] };
expect(intersection).toEqual(expected);
});

Expand Down Expand Up @@ -287,6 +341,7 @@ describe('buildAlert', () => {
const intersection = objectPairIntersection(a, b);
const expected = {
container_field: {
array_field: [1, 2],
field1: 1,
field6: null,
nested_container_field: {
Expand Down Expand Up @@ -332,6 +387,7 @@ describe('buildAlert', () => {
};
const intersection = objectPairIntersection(a, b);
const expected = {
array_field: [1, 2],
field1: 1,
field6: null,
container_field: {
Expand Down Expand Up @@ -419,6 +475,7 @@ describe('buildAlert', () => {
};
const intersection = objectArrayIntersection([a, b]);
const expected = {
array_field: [1, 2],
field1: 1,
field6: null,
container_field: {
Expand All @@ -427,7 +484,6 @@ describe('buildAlert', () => {
};
expect(intersection).toEqual(expected);
});

test('should work with 3 or more objects', () => {
const a = {
field1: 1,
Expand Down Expand Up @@ -477,6 +533,7 @@ describe('buildAlert', () => {
};
const intersection = objectArrayIntersection([a, b, c]);
const expected = {
array_field: [1, 2],
field1: 1,
};
expect(intersection).toEqual(expected);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import { ALERT_URL, ALERT_UUID } from '@kbn/rule-data-utils';
import { intersection as lodashIntersection, isArray } from 'lodash';

import { getAlertDetailsUrl } from '../../../../../common/utils/alert_detail_path';
import { DEFAULT_ALERTS_INDEX } from '../../../../../common/constants';
Expand Down Expand Up @@ -180,6 +181,11 @@ export const buildAlertRoot = (
};
};

/**
* Merges array of alert sources with the first item in the array
* @param objects array of alert _source objects
* @returns singular object
*/
export const objectArrayIntersection = (objects: object[]) => {
if (objects.length === 0) {
return undefined;
Expand All @@ -195,6 +201,16 @@ export const objectArrayIntersection = (objects: object[]) => {
}
};

/**
* Finds the intersection of two objects by recursively
* finding the "intersection" of each of of their common keys'
* values. If an intersection cannot be found between a key's
* values, the value will be undefined in the returned object.
*
* @param a object
* @param b object
* @returns intersection of the two objects
*/
export const objectPairIntersection = (a: object | undefined, b: object | undefined) => {
if (a === undefined || b === undefined) {
return undefined;
Expand All @@ -214,6 +230,12 @@ export const objectPairIntersection = (a: object | undefined, b: object | undefi
intersection[key] = objectPairIntersection(aVal, bVal);
} else if (aVal === bVal) {
intersection[key] = aVal;
} else if (isArray(aVal) && isArray(bVal)) {
intersection[key] = lodashIntersection(aVal, bVal);
} else if (isArray(aVal) && !isArray(bVal)) {
intersection[key] = lodashIntersection(aVal, [bVal]);
} else if (!isArray(aVal) && isArray(bVal)) {
intersection[key] = lodashIntersection([aVal], bVal);
}
}
});
Expand Down

0 comments on commit 7ac9650

Please sign in to comment.