[Security Solutions] Adds security detection rule actions as importable and exportable (#115243)
## Summary Adds the security detection rule actions as being exportable and importable. * Adds exportable actions for legacy notification system * Adds exportable actions for the new throttle notification system * Adds importable but only imports into the new throttle notification system. * Updates unit tests In your `ndjson` file when you have actions exported you will see them like so: ```json "actions": [ { "group": "default", "id": "b55117e0-2df9-11ec-b789-7f03e3cdd668", "params": { "message": "Rule {{context.rule.name}} generated {{state.signals_count}} alerts" }, "action_type_id": ".slack" } ] ``` where before it was `actions: []` and was not provided. **Caveats** If you delete your connector and have an invalid connector then the rule(s) that were referring to that invalid connector will not import and you will get an error like this: <img width="802" alt="Screen Shot 2021-10-15 at 2 47 10 PM" src="https://user-images.githubusercontent.com/1151048/137554991-b3984be9-d2ad-488e-a309-29da656ca4ea.png"> This does _not_ export your connectors at this point in time. You have to export your connector through the Saved Object Management separate like so: <img width="1545" alt="Screen Shot 2021-10-15 at 2 58 03 PM" src="https://user-images.githubusercontent.com/1151048/137555135-3f0bfd63-5d67-496b-8d5b-bdef01d6122f.png"> However, if remove everything and import your connector without changing its saved object ID and then go to import the rules everything should import ok and you will get your actions working. **Manual Testing**: * You can create normal actions on an alert and then do exports and you should see the actions in your ndjson file * You can create legacy notifications from 7.14.0 and then upgrade and export and you should see the actions in your ndjson file * You can manually create legacy notifications by: By getting an alert id first and ensuring that your `legacy_notifications/one_action.json` contains a valid action then running this command: ```ts ./post_legacy_notification.sh 3403c0d0-2d44-11ec-b147-3b0c6d563a60 ``` * You can export your connector and remove everything and then do an import and you will have everything imported and working with your actions and connector wired up correctly. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added
This commit is contained in:
parent
1a917674a4
commit
c2c08be709
11 changed files with 145 additions and 28 deletions
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import { transformError } from '@kbn/securitysolution-es-utils';
|
||||
import { Logger } from 'src/core/server';
|
||||
import {
|
||||
exportRulesQuerySchema,
|
||||
ExportRulesQuerySchemaDecoded,
|
||||
|
@ -24,6 +25,7 @@ import { buildSiemResponse } from '../utils';
|
|||
export const exportRulesRoute = (
|
||||
router: SecuritySolutionPluginRouter,
|
||||
config: ConfigType,
|
||||
logger: Logger,
|
||||
isRuleRegistryEnabled: boolean
|
||||
) => {
|
||||
router.post(
|
||||
|
@ -44,6 +46,7 @@ export const exportRulesRoute = (
|
|||
async (context, request, response) => {
|
||||
const siemResponse = buildSiemResponse(response);
|
||||
const rulesClient = context.alerting?.getRulesClient();
|
||||
const savedObjectsClient = context.core.savedObjects.client;
|
||||
|
||||
if (!rulesClient) {
|
||||
return siemResponse.error({ statusCode: 404 });
|
||||
|
@ -71,8 +74,14 @@ export const exportRulesRoute = (
|
|||
|
||||
const exported =
|
||||
request.body?.objects != null
|
||||
? await getExportByObjectIds(rulesClient, request.body.objects, isRuleRegistryEnabled)
|
||||
: await getExportAll(rulesClient, isRuleRegistryEnabled);
|
||||
? await getExportByObjectIds(
|
||||
rulesClient,
|
||||
savedObjectsClient,
|
||||
request.body.objects,
|
||||
logger,
|
||||
isRuleRegistryEnabled
|
||||
)
|
||||
: await getExportAll(rulesClient, savedObjectsClient, logger, isRuleRegistryEnabled);
|
||||
|
||||
const responseBody = request.query.exclude_export_details
|
||||
? exported.rulesNdjson
|
||||
|
|
|
@ -194,6 +194,7 @@ export const importRulesRoute = (
|
|||
throttle,
|
||||
version,
|
||||
exceptions_list: exceptionsList,
|
||||
actions,
|
||||
} = parsedRule;
|
||||
|
||||
try {
|
||||
|
@ -265,7 +266,7 @@ export const importRulesRoute = (
|
|||
note,
|
||||
version,
|
||||
exceptionsList,
|
||||
actions: [], // Actions are not imported nor exported at this time
|
||||
actions,
|
||||
});
|
||||
resolve({
|
||||
rule_id: ruleId,
|
||||
|
@ -328,7 +329,7 @@ export const importRulesRoute = (
|
|||
exceptionsList,
|
||||
anomalyThreshold,
|
||||
machineLearningJobId,
|
||||
actions: undefined,
|
||||
actions,
|
||||
});
|
||||
resolve({
|
||||
rule_id: ruleId,
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
import { requestContextMock, serverMock, requestMock } from '../__mocks__';
|
||||
import { performBulkActionRoute } from './perform_bulk_action_route';
|
||||
import { getPerformBulkActionSchemaMock } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema.mock';
|
||||
import { loggingSystemMock } from 'src/core/server/mocks';
|
||||
|
||||
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
|
||||
|
||||
|
@ -27,15 +28,17 @@ describe.each([
|
|||
let server: ReturnType<typeof serverMock.create>;
|
||||
let { clients, context } = requestContextMock.createTools();
|
||||
let ml: ReturnType<typeof mlServicesMock.createSetupContract>;
|
||||
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
|
||||
|
||||
beforeEach(() => {
|
||||
server = serverMock.create();
|
||||
logger = loggingSystemMock.createLogger();
|
||||
({ clients, context } = requestContextMock.createTools());
|
||||
ml = mlServicesMock.createSetupContract();
|
||||
|
||||
clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
|
||||
|
||||
performBulkActionRoute(server.router, ml, isRuleRegistryEnabled);
|
||||
performBulkActionRoute(server.router, ml, logger, isRuleRegistryEnabled);
|
||||
});
|
||||
|
||||
describe('status codes', () => {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
|
||||
import { transformError } from '@kbn/securitysolution-es-utils';
|
||||
import { Logger } from 'src/core/server';
|
||||
|
||||
import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../common/constants';
|
||||
import { BulkAction } from '../../../../../common/detection_engine/schemas/common/schemas';
|
||||
import { performBulkActionSchema } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema';
|
||||
|
@ -26,6 +28,7 @@ const BULK_ACTION_RULES_LIMIT = 10000;
|
|||
export const performBulkActionRoute = (
|
||||
router: SecuritySolutionPluginRouter,
|
||||
ml: SetupPlugins['ml'],
|
||||
logger: Logger,
|
||||
isRuleRegistryEnabled: boolean
|
||||
) => {
|
||||
router.post(
|
||||
|
@ -133,7 +136,9 @@ export const performBulkActionRoute = (
|
|||
case BulkAction.export:
|
||||
const exported = await getExportByObjectIds(
|
||||
rulesClient,
|
||||
savedObjectsClient,
|
||||
rules.data.map(({ params }) => ({ rule_id: params.ruleId })),
|
||||
logger,
|
||||
isRuleRegistryEnabled
|
||||
);
|
||||
|
||||
|
|
|
@ -469,12 +469,12 @@ describe.each([
|
|||
|
||||
describe('transformAlertsToRules', () => {
|
||||
test('given an empty array returns an empty array', () => {
|
||||
expect(transformAlertsToRules([])).toEqual([]);
|
||||
expect(transformAlertsToRules([], {})).toEqual([]);
|
||||
});
|
||||
|
||||
test('given single alert will return the alert transformed', () => {
|
||||
const result1 = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
|
||||
const transformed = transformAlertsToRules([result1]);
|
||||
const transformed = transformAlertsToRules([result1], {});
|
||||
const expected = getOutputRuleAlertForRest();
|
||||
expect(transformed).toEqual([expected]);
|
||||
});
|
||||
|
@ -485,7 +485,7 @@ describe.each([
|
|||
result2.id = 'some other id';
|
||||
result2.params.ruleId = 'some other id';
|
||||
|
||||
const transformed = transformAlertsToRules([result1, result2]);
|
||||
const transformed = transformAlertsToRules([result1, result2], {});
|
||||
const expected1 = getOutputRuleAlertForRest();
|
||||
const expected2 = getOutputRuleAlertForRest();
|
||||
expected2.id = 'some other id';
|
||||
|
|
|
@ -103,8 +103,11 @@ export const transformAlertToRule = (
|
|||
return internalRuleToAPIResponse(alert, ruleStatus?.attributes, legacyRuleActions);
|
||||
};
|
||||
|
||||
export const transformAlertsToRules = (alerts: RuleAlertType[]): Array<Partial<RulesSchema>> => {
|
||||
return alerts.map((alert) => transformAlertToRule(alert));
|
||||
export const transformAlertsToRules = (
|
||||
alerts: RuleAlertType[],
|
||||
legacyRuleActions: Record<string, LegacyRulesActionsSavedObject>
|
||||
): Array<Partial<RulesSchema>> => {
|
||||
return alerts.map((alert) => transformAlertToRule(alert, undefined, legacyRuleActions[alert.id]));
|
||||
};
|
||||
|
||||
export const transformFindAlerts = (
|
||||
|
|
|
@ -9,21 +9,33 @@ import {
|
|||
getAlertMock,
|
||||
getFindResultWithSingleHit,
|
||||
FindHit,
|
||||
getEmptySavedObjectsResponse,
|
||||
} from '../routes/__mocks__/request_responses';
|
||||
import { rulesClientMock } from '../../../../../alerting/server/mocks';
|
||||
import { getExportAll } from './get_export_all';
|
||||
import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock';
|
||||
import { getThreatMock } from '../../../../common/detection_engine/schemas/types/threat.mock';
|
||||
|
||||
import { getQueryRuleParams } from '../schemas/rule_schemas.mock';
|
||||
import { loggingSystemMock } from 'src/core/server/mocks';
|
||||
import { requestContextMock } from '../routes/__mocks__/request_context';
|
||||
|
||||
describe.each([
|
||||
['Legacy', false],
|
||||
['RAC', true],
|
||||
])('getExportAll - %s', (_, isRuleRegistryEnabled) => {
|
||||
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
|
||||
const { clients } = requestContextMock.createTools();
|
||||
|
||||
beforeEach(async () => {
|
||||
clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse());
|
||||
});
|
||||
|
||||
test('it exports everything from the alerts client', async () => {
|
||||
const rulesClient = rulesClientMock.create();
|
||||
const result = getFindResultWithSingleHit(isRuleRegistryEnabled);
|
||||
const alert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
|
||||
|
||||
alert.params = {
|
||||
...alert.params,
|
||||
filters: [{ query: { match_phrase: { 'host.name': 'some-host' } } }],
|
||||
|
@ -35,7 +47,12 @@ describe.each([
|
|||
result.data = [alert];
|
||||
rulesClient.find.mockResolvedValue(result);
|
||||
|
||||
const exports = await getExportAll(rulesClient, isRuleRegistryEnabled);
|
||||
const exports = await getExportAll(
|
||||
rulesClient,
|
||||
clients.savedObjectsClient,
|
||||
logger,
|
||||
isRuleRegistryEnabled
|
||||
);
|
||||
const rulesJson = JSON.parse(exports.rulesNdjson);
|
||||
const detailsJson = JSON.parse(exports.exportDetails);
|
||||
expect(rulesJson).toEqual({
|
||||
|
@ -97,7 +114,12 @@ describe.each([
|
|||
|
||||
rulesClient.find.mockResolvedValue(findResult);
|
||||
|
||||
const exports = await getExportAll(rulesClient, isRuleRegistryEnabled);
|
||||
const exports = await getExportAll(
|
||||
rulesClient,
|
||||
clients.savedObjectsClient,
|
||||
logger,
|
||||
isRuleRegistryEnabled
|
||||
);
|
||||
expect(exports).toEqual({
|
||||
rulesNdjson: '',
|
||||
exportDetails: '{"exported_count":0,"missing_rules":[],"missing_rules_count":0}\n',
|
||||
|
|
|
@ -7,20 +7,33 @@
|
|||
|
||||
import { transformDataToNdjson } from '@kbn/securitysolution-utils';
|
||||
|
||||
import { RulesClient } from '../../../../../alerting/server';
|
||||
import { Logger } from 'src/core/server';
|
||||
import { RulesClient, AlertServices } from '../../../../../alerting/server';
|
||||
import { getNonPackagedRules } from './get_existing_prepackaged_rules';
|
||||
import { getExportDetailsNdjson } from './get_export_details_ndjson';
|
||||
import { transformAlertsToRules } from '../routes/rules/utils';
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyGetBulkRuleActionsSavedObject } from '../rule_actions/legacy_get_bulk_rule_actions_saved_object';
|
||||
|
||||
export const getExportAll = async (
|
||||
rulesClient: RulesClient,
|
||||
savedObjectsClient: AlertServices['savedObjectsClient'],
|
||||
logger: Logger,
|
||||
isRuleRegistryEnabled: boolean
|
||||
): Promise<{
|
||||
rulesNdjson: string;
|
||||
exportDetails: string;
|
||||
}> => {
|
||||
const ruleAlertTypes = await getNonPackagedRules({ rulesClient, isRuleRegistryEnabled });
|
||||
const rules = transformAlertsToRules(ruleAlertTypes);
|
||||
const alertIds = ruleAlertTypes.map((rule) => rule.id);
|
||||
const legacyActions = await legacyGetBulkRuleActionsSavedObject({
|
||||
alertIds,
|
||||
savedObjectsClient,
|
||||
logger,
|
||||
});
|
||||
|
||||
const rules = transformAlertsToRules(ruleAlertTypes, legacyActions);
|
||||
// We do not support importing/exporting actions. When we do, delete this line of code
|
||||
const rulesWithoutActions = rules.map((rule) => ({ ...rule, actions: [] }));
|
||||
const rulesNdjson = transformDataToNdjson(rulesWithoutActions);
|
||||
|
|
|
@ -10,28 +10,43 @@ import {
|
|||
getAlertMock,
|
||||
getFindResultWithSingleHit,
|
||||
FindHit,
|
||||
getEmptySavedObjectsResponse,
|
||||
} from '../routes/__mocks__/request_responses';
|
||||
import { rulesClientMock } from '../../../../../alerting/server/mocks';
|
||||
import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock';
|
||||
import { getThreatMock } from '../../../../common/detection_engine/schemas/types/threat.mock';
|
||||
import { getQueryRuleParams } from '../schemas/rule_schemas.mock';
|
||||
import { loggingSystemMock } from 'src/core/server/mocks';
|
||||
import { requestContextMock } from '../routes/__mocks__/request_context';
|
||||
|
||||
describe.each([
|
||||
['Legacy', false],
|
||||
['RAC', true],
|
||||
])('get_export_by_object_ids - %s', (_, isRuleRegistryEnabled) => {
|
||||
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
|
||||
const { clients } = requestContextMock.createTools();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
jest.clearAllMocks();
|
||||
|
||||
clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse());
|
||||
});
|
||||
|
||||
describe('getExportByObjectIds', () => {
|
||||
test('it exports object ids into an expected string with new line characters', async () => {
|
||||
const rulesClient = rulesClientMock.create();
|
||||
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
|
||||
|
||||
const objects = [{ rule_id: 'rule-1' }];
|
||||
const exports = await getExportByObjectIds(rulesClient, objects, isRuleRegistryEnabled);
|
||||
const exports = await getExportByObjectIds(
|
||||
rulesClient,
|
||||
clients.savedObjectsClient,
|
||||
objects,
|
||||
logger,
|
||||
isRuleRegistryEnabled
|
||||
);
|
||||
const exportsObj = {
|
||||
rulesNdjson: JSON.parse(exports.rulesNdjson),
|
||||
exportDetails: JSON.parse(exports.exportDetails),
|
||||
|
@ -102,7 +117,13 @@ describe.each([
|
|||
rulesClient.find.mockResolvedValue(findResult);
|
||||
|
||||
const objects = [{ rule_id: 'rule-1' }];
|
||||
const exports = await getExportByObjectIds(rulesClient, objects, isRuleRegistryEnabled);
|
||||
const exports = await getExportByObjectIds(
|
||||
rulesClient,
|
||||
clients.savedObjectsClient,
|
||||
objects,
|
||||
logger,
|
||||
isRuleRegistryEnabled
|
||||
);
|
||||
expect(exports).toEqual({
|
||||
rulesNdjson: '',
|
||||
exportDetails:
|
||||
|
@ -117,7 +138,13 @@ describe.each([
|
|||
rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled));
|
||||
|
||||
const objects = [{ rule_id: 'rule-1' }];
|
||||
const exports = await getRulesFromObjects(rulesClient, objects, isRuleRegistryEnabled);
|
||||
const exports = await getRulesFromObjects(
|
||||
rulesClient,
|
||||
clients.savedObjectsClient,
|
||||
objects,
|
||||
logger,
|
||||
isRuleRegistryEnabled
|
||||
);
|
||||
const expected: RulesErrors = {
|
||||
exportedCount: 1,
|
||||
missingRules: [],
|
||||
|
@ -192,7 +219,13 @@ describe.each([
|
|||
rulesClient.find.mockResolvedValue(findResult);
|
||||
|
||||
const objects = [{ rule_id: 'rule-1' }];
|
||||
const exports = await getRulesFromObjects(rulesClient, objects, isRuleRegistryEnabled);
|
||||
const exports = await getRulesFromObjects(
|
||||
rulesClient,
|
||||
clients.savedObjectsClient,
|
||||
objects,
|
||||
logger,
|
||||
isRuleRegistryEnabled
|
||||
);
|
||||
const expected: RulesErrors = {
|
||||
exportedCount: 0,
|
||||
missingRules: [{ rule_id: 'rule-1' }],
|
||||
|
@ -215,7 +248,13 @@ describe.each([
|
|||
rulesClient.find.mockResolvedValue(findResult);
|
||||
|
||||
const objects = [{ rule_id: 'rule-1' }];
|
||||
const exports = await getRulesFromObjects(rulesClient, objects, isRuleRegistryEnabled);
|
||||
const exports = await getRulesFromObjects(
|
||||
rulesClient,
|
||||
clients.savedObjectsClient,
|
||||
objects,
|
||||
logger,
|
||||
isRuleRegistryEnabled
|
||||
);
|
||||
const expected: RulesErrors = {
|
||||
exportedCount: 0,
|
||||
missingRules: [{ rule_id: 'rule-1' }],
|
||||
|
|
|
@ -8,14 +8,20 @@
|
|||
import { chunk } from 'lodash';
|
||||
import { transformDataToNdjson } from '@kbn/securitysolution-utils';
|
||||
|
||||
import { Logger } from 'src/core/server';
|
||||
import { RulesSchema } from '../../../../common/detection_engine/schemas/response/rules_schema';
|
||||
import { RulesClient } from '../../../../../alerting/server';
|
||||
import { RulesClient, AlertServices } from '../../../../../alerting/server';
|
||||
|
||||
import { getExportDetailsNdjson } from './get_export_details_ndjson';
|
||||
|
||||
import { isAlertType } from '../rules/types';
|
||||
import { transformAlertToRule } from '../routes/rules/utils';
|
||||
import { INTERNAL_RULE_ID_KEY } from '../../../../common/constants';
|
||||
import { findRules } from './find_rules';
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyGetBulkRuleActionsSavedObject } from '../rule_actions/legacy_get_bulk_rule_actions_saved_object';
|
||||
|
||||
interface ExportSuccessRule {
|
||||
statusCode: 200;
|
||||
rule: Partial<RulesSchema>;
|
||||
|
@ -34,23 +40,32 @@ export interface RulesErrors {
|
|||
|
||||
export const getExportByObjectIds = async (
|
||||
rulesClient: RulesClient,
|
||||
savedObjectsClient: AlertServices['savedObjectsClient'],
|
||||
objects: Array<{ rule_id: string }>,
|
||||
logger: Logger,
|
||||
isRuleRegistryEnabled: boolean
|
||||
): Promise<{
|
||||
rulesNdjson: string;
|
||||
exportDetails: string;
|
||||
}> => {
|
||||
const rulesAndErrors = await getRulesFromObjects(rulesClient, objects, isRuleRegistryEnabled);
|
||||
// We do not support importing/exporting actions. When we do, delete this line of code
|
||||
const rulesWithoutActions = rulesAndErrors.rules.map((rule) => ({ ...rule, actions: [] }));
|
||||
const rulesNdjson = transformDataToNdjson(rulesWithoutActions);
|
||||
const exportDetails = getExportDetailsNdjson(rulesWithoutActions, rulesAndErrors.missingRules);
|
||||
const rulesAndErrors = await getRulesFromObjects(
|
||||
rulesClient,
|
||||
savedObjectsClient,
|
||||
objects,
|
||||
logger,
|
||||
isRuleRegistryEnabled
|
||||
);
|
||||
|
||||
const rulesNdjson = transformDataToNdjson(rulesAndErrors.rules);
|
||||
const exportDetails = getExportDetailsNdjson(rulesAndErrors.rules, rulesAndErrors.missingRules);
|
||||
return { rulesNdjson, exportDetails };
|
||||
};
|
||||
|
||||
export const getRulesFromObjects = async (
|
||||
rulesClient: RulesClient,
|
||||
savedObjectsClient: AlertServices['savedObjectsClient'],
|
||||
objects: Array<{ rule_id: string }>,
|
||||
logger: Logger,
|
||||
isRuleRegistryEnabled: boolean
|
||||
): Promise<RulesErrors> => {
|
||||
// If we put more than 1024 ids in one block like "alert.attributes.tags: (id1 OR id2 OR ... OR id1100)"
|
||||
|
@ -78,6 +93,13 @@ export const getRulesFromObjects = async (
|
|||
sortField: undefined,
|
||||
sortOrder: undefined,
|
||||
});
|
||||
const alertIds = rules.data.map((rule) => rule.id);
|
||||
const legacyActions = await legacyGetBulkRuleActionsSavedObject({
|
||||
alertIds,
|
||||
savedObjectsClient,
|
||||
logger,
|
||||
});
|
||||
|
||||
const alertsAndErrors = objects.map(({ rule_id: ruleId }) => {
|
||||
const matchingRule = rules.data.find((rule) => rule.params.ruleId === ruleId);
|
||||
if (
|
||||
|
@ -87,7 +109,7 @@ export const getRulesFromObjects = async (
|
|||
) {
|
||||
return {
|
||||
statusCode: 200,
|
||||
rule: transformAlertToRule(matchingRule),
|
||||
rule: transformAlertToRule(matchingRule, undefined, legacyActions[matchingRule.id]),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
|
|
|
@ -91,12 +91,12 @@ export const initRoutes = (
|
|||
updateRulesBulkRoute(router, ml, isRuleRegistryEnabled);
|
||||
patchRulesBulkRoute(router, ml, isRuleRegistryEnabled);
|
||||
deleteRulesBulkRoute(router, isRuleRegistryEnabled);
|
||||
performBulkActionRoute(router, ml, isRuleRegistryEnabled);
|
||||
performBulkActionRoute(router, ml, logger, isRuleRegistryEnabled);
|
||||
|
||||
createTimelinesRoute(router, config, security);
|
||||
patchTimelinesRoute(router, config, security);
|
||||
importRulesRoute(router, config, ml, isRuleRegistryEnabled);
|
||||
exportRulesRoute(router, config, isRuleRegistryEnabled);
|
||||
exportRulesRoute(router, config, logger, isRuleRegistryEnabled);
|
||||
|
||||
importTimelinesRoute(router, config, security);
|
||||
exportTimelinesRoute(router, config, security);
|
||||
|
|
Loading…
Reference in a new issue