Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] [Security Solutions] Adds back the legacy actions and notification system in a limited fashion (#112869) #113202

Merged
merged 1 commit into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,15 @@ module.exports = {
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-useless-constructor': 'error',
'@typescript-eslint/unified-signatures': 'error',
'no-restricted-imports': [
'error',
{
// prevents code from importing files that contain the name "legacy" within their name. This is a mechanism
// to help deprecation and prevent accidental re-use/continued use of code we plan on removing. If you are
// finding yourself turning this off a lot for "new code" consider renaming the file and functions if it is has valid uses.
patterns: ['*legacy*'],
},
],
},
},
{
Expand Down Expand Up @@ -1196,6 +1205,15 @@ module.exports = {
'no-template-curly-in-string': 'error',
'sort-keys': 'error',
'prefer-destructuring': 'error',
'no-restricted-imports': [
'error',
{
// prevents code from importing files that contain the name "legacy" within their name. This is a mechanism
// to help deprecation and prevent accidental re-use/continued use of code we plan on removing. If you are
// finding yourself turning this off a lot for "new code" consider renaming the file and functions if it has valid uses.
patterns: ['*legacy*'],
},
],
},
},
/**
Expand Down Expand Up @@ -1308,6 +1326,15 @@ module.exports = {
'no-template-curly-in-string': 'error',
'sort-keys': 'error',
'prefer-destructuring': 'error',
'no-restricted-imports': [
'error',
{
// prevents code from importing files that contain the name "legacy" within their name. This is a mechanism
// to help deprecation and prevent accidental re-use/continued use of code we plan on removing. If you are
// finding yourself turning this off a lot for "new code" consider renaming the file and functions if it has valid uses.
patterns: ['*legacy*'],
},
],
},
},
/**
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/security_solution/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,9 @@ export const THRESHOLD_RULE_TYPE_ID = `${RULE_TYPE_PREFIX}.thresholdRule` as con

/**
* Id for the notifications alerting type
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
*/
export const NOTIFICATIONS_ID = `siem.notifications`;
export const LEGACY_NOTIFICATIONS_ID = `siem.notifications`;

/**
* Special internal structure for tags for signals. This is used
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.
*/

// eslint-disable-next-line no-restricted-imports
import { legacyAddTags } from './legacy_add_tags';
import { INTERNAL_RULE_ALERT_ID_KEY } from '../../../../common/constants';

describe('legacyAdd_tags', () => {
test('it should add a rule id as an internal structure', () => {
const tags = legacyAddTags([], 'rule-1');
expect(tags).toEqual([`${INTERNAL_RULE_ALERT_ID_KEY}:rule-1`]);
});

test('it should not allow duplicate tags to be created', () => {
const tags = legacyAddTags(['tag-1', 'tag-1'], 'rule-1');
expect(tags).toEqual(['tag-1', `${INTERNAL_RULE_ALERT_ID_KEY}:rule-1`]);
});

test('it should not allow duplicate internal tags to be created when called two times in a row', () => {
const tags1 = legacyAddTags(['tag-1'], 'rule-1');
const tags2 = legacyAddTags(tags1, 'rule-1');
expect(tags2).toEqual(['tag-1', `${INTERNAL_RULE_ALERT_ID_KEY}:rule-1`]);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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 { INTERNAL_RULE_ALERT_ID_KEY } from '../../../../common/constants';

/**
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
*/
export const legacyAddTags = (tags: string[], ruleAlertId: string): string[] =>
Array.from(new Set([...tags, `${INTERNAL_RULE_ALERT_ID_KEY}:${ruleAlertId}`]));
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 { rulesClientMock } from '../../../../../alerting/server/mocks';
// eslint-disable-next-line no-restricted-imports
import { legacyCreateNotifications } from './legacy_create_notifications';

/**
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
*/
describe('legacyCreateNotifications', () => {
let rulesClient: ReturnType<typeof rulesClientMock.create>;

beforeEach(() => {
rulesClient = rulesClientMock.create();
});

it('calls the rulesClient with proper params', async () => {
const ruleAlertId = 'rule-04128c15-0d1b-4716-a4c5-46997ac7f3bd';

await legacyCreateNotifications({
rulesClient,
actions: [],
ruleAlertId,
enabled: true,
interval: '',
name: '',
});

expect(rulesClient.create).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
params: expect.objectContaining({
ruleAlertId,
}),
}),
})
);
});

it('calls the rulesClient with transformed actions', async () => {
const action = {
group: 'default',
id: '99403909-ca9b-49ba-9d7a-7e5320e68d05',
params: { message: 'Rule generated {{state.signals_count}} signals' },
actionTypeId: '.slack',
};
await legacyCreateNotifications({
rulesClient,
actions: [action],
ruleAlertId: 'new-rule-id',
enabled: true,
interval: '',
name: '',
});

expect(rulesClient.create).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
actions: expect.arrayContaining([
{
group: action.group,
id: action.id,
params: action.params,
actionTypeId: '.slack',
},
]),
}),
})
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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 { SanitizedAlert } from '../../../../../alerting/common';
import { SERVER_APP_ID, LEGACY_NOTIFICATIONS_ID } from '../../../../common/constants';
// eslint-disable-next-line no-restricted-imports
import { CreateNotificationParams, LegacyRuleNotificationAlertTypeParams } from './legacy_types';
// eslint-disable-next-line no-restricted-imports
import { legacyAddTags } from './legacy_add_tags';

/**
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
*/
export const legacyCreateNotifications = async ({
rulesClient,
actions,
enabled,
ruleAlertId,
interval,
name,
}: CreateNotificationParams): Promise<SanitizedAlert<LegacyRuleNotificationAlertTypeParams>> =>
rulesClient.create<LegacyRuleNotificationAlertTypeParams>({
data: {
name,
tags: legacyAddTags([], ruleAlertId),
alertTypeId: LEGACY_NOTIFICATIONS_ID,
consumer: SERVER_APP_ID,
params: {
ruleAlertId,
},
schedule: { interval },
enabled,
actions,
throttle: null,
notifyWhen: null,
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.
*/

// eslint-disable-next-line no-restricted-imports
import { legacyGetFilter } from './legacy_find_notifications';
import { LEGACY_NOTIFICATIONS_ID } from '../../../../common/constants';

describe('legacyFind_notifications', () => {
test('it returns a full filter with an AND if sent down', () => {
expect(legacyGetFilter('alert.attributes.enabled: true')).toEqual(
`alert.attributes.alertTypeId: ${LEGACY_NOTIFICATIONS_ID} AND alert.attributes.enabled: true`
);
});

test('it returns existing filter with no AND when not set', () => {
expect(legacyGetFilter(null)).toEqual(
`alert.attributes.alertTypeId: ${LEGACY_NOTIFICATIONS_ID}`
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* 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 { AlertTypeParams, FindResult } from '../../../../../alerting/server';
import { LEGACY_NOTIFICATIONS_ID } from '../../../../common/constants';
// eslint-disable-next-line no-restricted-imports
import { LegacyFindNotificationParams } from './legacy_types';

/**
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
*/
export const legacyGetFilter = (filter: string | null | undefined) => {
if (filter == null) {
return `alert.attributes.alertTypeId: ${LEGACY_NOTIFICATIONS_ID}`;
} else {
return `alert.attributes.alertTypeId: ${LEGACY_NOTIFICATIONS_ID} AND ${filter}`;
}
};

/**
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
*/
export const legacyFindNotifications = async ({
rulesClient,
perPage,
page,
fields,
filter,
sortField,
sortOrder,
}: LegacyFindNotificationParams): Promise<FindResult<AlertTypeParams>> =>
rulesClient.find({
options: {
fields,
page,
perPage,
filter: legacyGetFilter(filter),
sortOrder,
sortField,
},
});
Loading