mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
## Issue
Fixes #137435
Reason formatter was not when working correctly in case of threshold alerts. In an ideal scenario, if threshold alert is grouped by a field, say `user.name` then that field should be available in the reason message.
It was missing as per the bug.
## Solution
For threshold alerts, `mergedDoc` in results in a different shape of object where the fields are contained in `_source` key instead of `fields` key. This was corrected so that if `fields` key is not available in the `mergedDoc`, `_source` will act as the fallback key.
### Checklist
Delete any items that are not applicable to this PR.
- [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
### For maintainers
- [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
(cherry picked from commit ac0635bd9d
)
Co-authored-by: Jatin Kathuria <jatin.kathuria@elastic.co>
This commit is contained in:
parent
8ce6bcf8ef
commit
9e1eb0ed84
3 changed files with 93 additions and 35 deletions
|
@ -5,39 +5,50 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { buildReasonMessageUtil } from './reason_formatters';
|
||||
import type { SignalSourceHit } from './types';
|
||||
import { buildReasonMessageForThresholdAlert, buildReasonMessageUtil } from './reason_formatters';
|
||||
|
||||
const mergedDoc = {
|
||||
_index: 'index-1',
|
||||
_id: 'id-1',
|
||||
fields: {
|
||||
'destination.address': ['9.99.99.9'],
|
||||
'destination.port': ['6789'],
|
||||
'event.category': ['test'],
|
||||
'file.name': ['sample'],
|
||||
'host.name': ['host'],
|
||||
'process.name': ['doingThings.exe'],
|
||||
'process.parent.name': ['didThings.exe'],
|
||||
'source.address': ['1.11.11.1'],
|
||||
'source.port': ['1234'],
|
||||
'user.name': ['test-user'],
|
||||
'@timestamp': '2021-08-11T02:28:59.101Z',
|
||||
},
|
||||
};
|
||||
|
||||
const genThresholdMergedDoc = (groupedKeys: Record<string, string>) => ({
|
||||
_index: 'index-1',
|
||||
_id: 'some-id',
|
||||
_source: {
|
||||
'@timestamp': '2022-08-16T11:01:09.848Z',
|
||||
threshold_result: [Object],
|
||||
...groupedKeys,
|
||||
},
|
||||
});
|
||||
|
||||
describe('reason_formatter', () => {
|
||||
let name: string;
|
||||
let ruleName: string;
|
||||
let severity: string;
|
||||
let mergedDoc: SignalSourceHit;
|
||||
beforeAll(() => {
|
||||
name = 'my-rule';
|
||||
ruleName = 'my-rule';
|
||||
severity = 'medium';
|
||||
mergedDoc = {
|
||||
_index: 'index-1',
|
||||
_id: 'id-1',
|
||||
fields: {
|
||||
'destination.address': ['9.99.99.9'],
|
||||
'destination.port': ['6789'],
|
||||
'event.category': ['test'],
|
||||
'file.name': ['sample'],
|
||||
'host.name': ['host'],
|
||||
'process.name': ['doingThings.exe'],
|
||||
'process.parent.name': ['didThings.exe'],
|
||||
'source.address': ['1.11.11.1'],
|
||||
'source.port': ['1234'],
|
||||
'user.name': ['test-user'],
|
||||
'@timestamp': '2021-08-11T02:28:59.101Z',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe('buildReasonMessageUtil', () => {
|
||||
describe('when rule and mergedDoc are provided', () => {
|
||||
it('should return the full reason message', () => {
|
||||
expect(buildReasonMessageUtil({ name, severity, mergedDoc })).toMatchInlineSnapshot(
|
||||
expect(
|
||||
buildReasonMessageUtil({ name: ruleName, severity, mergedDoc })
|
||||
).toMatchInlineSnapshot(
|
||||
`"test event with process doingThings.exe, parent process didThings.exe, file sample, source 1.11.11.1:1234, destination 9.99.99.9:6789, by test-user on host created medium alert my-rule."`
|
||||
);
|
||||
});
|
||||
|
@ -52,7 +63,7 @@ describe('reason_formatter', () => {
|
|||
},
|
||||
};
|
||||
expect(
|
||||
buildReasonMessageUtil({ name, severity, mergedDoc: updatedMergedDoc })
|
||||
buildReasonMessageUtil({ name: ruleName, severity, mergedDoc: updatedMergedDoc })
|
||||
).toMatchInlineSnapshot(
|
||||
`"item one, item two event with process doingThings.exe, parent process didThings.exe, file sample, source 1.11.11.1:1234, destination 9.99.99.9:6789, by test-user on host created medium alert my-rule."`
|
||||
);
|
||||
|
@ -68,7 +79,7 @@ describe('reason_formatter', () => {
|
|||
},
|
||||
};
|
||||
expect(
|
||||
buildReasonMessageUtil({ name, severity, mergedDoc: updatedMergedDoc })
|
||||
buildReasonMessageUtil({ name: ruleName, severity, mergedDoc: updatedMergedDoc })
|
||||
).toMatchInlineSnapshot(
|
||||
`"test event with process doingThings.exe, parent process didThings.exe, file sample, source 1.11.11.1:1234, destination 9.99.99.9:6789, by test-user created medium alert my-rule."`
|
||||
);
|
||||
|
@ -84,7 +95,7 @@ describe('reason_formatter', () => {
|
|||
},
|
||||
};
|
||||
expect(
|
||||
buildReasonMessageUtil({ name, severity, mergedDoc: updatedMergedDoc })
|
||||
buildReasonMessageUtil({ name: ruleName, severity, mergedDoc: updatedMergedDoc })
|
||||
).toMatchInlineSnapshot(
|
||||
`"test event with process doingThings.exe, parent process didThings.exe, file sample, source 1.11.11.1:1234, destination 9.99.99.9:6789, on host created medium alert my-rule."`
|
||||
);
|
||||
|
@ -100,7 +111,7 @@ describe('reason_formatter', () => {
|
|||
},
|
||||
};
|
||||
expect(
|
||||
buildReasonMessageUtil({ name, severity, mergedDoc: noDestinationPortDoc })
|
||||
buildReasonMessageUtil({ name: ruleName, severity, mergedDoc: noDestinationPortDoc })
|
||||
).toMatchInlineSnapshot(
|
||||
`"test event with process doingThings.exe, parent process didThings.exe, file sample, source 1.11.11.1:1234, destination 9.99.99.9 by test-user on host created medium alert my-rule."`
|
||||
);
|
||||
|
@ -115,7 +126,7 @@ describe('reason_formatter', () => {
|
|||
},
|
||||
};
|
||||
expect(
|
||||
buildReasonMessageUtil({ name, severity, mergedDoc: noDestinationPortDoc })
|
||||
buildReasonMessageUtil({ name: ruleName, severity, mergedDoc: noDestinationPortDoc })
|
||||
).toMatchInlineSnapshot(
|
||||
`"test event with process doingThings.exe, parent process didThings.exe, file sample, source 1.11.11.1:1234, by test-user on host created medium alert my-rule."`
|
||||
);
|
||||
|
@ -131,7 +142,7 @@ describe('reason_formatter', () => {
|
|||
},
|
||||
};
|
||||
expect(
|
||||
buildReasonMessageUtil({ name, severity, mergedDoc: noSourcePortDoc })
|
||||
buildReasonMessageUtil({ name: ruleName, severity, mergedDoc: noSourcePortDoc })
|
||||
).toMatchInlineSnapshot(
|
||||
`"test event with process doingThings.exe, parent process didThings.exe, file sample, source 1.11.11.1 destination 9.99.99.9:6789, by test-user on host created medium alert my-rule."`
|
||||
);
|
||||
|
@ -146,7 +157,7 @@ describe('reason_formatter', () => {
|
|||
},
|
||||
};
|
||||
expect(
|
||||
buildReasonMessageUtil({ name, severity, mergedDoc: noSourcePortDoc })
|
||||
buildReasonMessageUtil({ name: ruleName, severity, mergedDoc: noSourcePortDoc })
|
||||
).toMatchInlineSnapshot(
|
||||
`"test event with process doingThings.exe, parent process didThings.exe, file sample, destination 9.99.99.9:6789, by test-user on host created medium alert my-rule."`
|
||||
);
|
||||
|
@ -163,7 +174,7 @@ describe('reason_formatter', () => {
|
|||
},
|
||||
};
|
||||
expect(
|
||||
buildReasonMessageUtil({ name, severity, mergedDoc: updatedMergedDoc })
|
||||
buildReasonMessageUtil({ name: ruleName, severity, mergedDoc: updatedMergedDoc })
|
||||
).toMatchInlineSnapshot(
|
||||
`"test event with file sample, source 1.11.11.1:1234, destination 9.99.99.9:6789, by test-user on host created medium alert my-rule."`
|
||||
);
|
||||
|
@ -180,14 +191,61 @@ describe('reason_formatter', () => {
|
|||
},
|
||||
};
|
||||
expect(
|
||||
buildReasonMessageUtil({ name, severity, mergedDoc: updatedMergedDoc })
|
||||
buildReasonMessageUtil({ name: ruleName, severity, mergedDoc: updatedMergedDoc })
|
||||
).toMatchInlineSnapshot(`"test event by test-user created medium alert my-rule."`);
|
||||
});
|
||||
});
|
||||
describe('when only rule is provided', () => {
|
||||
it('should return the reason message without host name or user name', () => {
|
||||
expect(buildReasonMessageUtil({ name, severity })).toMatchInlineSnapshot(`""`);
|
||||
expect(buildReasonMessageUtil({ name: ruleName, severity })).toMatchInlineSnapshot(`""`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(`buildReasonMessageForThresholdAlert`, () => {
|
||||
it('When thresold rule is grouped by user.name', () => {
|
||||
const userName = 'Some User Name';
|
||||
const thresholdMergedDoc = genThresholdMergedDoc({
|
||||
'user.name': userName,
|
||||
});
|
||||
expect(
|
||||
buildReasonMessageForThresholdAlert({
|
||||
name: ruleName,
|
||||
severity,
|
||||
mergedDoc: thresholdMergedDoc,
|
||||
})
|
||||
).toEqual(`event by ${userName} created ${severity} alert ${ruleName}.`);
|
||||
});
|
||||
|
||||
it('When threshold rule is grouped by host.name', () => {
|
||||
const hostName = 'Some Host Name';
|
||||
const thresholdMergedDoc = genThresholdMergedDoc({
|
||||
'host.name': hostName,
|
||||
});
|
||||
|
||||
expect(
|
||||
buildReasonMessageForThresholdAlert({
|
||||
name: ruleName,
|
||||
severity,
|
||||
mergedDoc: thresholdMergedDoc,
|
||||
})
|
||||
).toEqual(`event on ${hostName} created ${severity} alert ${ruleName}.`);
|
||||
});
|
||||
it('When threshold rule is grouped by host.name and user.name', () => {
|
||||
const hostName = 'Some Host Name';
|
||||
const userName = 'Some User Name';
|
||||
const thresholdMergedDoc = genThresholdMergedDoc({
|
||||
'host.name': hostName,
|
||||
'user.name': userName,
|
||||
});
|
||||
|
||||
expect(
|
||||
buildReasonMessageForThresholdAlert({
|
||||
name: ruleName,
|
||||
severity,
|
||||
mergedDoc: thresholdMergedDoc,
|
||||
})
|
||||
).toEqual(`event by ${userName} on ${hostName} created ${severity} alert ${ruleName}.`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@ interface ReasonFields {
|
|||
}
|
||||
const getFieldsFromDoc = (mergedDoc: SignalSourceHit) => {
|
||||
const reasonFields: ReasonFields = {};
|
||||
const docToUse = mergedDoc?.fields || mergedDoc;
|
||||
const docToUse = mergedDoc?.fields || mergedDoc?._source || mergedDoc;
|
||||
|
||||
reasonFields.destinationAddress = getOr(null, 'destination.address', docToUse);
|
||||
reasonFields.destinationPort = getOr(null, 'destination.port', docToUse);
|
||||
|
|
|
@ -1019,7 +1019,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
},
|
||||
],
|
||||
[ALERT_WORKFLOW_STATUS]: 'open',
|
||||
[ALERT_REASON]: `event created high alert Signal Testing Query.`,
|
||||
[ALERT_REASON]: `event with process sshd, created high alert Signal Testing Query.`,
|
||||
[ALERT_RULE_UUID]: fullSignal[ALERT_RULE_UUID],
|
||||
[ALERT_ORIGINAL_TIME]: fullSignal[ALERT_ORIGINAL_TIME],
|
||||
[ALERT_DEPTH]: 1,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue