[Security Solution] Migrates siem-detection-engine-rule-status alertId to saved object references array (#114585)
## Summary Resolves (a portion of) https://github.com/elastic/kibana/issues/107068 for the `siem-detection-engine-rule-status` type by migrating the `alertId` to be within the `SO references[]`. Based on: https://github.com/elastic/kibana/pull/113577 * Migrates the legacy `siem-detection-engine-rule-status` `alertId` to saved object references array * Adds an e2e test for `siem-detection-engine-rule-status` * Breaks out `siem-detection-engine-rule-status` & `security-rule` SO's to their own dedicated files/directories, and cleaned up typings/imports Before migration you can observe the existing data structure of `siem-detection-engine-rule-status` via Dev tools as follows: ``` GET .kibana/_search { "size": 10000, "query": { "term": { "type": { "value": "siem-detection-engine-rule-status" } } } } ``` ``` JSON { "_index" : ".kibana-spong_8.0.0_001", "_id" : "siem-detection-engine-rule-status:d580f1a0-2afe-11ec-8621-8d6bfcdfd75e", "_score" : 2.150102, "_source" : { "siem-detection-engine-rule-status" : { "alertId" : "d62d2980-27c4-11ec-92b0-f7b47106bb35", <-- alertId which we want in the references array and removed "statusDate" : "2021-10-12T01:50:52.898Z", "status" : "failed", "lastFailureAt" : "2021-10-12T01:50:52.898Z", "lastSuccessAt" : "2021-10-12T01:18:29.195Z", "lastFailureMessage" : "6 minutes (385585ms) were not queried between this rule execution and the last execution, so signals may have been missed. Consider increasing your look behind time or adding more Kibana instances. name: \"I am the Host who Names!\" id: \"d62d2980-27c4-11ec-92b0-f7b47106bb35\" rule id: \"214ccef6-e98e-493a-98c5-5bcc2d497b79\" signals index: \".siem-signals-spong-default\"", "lastSuccessMessage" : "succeeded", "gap" : "6 minutes", "lastLookBackDate" : "2021-10-07T23:43:27.961Z" }, "type" : "siem-detection-engine-rule-status", "references" : [ ], "coreMigrationVersion" : "7.14.0", "updated_at" : "2021-10-12T01:50:53.404Z" } } ``` Post migration the data structure should be updated as follows: ``` JSON { "_index": ".kibana-spong_8.0.0_001", "_id": "siem-detection-engine-rule-status:d580f1a0-2afe-11ec-8621-8d6bfcdfd75e", "_score": 2.1865466, "_source": { "siem-detection-engine-rule-status": { "statusDate": "2021-10-12T01:50:52.898Z", <-- alertId is no more! "status": "failed", "lastFailureAt": "2021-10-12T01:50:52.898Z", "lastSuccessAt": "2021-10-12T01:18:29.195Z", "lastFailureMessage": "6 minutes (385585ms) were not queried between this rule execution and the last execution, so signals may have been missed. Consider increasing your look behind time or adding more Kibana instances. name: \"I am the Host who Names!\" id: \"d62d2980-27c4-11ec-92b0-f7b47106bb35\" rule id: \"214ccef6-e98e-493a-98c5-5bcc2d497b79\" signals index: \".siem-signals-spong-default\"", "lastSuccessMessage": "succeeded", "gap": "6 minutes", "lastLookBackDate": "2021-10-07T23:43:27.961Z" }, "type": "siem-detection-engine-rule-status", "references": [ { "id": "d62d2980-27c4-11ec-92b0-f7b47106bb35", <-- previous alertId has been converted to references[] "type": "alert", "name": "alert_0" } ], "migrationVersion": { "siem-detection-engine-rule-status": "7.16.0" }, "coreMigrationVersion": "8.0.0", "updated_at": "2021-10-12T01:50:53.406Z" } }, ``` #### Manual testing --- There are e2e tests but for any manual testing or verification you can do the following: ##### Manual upgrade test If you have a 7.15.0 system and can migrate it forward that is the most straight forward way to ensure this does migrate correctly. You should see that the `Rule Monitoring` table and Rule Details `Failure History` table continue to function without error. ##### Downgrade via script and test migration on kibana reboot If you have a migrated `Rule Status SO` and want to test the migration, you can run the below script to downgrade the status SO then restart Kibana and observe the migration on startup. Note: Since this PR removes the mapping, you would need to [update the SO mapping](https://github.com/elastic/kibana/pull/114585/files#r729386126) to include `alertId` again else you will receive a strict/dynamic mapping error. ```json # Replace id w/ correct Rule Status SO id of existing migrated object POST .kibana/_update/siem-detection-engine-rule-status:d580ca91-2afe-11ec-8621-8d6bfcdfd75e { "script" : { "source": """ ctx._source.migrationVersion['siem-detection-engine-rule-status'] = "7.15.0"; ctx._source['siem-detection-engine-rule-status'].alertId = ctx._source.references[0].id; ctx._source.references.remove(0); """, "lang": "painless" } } ``` Restart Kibana and now it should be migrated correctly and you shouldn't see any errors in your console. You should also see that the `Rule Monitoring` table and Rule Details `Failure History` table continue to function without error. ### Checklist Delete any items that are not applicable to this PR. - [ ] ~[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials~ - [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 - [x] 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) Co-authored-by: Georgii Gorbachev <georgii.gorbachev@elastic.co> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
596b2e3460
commit
fe979e4932
|
@ -16,6 +16,7 @@ import { sortOrderSchema } from './common_schemas';
|
|||
* - filter
|
||||
* - histogram
|
||||
* - nested
|
||||
* - reverse_nested
|
||||
* - terms
|
||||
*
|
||||
* Not implemented:
|
||||
|
@ -37,7 +38,6 @@ import { sortOrderSchema } from './common_schemas';
|
|||
* - parent
|
||||
* - range
|
||||
* - rare_terms
|
||||
* - reverse_nested
|
||||
* - sampler
|
||||
* - significant_terms
|
||||
* - significant_text
|
||||
|
@ -76,6 +76,9 @@ export const bucketAggsSchemas: Record<string, ObjectType> = {
|
|||
nested: s.object({
|
||||
path: s.string(),
|
||||
}),
|
||||
reverse_nested: s.object({
|
||||
path: s.maybe(s.string()),
|
||||
}),
|
||||
terms: s.object({
|
||||
field: s.maybe(s.string()),
|
||||
collect_mode: s.maybe(s.string()),
|
||||
|
|
|
@ -479,7 +479,6 @@ export const getRuleExecutionStatuses = (): Array<
|
|||
type: 'my-type',
|
||||
id: 'e0b86950-4e9f-11ea-bdbd-07b56aa159b3',
|
||||
attributes: {
|
||||
alertId: '04128c15-0d1b-4716-a4c5-46997ac7f3bc',
|
||||
statusDate: '2020-02-18T15:26:49.783Z',
|
||||
status: RuleExecutionStatus.succeeded,
|
||||
lastFailureAt: undefined,
|
||||
|
@ -492,7 +491,13 @@ export const getRuleExecutionStatuses = (): Array<
|
|||
bulkCreateTimeDurations: ['800.43'],
|
||||
},
|
||||
score: 1,
|
||||
references: [],
|
||||
references: [
|
||||
{
|
||||
id: '04128c15-0d1b-4716-a4c5-46997ac7f3bc',
|
||||
type: 'alert',
|
||||
name: 'alert_0',
|
||||
},
|
||||
],
|
||||
updated_at: '2020-02-18T15:26:51.333Z',
|
||||
version: 'WzQ2LDFd',
|
||||
},
|
||||
|
@ -500,7 +505,6 @@ export const getRuleExecutionStatuses = (): Array<
|
|||
type: 'my-type',
|
||||
id: '91246bd0-5261-11ea-9650-33b954270f67',
|
||||
attributes: {
|
||||
alertId: '1ea5a820-4da1-4e82-92a1-2b43a7bece08',
|
||||
statusDate: '2020-02-18T15:15:58.806Z',
|
||||
status: RuleExecutionStatus.failed,
|
||||
lastFailureAt: '2020-02-18T15:15:58.806Z',
|
||||
|
@ -514,7 +518,13 @@ export const getRuleExecutionStatuses = (): Array<
|
|||
bulkCreateTimeDurations: ['800.43'],
|
||||
},
|
||||
score: 1,
|
||||
references: [],
|
||||
references: [
|
||||
{
|
||||
id: '1ea5a820-4da1-4e82-92a1-2b43a7bece08',
|
||||
type: 'alert',
|
||||
name: 'alert_0',
|
||||
},
|
||||
],
|
||||
updated_at: '2020-02-18T15:15:58.860Z',
|
||||
version: 'WzMyLDFd',
|
||||
},
|
||||
|
@ -523,7 +533,6 @@ export const getRuleExecutionStatuses = (): Array<
|
|||
export const getFindBulkResultStatus = (): FindBulkExecutionLogResponse => ({
|
||||
'04128c15-0d1b-4716-a4c5-46997ac7f3bd': [
|
||||
{
|
||||
alertId: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
|
||||
statusDate: '2020-02-18T15:26:49.783Z',
|
||||
status: RuleExecutionStatus.succeeded,
|
||||
lastFailureAt: undefined,
|
||||
|
@ -538,7 +547,6 @@ export const getFindBulkResultStatus = (): FindBulkExecutionLogResponse => ({
|
|||
],
|
||||
'1ea5a820-4da1-4e82-92a1-2b43a7bece08': [
|
||||
{
|
||||
alertId: '1ea5a820-4da1-4e82-92a1-2b43a7bece08',
|
||||
statusDate: '2020-02-18T15:15:58.806Z',
|
||||
status: RuleExecutionStatus.failed,
|
||||
lastFailureAt: '2020-02-18T15:15:58.806Z',
|
||||
|
|
|
@ -31,7 +31,7 @@ import { updatePrepackagedRules } from '../../rules/update_prepacked_rules';
|
|||
import { getRulesToInstall } from '../../rules/get_rules_to_install';
|
||||
import { getRulesToUpdate } from '../../rules/get_rules_to_update';
|
||||
import { getExistingPrepackagedRules } from '../../rules/get_existing_prepackaged_rules';
|
||||
import { ruleAssetSavedObjectsClientFactory } from '../../rules/rule_asset_saved_objects_client';
|
||||
import { ruleAssetSavedObjectsClientFactory } from '../../rules/rule_asset/rule_asset_saved_objects_client';
|
||||
|
||||
import { buildSiemResponse } from '../utils';
|
||||
import { RulesClient } from '../../../../../../alerting/server';
|
||||
|
|
|
@ -20,7 +20,7 @@ import { getRulesToUpdate } from '../../rules/get_rules_to_update';
|
|||
import { findRules } from '../../rules/find_rules';
|
||||
import { getLatestPrepackagedRules } from '../../rules/get_prepackaged_rules';
|
||||
import { getExistingPrepackagedRules } from '../../rules/get_existing_prepackaged_rules';
|
||||
import { ruleAssetSavedObjectsClientFactory } from '../../rules/rule_asset_saved_objects_client';
|
||||
import { ruleAssetSavedObjectsClientFactory } from '../../rules/rule_asset/rule_asset_saved_objects_client';
|
||||
import { buildFrameworkRequest } from '../../../timeline/utils/common';
|
||||
import { ConfigType } from '../../../../config';
|
||||
import { SetupPlugins } from '../../../../plugin';
|
||||
|
|
|
@ -136,16 +136,16 @@ describe.each([
|
|||
|
||||
describe('mergeStatuses', () => {
|
||||
it('merges statuses and converts from camelCase saved object to snake_case HTTP response', () => {
|
||||
//
|
||||
const statusOne = exampleRuleStatus();
|
||||
statusOne.attributes.status = RuleExecutionStatus.failed;
|
||||
const statusTwo = exampleRuleStatus();
|
||||
statusTwo.attributes.status = RuleExecutionStatus.failed;
|
||||
const currentStatus = exampleRuleStatus();
|
||||
const foundRules = [currentStatus.attributes, statusOne.attributes, statusTwo.attributes];
|
||||
const res = mergeStatuses(currentStatus.attributes.alertId, foundRules, {
|
||||
const res = mergeStatuses(currentStatus.references[0].id, foundRules, {
|
||||
'myfakealertid-8cfac': {
|
||||
current_status: {
|
||||
alert_id: 'myfakealertid-8cfac',
|
||||
status_date: '2020-03-27T22:55:59.517Z',
|
||||
status: RuleExecutionStatus.succeeded,
|
||||
last_failure_at: null,
|
||||
|
@ -163,7 +163,6 @@ describe.each([
|
|||
expect(res).toEqual({
|
||||
'myfakealertid-8cfac': {
|
||||
current_status: {
|
||||
alert_id: 'myfakealertid-8cfac',
|
||||
status_date: '2020-03-27T22:55:59.517Z',
|
||||
status: 'succeeded',
|
||||
last_failure_at: null,
|
||||
|
@ -179,7 +178,6 @@ describe.each([
|
|||
},
|
||||
'f4b8e31d-cf93-4bde-a265-298bde885cd7': {
|
||||
current_status: {
|
||||
alert_id: 'f4b8e31d-cf93-4bde-a265-298bde885cd7',
|
||||
status_date: '2020-03-27T22:55:59.517Z',
|
||||
status: 'succeeded',
|
||||
last_failure_at: null,
|
||||
|
@ -193,7 +191,6 @@ describe.each([
|
|||
},
|
||||
failures: [
|
||||
{
|
||||
alert_id: 'f4b8e31d-cf93-4bde-a265-298bde885cd7',
|
||||
status_date: '2020-03-27T22:55:59.517Z',
|
||||
status: 'failed',
|
||||
last_failure_at: null,
|
||||
|
@ -206,7 +203,6 @@ describe.each([
|
|||
last_look_back_date: null, // NOTE: This is no longer used on the UI, but left here in case users are using it within the API
|
||||
},
|
||||
{
|
||||
alert_id: 'f4b8e31d-cf93-4bde-a265-298bde885cd7',
|
||||
status_date: '2020-03-27T22:55:59.517Z',
|
||||
status: 'failed',
|
||||
last_failure_at: null,
|
||||
|
|
|
@ -42,7 +42,7 @@ export class EventLogAdapter implements IRuleExecutionLogClient {
|
|||
}
|
||||
|
||||
public async update(args: UpdateExecutionLogArgs) {
|
||||
const { attributes, spaceId, ruleName, ruleType } = args;
|
||||
const { attributes, spaceId, ruleId, ruleName, ruleType } = args;
|
||||
|
||||
await this.savedObjectsAdapter.update(args);
|
||||
|
||||
|
@ -51,7 +51,7 @@ export class EventLogAdapter implements IRuleExecutionLogClient {
|
|||
this.eventLogClient.logStatusChange({
|
||||
ruleName,
|
||||
ruleType,
|
||||
ruleId: attributes.alertId,
|
||||
ruleId,
|
||||
newStatus: attributes.status,
|
||||
spaceId,
|
||||
});
|
||||
|
|
|
@ -5,27 +5,33 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import {
|
||||
SavedObjectsClientContract,
|
||||
SavedObject,
|
||||
SavedObjectsUpdateResponse,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectsCreateOptions,
|
||||
SavedObjectsFindOptions,
|
||||
SavedObjectsFindOptionsReference,
|
||||
SavedObjectsFindResult,
|
||||
} from '../../../../../../../../src/core/server';
|
||||
import { ruleStatusSavedObjectType } from '../../rules/saved_object_mappings';
|
||||
SavedObjectsUpdateResponse,
|
||||
} from 'kibana/server';
|
||||
import { get } from 'lodash';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyRuleStatusSavedObjectType } from '../../rules/legacy_rule_status/legacy_rule_status_saved_object_mappings';
|
||||
import { IRuleStatusSOAttributes } from '../../rules/types';
|
||||
import { buildChunkedOrFilter } from '../../signals/utils';
|
||||
|
||||
export interface RuleStatusSavedObjectsClient {
|
||||
find: (
|
||||
options?: Omit<SavedObjectsFindOptions, 'type'>
|
||||
) => Promise<Array<SavedObjectsFindResult<IRuleStatusSOAttributes>>>;
|
||||
findBulk: (ids: string[], statusesPerId: number) => Promise<FindBulkResponse>;
|
||||
create: (attributes: IRuleStatusSOAttributes) => Promise<SavedObject<IRuleStatusSOAttributes>>;
|
||||
create: (
|
||||
attributes: IRuleStatusSOAttributes,
|
||||
options: SavedObjectsCreateOptions
|
||||
) => Promise<SavedObject<IRuleStatusSOAttributes>>;
|
||||
update: (
|
||||
id: string,
|
||||
attributes: Partial<IRuleStatusSOAttributes>
|
||||
attributes: Partial<IRuleStatusSOAttributes>,
|
||||
options: SavedObjectsCreateOptions
|
||||
) => Promise<SavedObjectsUpdateResponse<IRuleStatusSOAttributes>>;
|
||||
delete: (id: string) => Promise<{}>;
|
||||
}
|
||||
|
@ -35,7 +41,7 @@ export interface FindBulkResponse {
|
|||
}
|
||||
|
||||
/**
|
||||
* @pdeprecated Use RuleExecutionLogClient instead
|
||||
* @deprecated Use RuleExecutionLogClient instead
|
||||
*/
|
||||
export const ruleStatusSavedObjectsClientFactory = (
|
||||
savedObjectsClient: SavedObjectsClientContract
|
||||
|
@ -43,7 +49,7 @@ export const ruleStatusSavedObjectsClientFactory = (
|
|||
find: async (options) => {
|
||||
const result = await savedObjectsClient.find<IRuleStatusSOAttributes>({
|
||||
...options,
|
||||
type: ruleStatusSavedObjectType,
|
||||
type: legacyRuleStatusSavedObjectType,
|
||||
});
|
||||
return result.saved_objects;
|
||||
},
|
||||
|
@ -51,47 +57,64 @@ export const ruleStatusSavedObjectsClientFactory = (
|
|||
if (ids.length === 0) {
|
||||
return {};
|
||||
}
|
||||
const filter = buildChunkedOrFilter(`${ruleStatusSavedObjectType}.attributes.alertId`, ids);
|
||||
const references = ids.map<SavedObjectsFindOptionsReference>((alertId) => ({
|
||||
id: alertId,
|
||||
type: 'alert',
|
||||
}));
|
||||
const order: 'desc' = 'desc';
|
||||
const aggs = {
|
||||
alertIds: {
|
||||
terms: {
|
||||
field: `${ruleStatusSavedObjectType}.attributes.alertId`,
|
||||
size: ids.length,
|
||||
references: {
|
||||
nested: {
|
||||
path: `${legacyRuleStatusSavedObjectType}.references`,
|
||||
},
|
||||
aggs: {
|
||||
most_recent_statuses: {
|
||||
top_hits: {
|
||||
sort: [
|
||||
{
|
||||
[`${ruleStatusSavedObjectType}.statusDate`]: {
|
||||
order,
|
||||
alertIds: {
|
||||
terms: {
|
||||
field: `${legacyRuleStatusSavedObjectType}.references.id`,
|
||||
size: ids.length,
|
||||
},
|
||||
aggs: {
|
||||
rule_status: {
|
||||
reverse_nested: {},
|
||||
aggs: {
|
||||
most_recent_statuses: {
|
||||
top_hits: {
|
||||
sort: [
|
||||
{
|
||||
[`${legacyRuleStatusSavedObjectType}.statusDate`]: {
|
||||
order,
|
||||
},
|
||||
},
|
||||
],
|
||||
size: statusesPerId,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
size: statusesPerId,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const results = await savedObjectsClient.find({
|
||||
filter,
|
||||
hasReference: references,
|
||||
aggs,
|
||||
type: ruleStatusSavedObjectType,
|
||||
type: legacyRuleStatusSavedObjectType,
|
||||
perPage: 0,
|
||||
});
|
||||
const buckets = get(results, 'aggregations.alertIds.buckets');
|
||||
const buckets = get(results, 'aggregations.references.alertIds.buckets');
|
||||
return buckets.reduce((acc: Record<string, unknown>, bucket: unknown) => {
|
||||
const key = get(bucket, 'key');
|
||||
const hits = get(bucket, 'most_recent_statuses.hits.hits');
|
||||
const hits = get(bucket, 'rule_status.most_recent_statuses.hits.hits');
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const statuses = hits.map((hit: any) => hit._source['siem-detection-engine-rule-status']);
|
||||
acc[key] = statuses;
|
||||
acc[key] = hits.map((hit: any) => hit._source[legacyRuleStatusSavedObjectType]);
|
||||
return acc;
|
||||
}, {});
|
||||
},
|
||||
create: (attributes) => savedObjectsClient.create(ruleStatusSavedObjectType, attributes),
|
||||
update: (id, attributes) => savedObjectsClient.update(ruleStatusSavedObjectType, id, attributes),
|
||||
delete: (id) => savedObjectsClient.delete(ruleStatusSavedObjectType, id),
|
||||
create: (attributes, options) => {
|
||||
return savedObjectsClient.create(legacyRuleStatusSavedObjectType, attributes, options);
|
||||
},
|
||||
update: (id, attributes, options) =>
|
||||
savedObjectsClient.update(legacyRuleStatusSavedObjectType, id, attributes, options),
|
||||
delete: (id) => savedObjectsClient.delete(legacyRuleStatusSavedObjectType, id),
|
||||
});
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { SavedObject } from 'src/core/server';
|
||||
import { SavedObject, SavedObjectReference } from 'src/core/server';
|
||||
import { SavedObjectsClientContract } from '../../../../../../../../src/core/server';
|
||||
import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyGetRuleReference } from '../../rules/legacy_rule_status/legacy_utils';
|
||||
|
||||
import { IRuleStatusSOAttributes } from '../../rules/types';
|
||||
import {
|
||||
RuleStatusSavedObjectsClient,
|
||||
|
@ -51,7 +54,7 @@ export class SavedObjectsAdapter implements IRuleExecutionLogClient {
|
|||
sortField: 'statusDate',
|
||||
sortOrder: 'desc',
|
||||
search: ruleId,
|
||||
searchFields: ['alertId'],
|
||||
searchFields: ['references.id'],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -59,8 +62,9 @@ export class SavedObjectsAdapter implements IRuleExecutionLogClient {
|
|||
return this.ruleStatusClient.findBulk(ruleIds, logsCount);
|
||||
}
|
||||
|
||||
public async update({ id, attributes }: UpdateExecutionLogArgs) {
|
||||
await this.ruleStatusClient.update(id, attributes);
|
||||
public async update({ id, attributes, ruleId }: UpdateExecutionLogArgs) {
|
||||
const references: SavedObjectReference[] = [legacyGetRuleReference(ruleId)];
|
||||
await this.ruleStatusClient.update(id, attributes, { references });
|
||||
}
|
||||
|
||||
public async delete(id: string) {
|
||||
|
@ -68,31 +72,39 @@ export class SavedObjectsAdapter implements IRuleExecutionLogClient {
|
|||
}
|
||||
|
||||
public async logExecutionMetrics({ ruleId, metrics }: LogExecutionMetricsArgs) {
|
||||
const references: SavedObjectReference[] = [legacyGetRuleReference(ruleId)];
|
||||
const [currentStatus] = await this.getOrCreateRuleStatuses(ruleId);
|
||||
|
||||
await this.ruleStatusClient.update(currentStatus.id, {
|
||||
...currentStatus.attributes,
|
||||
...convertMetricFields(metrics),
|
||||
});
|
||||
await this.ruleStatusClient.update(
|
||||
currentStatus.id,
|
||||
{
|
||||
...currentStatus.attributes,
|
||||
...convertMetricFields(metrics),
|
||||
},
|
||||
{ references }
|
||||
);
|
||||
}
|
||||
|
||||
private createNewRuleStatus = async (
|
||||
ruleId: string
|
||||
): Promise<SavedObject<IRuleStatusSOAttributes>> => {
|
||||
const references: SavedObjectReference[] = [legacyGetRuleReference(ruleId)];
|
||||
const now = new Date().toISOString();
|
||||
return this.ruleStatusClient.create({
|
||||
alertId: ruleId,
|
||||
statusDate: now,
|
||||
status: RuleExecutionStatus['going to run'],
|
||||
lastFailureAt: null,
|
||||
lastSuccessAt: null,
|
||||
lastFailureMessage: null,
|
||||
lastSuccessMessage: null,
|
||||
gap: null,
|
||||
bulkCreateTimeDurations: [],
|
||||
searchAfterTimeDurations: [],
|
||||
lastLookBackDate: null,
|
||||
});
|
||||
return this.ruleStatusClient.create(
|
||||
{
|
||||
statusDate: now,
|
||||
status: RuleExecutionStatus['going to run'],
|
||||
lastFailureAt: null,
|
||||
lastSuccessAt: null,
|
||||
lastFailureMessage: null,
|
||||
lastSuccessMessage: null,
|
||||
gap: null,
|
||||
bulkCreateTimeDurations: [],
|
||||
searchAfterTimeDurations: [],
|
||||
lastLookBackDate: null,
|
||||
},
|
||||
{ references }
|
||||
);
|
||||
};
|
||||
|
||||
private getOrCreateRuleStatuses = async (
|
||||
|
@ -112,6 +124,8 @@ export class SavedObjectsAdapter implements IRuleExecutionLogClient {
|
|||
};
|
||||
|
||||
public async logStatusChange({ newStatus, ruleId, message, metrics }: LogStatusChangeArgs) {
|
||||
const references: SavedObjectReference[] = [legacyGetRuleReference(ruleId)];
|
||||
|
||||
switch (newStatus) {
|
||||
case RuleExecutionStatus['going to run']:
|
||||
case RuleExecutionStatus.succeeded:
|
||||
|
@ -119,10 +133,14 @@ export class SavedObjectsAdapter implements IRuleExecutionLogClient {
|
|||
case RuleExecutionStatus['partial failure']: {
|
||||
const [currentStatus] = await this.getOrCreateRuleStatuses(ruleId);
|
||||
|
||||
await this.ruleStatusClient.update(currentStatus.id, {
|
||||
...currentStatus.attributes,
|
||||
...buildRuleStatusAttributes(newStatus, message, metrics),
|
||||
});
|
||||
await this.ruleStatusClient.update(
|
||||
currentStatus.id,
|
||||
{
|
||||
...currentStatus.attributes,
|
||||
...buildRuleStatusAttributes(newStatus, message, metrics),
|
||||
},
|
||||
{ references }
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -137,8 +155,8 @@ export class SavedObjectsAdapter implements IRuleExecutionLogClient {
|
|||
};
|
||||
|
||||
// We always update the newest status, so to 'persist' a failure we push a copy to the head of the list
|
||||
await this.ruleStatusClient.update(currentStatus.id, failureAttributes);
|
||||
const lastStatus = await this.ruleStatusClient.create(failureAttributes);
|
||||
await this.ruleStatusClient.update(currentStatus.id, failureAttributes, { references });
|
||||
const lastStatus = await this.ruleStatusClient.create(failureAttributes, { references });
|
||||
|
||||
// drop oldest failures
|
||||
const oldStatuses = [lastStatus, ...ruleStatuses].slice(MAX_RULE_STATUSES);
|
||||
|
|
|
@ -53,6 +53,7 @@ export interface LogStatusChangeArgs {
|
|||
export interface UpdateExecutionLogArgs {
|
||||
id: string;
|
||||
attributes: IRuleStatusSOAttributes;
|
||||
ruleId: string;
|
||||
ruleName: string;
|
||||
ruleType: string;
|
||||
spaceId: string;
|
||||
|
|
|
@ -26,7 +26,6 @@ describe('deleteRules', () => {
|
|||
type: '',
|
||||
references: [],
|
||||
attributes: {
|
||||
alertId: 'alertId',
|
||||
statusDate: '',
|
||||
lastFailureAt: null,
|
||||
lastFailureMessage: null,
|
||||
|
|
|
@ -44,6 +44,7 @@ export const enableRule = async ({
|
|||
const currentStatusToDisable = ruleCurrentStatus[0];
|
||||
await ruleStatusClient.update({
|
||||
id: currentStatusToDisable.id,
|
||||
ruleId: rule.id,
|
||||
ruleName: rule.name,
|
||||
ruleType: rule.alertTypeId,
|
||||
attributes: {
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
|
||||
// TODO: convert rules files to TS and add explicit type definitions
|
||||
import { rawRules } from './prepackaged_rules';
|
||||
import { RuleAssetSavedObjectsClient } from './rule_asset_saved_objects_client';
|
||||
import { RuleAssetSavedObjectsClient } from './rule_asset/rule_asset_saved_objects_client';
|
||||
import { IRuleAssetSOAttributes } from './types';
|
||||
import { SavedObjectAttributes } from '../../../../../../../src/core/types';
|
||||
import { ConfigType } from '../../../config';
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
SavedObjectMigrationFn,
|
||||
SavedObjectReference,
|
||||
SavedObjectSanitizedDoc,
|
||||
SavedObjectUnsanitizedDoc,
|
||||
} from 'kibana/server';
|
||||
import { isString } from 'lodash/fp';
|
||||
import { truncateMessage } from '../../rule_execution_log';
|
||||
import { IRuleSavedAttributesSavedObjectAttributes } from '../types';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyGetRuleReference } from './legacy_utils';
|
||||
|
||||
export const truncateMessageFields: SavedObjectMigrationFn<Record<string, unknown>> = (doc) => {
|
||||
const { lastFailureMessage, lastSuccessMessage, ...restAttributes } = doc.attributes;
|
||||
|
||||
return {
|
||||
...doc,
|
||||
attributes: {
|
||||
lastFailureMessage: truncateMessage(lastFailureMessage),
|
||||
lastSuccessMessage: truncateMessage(lastSuccessMessage),
|
||||
...restAttributes,
|
||||
},
|
||||
references: doc.references ?? [],
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* This side-car rule status SO is deprecated and is to be replaced by the RuleExecutionLog on Event-Log and
|
||||
* additional fields on the Alerting Framework Rule SO.
|
||||
*
|
||||
* @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x)
|
||||
*/
|
||||
export const legacyRuleStatusSavedObjectMigration = {
|
||||
'7.15.2': truncateMessageFields,
|
||||
'7.16.0': (
|
||||
doc: SavedObjectUnsanitizedDoc<IRuleSavedAttributesSavedObjectAttributes>
|
||||
): SavedObjectSanitizedDoc<IRuleSavedAttributesSavedObjectAttributes> => {
|
||||
return legacyMigrateRuleAlertIdSOReferences(doc);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* This migrates alertId within legacy `siem-detection-engine-rule-status` to saved object references on an upgrade.
|
||||
* We only migrate alertId if we find these conditions:
|
||||
* - alertId is a string and not null, undefined, or malformed data.
|
||||
* - The existing references do not already have a alertId found within it.
|
||||
*
|
||||
* Some of these issues could crop up during either user manual errors of modifying things, earlier migration
|
||||
* issues, etc... so we are safer to check them as possibilities
|
||||
*
|
||||
* @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x)
|
||||
* @param doc The document having an alertId to migrate into references
|
||||
* @returns The document migrated with saved object references
|
||||
*/
|
||||
export const legacyMigrateRuleAlertIdSOReferences = (
|
||||
doc: SavedObjectUnsanitizedDoc<IRuleSavedAttributesSavedObjectAttributes>
|
||||
): SavedObjectSanitizedDoc<IRuleSavedAttributesSavedObjectAttributes> => {
|
||||
const { references } = doc;
|
||||
|
||||
// Isolate alertId from the doc
|
||||
const { alertId, ...attributesWithoutAlertId } = doc.attributes;
|
||||
const existingReferences = references ?? [];
|
||||
|
||||
if (!isString(alertId)) {
|
||||
// early return if alertId is not a string as expected
|
||||
return { ...doc, references: existingReferences };
|
||||
} else {
|
||||
const alertReferences = legacyMigrateAlertId({
|
||||
alertId,
|
||||
existingReferences,
|
||||
});
|
||||
|
||||
return {
|
||||
...doc,
|
||||
attributes: {
|
||||
...attributesWithoutAlertId.attributes,
|
||||
},
|
||||
references: [...existingReferences, ...alertReferences],
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a helper to migrate "alertId"
|
||||
*
|
||||
* @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x)
|
||||
*
|
||||
* @param existingReferences The existing saved object references
|
||||
* @param alertId The alertId to migrate
|
||||
*
|
||||
* @returns The savedObjectReferences migrated
|
||||
*/
|
||||
export const legacyMigrateAlertId = ({
|
||||
existingReferences,
|
||||
alertId,
|
||||
}: {
|
||||
existingReferences: SavedObjectReference[];
|
||||
alertId: string;
|
||||
}): SavedObjectReference[] => {
|
||||
const existingReferenceFound = existingReferences.find((reference) => {
|
||||
return reference.id === alertId && reference.type === 'alert';
|
||||
});
|
||||
if (existingReferenceFound) {
|
||||
return [];
|
||||
} else {
|
||||
return [legacyGetRuleReference(alertId)];
|
||||
}
|
||||
};
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { SavedObjectsType } from 'kibana/server';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyRuleStatusSavedObjectMigration } from './legacy_migrations';
|
||||
|
||||
/**
|
||||
* This side-car rule status SO is deprecated and is to be replaced by the RuleExecutionLog on Event-Log and
|
||||
* additional fields on the Alerting Framework Rule SO.
|
||||
*
|
||||
* @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x)
|
||||
*/
|
||||
export const legacyRuleStatusSavedObjectType = 'siem-detection-engine-rule-status';
|
||||
|
||||
/**
|
||||
* This side-car rule status SO is deprecated and is to be replaced by the RuleExecutionLog on Event-Log and
|
||||
* additional fields on the Alerting Framework Rule SO.
|
||||
*
|
||||
* @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x)
|
||||
*/
|
||||
export const ruleStatusSavedObjectMappings: SavedObjectsType['mappings'] = {
|
||||
properties: {
|
||||
status: {
|
||||
type: 'keyword',
|
||||
},
|
||||
statusDate: {
|
||||
type: 'date',
|
||||
},
|
||||
lastFailureAt: {
|
||||
type: 'date',
|
||||
},
|
||||
lastSuccessAt: {
|
||||
type: 'date',
|
||||
},
|
||||
lastFailureMessage: {
|
||||
type: 'text',
|
||||
},
|
||||
lastSuccessMessage: {
|
||||
type: 'text',
|
||||
},
|
||||
lastLookBackDate: {
|
||||
type: 'date',
|
||||
},
|
||||
gap: {
|
||||
type: 'text',
|
||||
},
|
||||
bulkCreateTimeDurations: {
|
||||
type: 'float',
|
||||
},
|
||||
searchAfterTimeDurations: {
|
||||
type: 'float',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* This side-car rule status SO is deprecated and is to be replaced by the RuleExecutionLog on Event-Log and
|
||||
* additional fields on the Alerting Framework Rule SO.
|
||||
*
|
||||
* @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x)
|
||||
*/
|
||||
export const legacyRuleStatusType: SavedObjectsType = {
|
||||
name: legacyRuleStatusSavedObjectType,
|
||||
hidden: false,
|
||||
namespaceType: 'single',
|
||||
mappings: ruleStatusSavedObjectMappings,
|
||||
migrations: legacyRuleStatusSavedObjectMigration,
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Given an id this returns a legacy rule reference.
|
||||
* @param id The id of the alert
|
||||
* @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x)
|
||||
*/
|
||||
export const legacyGetRuleReference = (id: string) => ({
|
||||
id,
|
||||
type: 'alert',
|
||||
name: 'alert_0',
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { SavedObjectsType } from '../../../../../../../../src/core/server';
|
||||
|
||||
export const ruleAssetSavedObjectType = 'security-rule';
|
||||
|
||||
export const ruleAssetSavedObjectMappings: SavedObjectsType['mappings'] = {
|
||||
dynamic: false,
|
||||
properties: {
|
||||
name: {
|
||||
type: 'keyword',
|
||||
},
|
||||
rule_id: {
|
||||
type: 'keyword',
|
||||
},
|
||||
version: {
|
||||
type: 'long',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ruleAssetType: SavedObjectsType = {
|
||||
name: ruleAssetSavedObjectType,
|
||||
hidden: false,
|
||||
namespaceType: 'agnostic',
|
||||
mappings: ruleAssetSavedObjectMappings,
|
||||
};
|
|
@ -9,9 +9,9 @@ import {
|
|||
SavedObjectsClientContract,
|
||||
SavedObjectsFindOptions,
|
||||
SavedObjectsFindResponse,
|
||||
} from '../../../../../../../src/core/server';
|
||||
import { ruleAssetSavedObjectType } from '../rules/saved_object_mappings';
|
||||
import { IRuleAssetSavedObject } from '../rules/types';
|
||||
} from 'kibana/server';
|
||||
import { ruleAssetSavedObjectType } from './rule_asset_saved_object_mappings';
|
||||
import { IRuleAssetSavedObject } from '../types';
|
||||
|
||||
const DEFAULT_PAGE_SIZE = 100;
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { SavedObjectsType, SavedObjectMigrationFn } from 'kibana/server';
|
||||
import { truncateMessage } from '../rule_execution_log';
|
||||
|
||||
export const ruleStatusSavedObjectType = 'siem-detection-engine-rule-status';
|
||||
|
||||
export const ruleStatusSavedObjectMappings: SavedObjectsType['mappings'] = {
|
||||
properties: {
|
||||
alertId: {
|
||||
type: 'keyword',
|
||||
},
|
||||
status: {
|
||||
type: 'keyword',
|
||||
},
|
||||
statusDate: {
|
||||
type: 'date',
|
||||
},
|
||||
lastFailureAt: {
|
||||
type: 'date',
|
||||
},
|
||||
lastSuccessAt: {
|
||||
type: 'date',
|
||||
},
|
||||
lastFailureMessage: {
|
||||
type: 'text',
|
||||
},
|
||||
lastSuccessMessage: {
|
||||
type: 'text',
|
||||
},
|
||||
lastLookBackDate: {
|
||||
type: 'date',
|
||||
},
|
||||
gap: {
|
||||
type: 'text',
|
||||
},
|
||||
bulkCreateTimeDurations: {
|
||||
type: 'float',
|
||||
},
|
||||
searchAfterTimeDurations: {
|
||||
type: 'float',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const truncateMessageFields: SavedObjectMigrationFn<Record<string, unknown>> = (doc) => {
|
||||
const { lastFailureMessage, lastSuccessMessage, ...restAttributes } = doc.attributes;
|
||||
|
||||
return {
|
||||
...doc,
|
||||
attributes: {
|
||||
lastFailureMessage: truncateMessage(lastFailureMessage),
|
||||
lastSuccessMessage: truncateMessage(lastSuccessMessage),
|
||||
...restAttributes,
|
||||
},
|
||||
references: doc.references ?? [],
|
||||
};
|
||||
};
|
||||
|
||||
export const type: SavedObjectsType = {
|
||||
name: ruleStatusSavedObjectType,
|
||||
hidden: false,
|
||||
namespaceType: 'single',
|
||||
mappings: ruleStatusSavedObjectMappings,
|
||||
migrations: {
|
||||
'7.15.2': truncateMessageFields,
|
||||
},
|
||||
};
|
||||
|
||||
export const ruleAssetSavedObjectType = 'security-rule';
|
||||
|
||||
export const ruleAssetSavedObjectMappings: SavedObjectsType['mappings'] = {
|
||||
dynamic: false,
|
||||
properties: {
|
||||
name: {
|
||||
type: 'keyword',
|
||||
},
|
||||
rule_id: {
|
||||
type: 'keyword',
|
||||
},
|
||||
version: {
|
||||
type: 'long',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ruleAssetType: SavedObjectsType = {
|
||||
name: ruleAssetSavedObjectType,
|
||||
hidden: false,
|
||||
namespaceType: 'agnostic',
|
||||
mappings: ruleAssetSavedObjectMappings,
|
||||
};
|
|
@ -111,7 +111,6 @@ export type RuleAlertType = SanitizedAlert<RuleParams>;
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export interface IRuleStatusSOAttributes extends Record<string, any> {
|
||||
alertId: string; // created alert id.
|
||||
statusDate: StatusDate;
|
||||
lastFailureAt: LastFailureAt | null | undefined;
|
||||
lastFailureMessage: LastFailureMessage | null | undefined;
|
||||
|
@ -125,7 +124,6 @@ export interface IRuleStatusSOAttributes extends Record<string, any> {
|
|||
}
|
||||
|
||||
export interface IRuleStatusResponseAttributes {
|
||||
alert_id: string; // created alert id.
|
||||
status_date: StatusDate;
|
||||
last_failure_at: LastFailureAt | null | undefined;
|
||||
last_failure_message: LastFailureMessage | null | undefined;
|
||||
|
|
|
@ -18,7 +18,8 @@ import type {
|
|||
import { SavedObject } from '../../../../../../../../src/core/server';
|
||||
import { loggingSystemMock } from '../../../../../../../../src/core/server/mocks';
|
||||
import { IRuleStatusSOAttributes } from '../../rules/types';
|
||||
import { ruleStatusSavedObjectType } from '../../rules/saved_object_mappings';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyRuleStatusSavedObjectType } from '../../rules/legacy_rule_status/legacy_rule_status_saved_object_mappings';
|
||||
import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock';
|
||||
import { RulesSchema } from '../../../../../common/detection_engine/schemas/response';
|
||||
import { RuleParams } from '../../schemas/rule_schemas';
|
||||
|
@ -725,10 +726,9 @@ export const sampleRuleGuid = '04128c15-0d1b-4716-a4c5-46997ac7f3bd';
|
|||
export const sampleIdGuid = 'e1e08ddc-5e37-49ff-a258-5393aa44435a';
|
||||
|
||||
export const exampleRuleStatus: () => SavedObject<IRuleStatusSOAttributes> = () => ({
|
||||
type: ruleStatusSavedObjectType,
|
||||
type: legacyRuleStatusSavedObjectType,
|
||||
id: '042e6d90-7069-11ea-af8b-0f8ae4fa817e',
|
||||
attributes: {
|
||||
alertId: 'f4b8e31d-cf93-4bde-a265-298bde885cd7',
|
||||
statusDate: '2020-03-27T22:55:59.517Z',
|
||||
status: RuleExecutionStatus.succeeded,
|
||||
lastFailureAt: null,
|
||||
|
@ -740,7 +740,13 @@ export const exampleRuleStatus: () => SavedObject<IRuleStatusSOAttributes> = ()
|
|||
searchAfterTimeDurations: [],
|
||||
lastLookBackDate: null,
|
||||
},
|
||||
references: [],
|
||||
references: [
|
||||
{
|
||||
id: 'f4b8e31d-cf93-4bde-a265-298bde885cd7',
|
||||
type: 'alert',
|
||||
name: 'alert_0',
|
||||
},
|
||||
],
|
||||
updated_at: '2020-03-27T22:55:59.577Z',
|
||||
version: 'WzgyMiwxXQ==',
|
||||
});
|
||||
|
|
|
@ -8,10 +8,9 @@
|
|||
import { CoreSetup } from '../../../../src/core/server';
|
||||
|
||||
import { noteType, pinnedEventType, timelineType } from './lib/timeline/saved_object_mappings';
|
||||
import {
|
||||
type as ruleStatusType,
|
||||
ruleAssetType,
|
||||
} from './lib/detection_engine/rules/saved_object_mappings';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyRuleStatusType } from './lib/detection_engine/rules/legacy_rule_status/legacy_rule_status_saved_object_mappings';
|
||||
import { ruleAssetType } from './lib/detection_engine/rules/rule_asset/rule_asset_saved_object_mappings';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyType as legacyRuleActionsType } from './lib/detection_engine/rule_actions/legacy_saved_object_mappings';
|
||||
import { type as signalsMigrationType } from './lib/detection_engine/migrations/saved_objects';
|
||||
|
@ -24,7 +23,7 @@ const types = [
|
|||
noteType,
|
||||
pinnedEventType,
|
||||
legacyRuleActionsType,
|
||||
ruleStatusType,
|
||||
legacyRuleStatusType,
|
||||
ruleAssetType,
|
||||
timelineType,
|
||||
exceptionsArtifactType,
|
||||
|
|
|
@ -86,6 +86,33 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
'7d'
|
||||
);
|
||||
});
|
||||
|
||||
it('migrates legacy siem-detection-engine-rule-status to use saved object references', async () => {
|
||||
const response = await es.get<{
|
||||
'siem-detection-engine-rule-status': {
|
||||
alertId: string;
|
||||
};
|
||||
references: [{}];
|
||||
}>({
|
||||
index: '.kibana',
|
||||
id: 'siem-detection-engine-rule-status:d62d2980-27c4-11ec-92b0-f7b47106bb35',
|
||||
});
|
||||
expect(response.statusCode).to.eql(200);
|
||||
|
||||
// references exist and are expected values
|
||||
expect(response.body._source?.references).to.eql([
|
||||
{
|
||||
name: 'alert_0',
|
||||
id: 'fb1046a0-0452-11ec-9b15-d13d79d162f3',
|
||||
type: 'alert',
|
||||
},
|
||||
]);
|
||||
|
||||
// alertId no longer exist
|
||||
expect(response.body._source?.['siem-detection-engine-rule-status'].alertId).to.eql(
|
||||
undefined
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "siem-detection-engine-rule-actions:fce024a0-0452-11ec-9b15-d13d79d162f3",
|
||||
|
@ -29,3 +29,35 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "siem-detection-engine-rule-status:d62d2980-27c4-11ec-92b0-f7b47106bb35",
|
||||
"index": ".kibana_1",
|
||||
"source": {
|
||||
"siem-detection-engine-rule-status": {
|
||||
"alertId": "fb1046a0-0452-11ec-9b15-d13d79d162f3",
|
||||
"statusDate": "2021-10-11T20:51:26.622Z",
|
||||
"status": "succeeded",
|
||||
"lastFailureAt": "2021-10-11T18:10:08.982Z",
|
||||
"lastSuccessAt": "2021-10-11T20:51:26.622Z",
|
||||
"lastFailureMessage": "4 days (323690920ms) were not queried between this rule execution and the last execution, so signals may have been missed. Consider increasing your look behind time or adding more Kibana instances. name: \"Threshy\" id: \"fb1046a0-0452-11ec-9b15-d13d79d162f3\" rule id: \"b789c80f-f6d8-41f1-8b4f-b4a23342cde2\" signals index: \".siem-signals-spong-default\"",
|
||||
"lastSuccessMessage": "succeeded",
|
||||
"gap": "4 days",
|
||||
"bulkCreateTimeDurations": [
|
||||
"34.49"
|
||||
],
|
||||
"searchAfterTimeDurations": [
|
||||
"62.58"
|
||||
],
|
||||
"lastLookBackDate": null
|
||||
},
|
||||
"type": "siem-detection-engine-rule-status",
|
||||
"references": [],
|
||||
"coreMigrationVersion": "7.14.0",
|
||||
"updated_at": "2021-10-11T20:51:26.657Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue