Skip to content

Commit

Permalink
Refactors signal ancestry to allow multiple parents
Browse files Browse the repository at this point in the history
  • Loading branch information
marshallmain committed Sep 2, 2020
1 parent 1e8c05f commit 39a5f49
Show file tree
Hide file tree
Showing 12 changed files with 283 additions and 317 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,33 @@
}
}
},
"parents": {
"properties": {
"rule": {
"type": "keyword"
},
"index": {
"type": "keyword"
},
"id": {
"type": "keyword"
},
"type": {
"type": "keyword"
},
"depth": {
"type": "long"
}
}
},
"ancestors": {
"properties": {
"rule": {
"type": "keyword"
},
"index": {
"type": "keyword"
},
"id": {
"type": "keyword"
},
Expand Down Expand Up @@ -299,6 +321,9 @@
},
"threshold_count": {
"type": "float"
},
"depth": {
"type": "integer"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,21 +149,23 @@ export const sampleDocWithAncestors = (): SignalSearchResponse => {
delete sampleDoc._source.source;
sampleDoc._source.signal = {
parent: {
rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71',
type: 'event',
index: 'myFakeSignalIndex',
depth: 1,
depth: 0,
},
ancestors: [
{
rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71',
type: 'event',
index: 'myFakeSignalIndex',
depth: 1,
depth: 0,
},
],
rule: {
id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
},
depth: 1,
};

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,20 @@ describe('buildBulkBody', () => {
kind: 'signal',
},
signal: {
parent: {
rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 1,
},
parents: [
{
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 0,
},
],
ancestors: [
{
rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 1,
depth: 0,
},
],
original_time: '2020-04-20T21:27:45+0000',
Expand Down Expand Up @@ -101,6 +101,7 @@ describe('buildBulkBody', () => {
updated_at: fakeSignalSourceHit.signal.rule?.updated_at,
exceptions_list: getListArrayMock(),
},
depth: 1,
},
};
expect(fakeSignalSourceHit).toEqual(expected);
Expand Down Expand Up @@ -148,20 +149,20 @@ describe('buildBulkBody', () => {
kind: 'event',
module: 'system',
},
parent: {
rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 1,
},
parents: [
{
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 0,
},
],
ancestors: [
{
rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 1,
depth: 0,
},
],
original_time: '2020-04-20T21:27:45+0000',
Expand Down Expand Up @@ -203,6 +204,7 @@ describe('buildBulkBody', () => {
threat: [],
exceptions_list: getListArrayMock(),
},
depth: 1,
},
};
expect(fakeSignalSourceHit).toEqual(expected);
Expand Down Expand Up @@ -248,20 +250,20 @@ describe('buildBulkBody', () => {
dataset: 'socket',
module: 'system',
},
parent: {
rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 1,
},
parents: [
{
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 0,
},
],
ancestors: [
{
rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 1,
depth: 0,
},
],
original_time: '2020-04-20T21:27:45+0000',
Expand Down Expand Up @@ -303,6 +305,7 @@ describe('buildBulkBody', () => {
throttle: 'no_actions',
exceptions_list: getListArrayMock(),
},
depth: 1,
},
};
expect(fakeSignalSourceHit).toEqual(expected);
Expand Down Expand Up @@ -341,20 +344,20 @@ describe('buildBulkBody', () => {
original_event: {
kind: 'event',
},
parent: {
rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 1,
},
parents: [
{
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 0,
},
],
ancestors: [
{
rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
id: sampleIdGuid,
type: 'event',
index: 'myFakeSignalIndex',
depth: 1,
depth: 0,
},
],
original_time: '2020-04-20T21:27:45+0000',
Expand Down Expand Up @@ -396,6 +399,7 @@ describe('buildBulkBody', () => {
throttle: 'no_actions',
exceptions_list: getListArrayMock(),
},
depth: 1,
},
};
expect(fakeSignalSourceHit).toEqual(expected);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { SignalSourceHit, SignalHit } from './types';
import { SignalSourceHit, SignalHit, Signal } from './types';
import { buildRule } from './build_rule';
import { buildSignal } from './build_signal';
import { additionalSignalFields, buildSignal } from './build_signal';
import { buildEventTypeSignal } from './build_event_type_signal';
import { RuleAlertAction } from '../../../../common/detection_engine/types';
import { RuleTypeParams } from '../types';
Expand Down Expand Up @@ -58,7 +58,10 @@ export const buildBulkBody = ({
tags,
throttle,
});
const signal = buildSignal(doc, rule);
const signal: Signal = {
...buildSignal([doc], rule),
...additionalSignalFields(doc),
};
const event = buildEventTypeSignal(doc);
const signalHit: SignalHit = {
...doc._source,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { buildRule } from './build_rule';
import { buildRule, removeInternalTagsFromRule } from './build_rule';
import { sampleDocNoSortId, sampleRuleAlertParams, sampleRuleGuid } from './__mocks__/es_results';
import { RulesSchema } from '../../../../common/detection_engine/schemas/response/rules_schema';
import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock';
import { INTERNAL_RULE_ID_KEY, INTERNAL_IMMUTABLE_KEY } from '../../../../common/constants';
import { getPartialRulesSchemaMock } from '../../../../common/detection_engine/schemas/response/rules_schema.mocks';

describe('buildRule', () => {
beforeEach(() => {
Expand Down Expand Up @@ -208,4 +210,102 @@ describe('buildRule', () => {
};
expect(rule).toEqual(expected);
});

test('it builds a rule and removes internal tags', () => {
const ruleParams = sampleRuleAlertParams();
const rule = buildRule({
actions: [],
doc: sampleDocNoSortId(),
ruleParams,
name: 'some-name',
id: sampleRuleGuid,
enabled: false,
createdAt: '2020-01-28T15:58:34.810Z',
updatedAt: '2020-01-28T15:59:14.004Z',
createdBy: 'elastic',
updatedBy: 'elastic',
interval: 'some interval',
tags: [
'some fake tag 1',
'some fake tag 2',
`${INTERNAL_RULE_ID_KEY}:rule-1`,
`${INTERNAL_IMMUTABLE_KEY}:true`,
],
throttle: 'no_actions',
});
const expected: Partial<RulesSchema> = {
actions: [],
author: ['Elastic'],
building_block_type: 'default',
created_by: 'elastic',
description: 'Detecting root and admin users',
enabled: false,
false_positives: [],
from: 'now-6m',
id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
immutable: false,
index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
interval: 'some interval',
language: 'kuery',
license: 'Elastic License',
max_signals: 10000,
name: 'some-name',
output_index: '.siem-signals',
query: 'user.name: root or user.name: admin',
references: ['http://google.com'],
risk_score: 50,
risk_score_mapping: [],
rule_id: 'rule-1',
severity: 'high',
severity_mapping: [],
tags: ['some fake tag 1', 'some fake tag 2'],
threat: [],
to: 'now',
type: 'query',
note: '',
updated_by: 'elastic',
updated_at: rule.updated_at,
created_at: rule.created_at,
throttle: 'no_actions',
exceptions_list: getListArrayMock(),
version: 1,
};
expect(rule).toEqual(expected);
});

test('it removes internal tags from a typical rule', () => {
const rule = getPartialRulesSchemaMock();
rule.tags = [
'some fake tag 1',
'some fake tag 2',
`${INTERNAL_RULE_ID_KEY}:rule-1`,
`${INTERNAL_IMMUTABLE_KEY}:true`,
];
const noInternals = removeInternalTagsFromRule(rule);
expect(noInternals).toEqual(getPartialRulesSchemaMock());
});

test('it works with an empty array', () => {
const rule = getPartialRulesSchemaMock();
rule.tags = [];
const noInternals = removeInternalTagsFromRule(rule);
const expected = getPartialRulesSchemaMock();
expected.tags = [];
expect(noInternals).toEqual(expected);
});

test('it works if tags does not exist', () => {
const rule = getPartialRulesSchemaMock();
delete rule.tags;
const noInternals = removeInternalTagsFromRule(rule);
const expected = getPartialRulesSchemaMock();
delete expected.tags;
expect(noInternals).toEqual(expected);
});

test('it works if tags contains normal values and no internal values', () => {
const rule = getPartialRulesSchemaMock();
const noInternals = removeInternalTagsFromRule(rule);
expect(noInternals).toEqual(rule);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { buildRiskScoreFromMapping } from './mappings/build_risk_score_from_mapp
import { SignalSourceHit } from './types';
import { buildSeverityFromMapping } from './mappings/build_severity_from_mapping';
import { buildRuleNameFromMapping } from './mappings/build_rule_name_from_mapping';
import { INTERNAL_IDENTIFIER } from '../../../../common/constants';

interface BuildRuleParams {
ruleParams: RuleTypeParams;
Expand Down Expand Up @@ -64,7 +65,7 @@ export const buildRule = ({

const meta = { ...ruleParams.meta, ...riskScoreMeta, ...severityMeta, ...ruleNameMeta };

return pickBy<RulesSchema>((value: unknown) => value != null, {
const rule = pickBy<RulesSchema>((value: unknown) => value != null, {
id,
rule_id: ruleParams.ruleId ?? '(unknown rule_id)',
actions,
Expand Down Expand Up @@ -111,4 +112,17 @@ export const buildRule = ({
anomaly_threshold: ruleParams.anomalyThreshold,
threshold: ruleParams.threshold,
});
return removeInternalTagsFromRule(rule);
};

export const removeInternalTagsFromRule = (rule: Partial<RulesSchema>): Partial<RulesSchema> => {
if (rule.tags == null) {
return rule;
} else {
const ruleWithoutInternalTags: Partial<RulesSchema> = {
...rule,
tags: rule.tags.filter((tag) => !tag.startsWith(INTERNAL_IDENTIFIER)),
};
return ruleWithoutInternalTags;
}
};
Loading

0 comments on commit 39a5f49

Please sign in to comment.