From ea2319e4e4fed9813ce2c1cdb0be78f2775ffc36 Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Tue, 10 Jan 2023 21:18:31 +0200
Subject: [PATCH 01/40] use getImporter and getExporter from Saved Object
---
.../api/rules/import_rules/response_schema.ts | 4 +
.../api/rules/bulk_actions/route.ts | 12 ++-
.../api/rules/export_rules/route.ts | 27 +++++--
.../api/rules/import_rules/route.ts | 21 ++++-
.../logic/export/get_export_all.ts | 20 ++++-
.../logic/export/get_export_by_object_ids.ts | 25 ++++--
.../logic/export/get_export_details_ndjson.ts | 22 +++--
.../get_export_rule_action_connectors.ts | 81 +++++++++++++++++++
.../import/create_rules_stream_from_ndjson.ts | 9 +++
.../import/import_rule_action_connectors.ts | 62 ++++++++++++++
.../logic/import/import_rules_utils.ts | 3 +-
11 files changed, 258 insertions(+), 28 deletions(-)
create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_rule_action_connectors.ts
create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_action_connectors.ts
diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts
index 77ccd0812c2c9..ac43f394734e9 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts
@@ -19,5 +19,9 @@ export const ImportRulesResponse = t.exact(
success: t.boolean,
success_count: PositiveInteger,
errors: t.array(errorSchema),
+ // action_connectors_errors: t.array(errorSchema),
+ // action_connectors_warnings: t.array(),
+ action_connectors_success: t.boolean,
+ action_connectors_success_count: PositiveInteger,
})
);
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts
index 82660cba2a870..d00a09d4f7c92 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts
@@ -326,6 +326,7 @@ export const performBulkActionRoute = (
'alerting',
'licensing',
'lists',
+ 'actions',
]);
const rulesClient = ctx.alerting.getRulesClient();
@@ -333,6 +334,11 @@ export const performBulkActionRoute = (
const exceptionsClient = ctx.lists?.getExceptionListClient();
const savedObjectsClient = ctx.core.savedObjects.client;
+ const { getExporter, getClient } = (await ctx.core).savedObjects;
+ const client = getClient({ includedHiddenTypes: ['action'] });
+
+ const exporter = getExporter(client);
+
const mlAuthz = buildMlAuthz({
license: ctx.licensing.license,
ml,
@@ -558,10 +564,12 @@ export const performBulkActionRoute = (
exceptionsClient,
savedObjectsClient,
rules.map(({ params }) => ({ rule_id: params.ruleId })),
- logger
+ logger,
+ exporter,
+ request
);
- const responseBody = `${exported.rulesNdjson}${exported.exceptionLists}${exported.exportDetails}`;
+ const responseBody = `${exported.rulesNdjson}${exported.exceptionLists}${exported.actionConnectors}${exported.exportDetails}`;
return response.ok({
headers: {
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts
index ec96f38f5f86e..a1a5f798fc002 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts
@@ -45,8 +45,14 @@ export const exportRulesRoute = (
const siemResponse = buildSiemResponse(response);
const rulesClient = (await context.alerting).getRulesClient();
const exceptionsClient = (await context.lists)?.getExceptionListClient();
- const savedObjectsClient = (await context.core).savedObjects.client;
+ const {
+ getExporter,
+ getClient,
+ client: savedObjectsClient,
+ } = (await context.core).savedObjects;
+ const client = getClient({ includedHiddenTypes: ['action'] });
+ const actionsExporter = getExporter(client);
try {
const exportSizeLimit = config.maxRuleImportExportSize;
if (request.body?.objects != null && request.body.objects.length > exportSizeLimit) {
@@ -66,20 +72,29 @@ export const exportRulesRoute = (
}
}
- const exportedRulesAndExceptions =
+ const exportedRulesAndReferences =
request.body?.objects != null
? await getExportByObjectIds(
rulesClient,
exceptionsClient,
savedObjectsClient,
request.body.objects,
- logger
+ logger,
+ actionsExporter,
+ request
)
- : await getExportAll(rulesClient, exceptionsClient, savedObjectsClient, logger);
+ : await getExportAll(
+ rulesClient,
+ exceptionsClient,
+ savedObjectsClient,
+ logger,
+ actionsExporter,
+ request
+ );
const responseBody = request.query.exclude_export_details
- ? exportedRulesAndExceptions.rulesNdjson
- : `${exportedRulesAndExceptions.rulesNdjson}${exportedRulesAndExceptions.exceptionLists}${exportedRulesAndExceptions.exportDetails}`;
+ ? exportedRulesAndReferences.rulesNdjson
+ : `${exportedRulesAndReferences.rulesNdjson}${exportedRulesAndReferences.exceptionLists}${exportedRulesAndReferences.actionConnectors}${exportedRulesAndReferences.exportDetails}`;
return response.ok({
headers: {
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
index e306caac12194..6bb12762d4492 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
@@ -38,6 +38,7 @@ import { importRules as importRulesHelper } from '../../../logic/import/import_r
import { getReferencedExceptionLists } from '../../../logic/import/gather_referenced_exceptions';
import { importRuleExceptions } from '../../../logic/import/import_rule_exceptions';
import type { HapiReadableStream } from '../../../logic/import/hapi_readable_stream';
+import { importRuleActionConnectors } from '../../../logic/import/import_rule_action_connectors';
const CHUNK_PARSED_OBJECT_SIZE = 50;
@@ -81,6 +82,8 @@ export const importRulesRoute = (
const actionSOClient = ctx.core.savedObjects.getClient({
includedHiddenTypes: ['action'],
});
+ const actionsImporter = ctx.core.savedObjects.getImporter(actionSOClient);
+
const savedObjectsClient = ctx.core.savedObjects.client;
const exceptionsClient = ctx.lists?.getExceptionListClient();
@@ -104,7 +107,7 @@ export const importRulesRoute = (
// parse file to separate out exceptions from rules
const readAllStream = createRulesAndExceptionsStreamFromNdJson(objectLimit);
- const [{ exceptions, rules }] = await createPromiseFromStreams<
+ const [{ exceptions, rules, actionConnectors }] = await createPromiseFromStreams<
RuleExceptionsPromiseFromStreams[]
>([request.body.file as HapiReadableStream, ...readAllStream]);
@@ -120,6 +123,18 @@ export const importRulesRoute = (
maxExceptionsImportSize: objectLimit,
});
+ // import actions-connectors
+ const {
+ successCount: actionConnectorSuccessCount,
+ success: actionConnectorSuccess,
+ warnings: actionConnectorWarnings,
+ errors: actionConnectorErrors,
+ } = await importRuleActionConnectors({
+ actionConnectors,
+ actionsClient,
+ actionsImporter,
+ });
+
// report on duplicate rules
const [duplicateIdErrors, parsedObjectsWithoutDuplicateErrors] =
getTupleDuplicateErrorsAndUniqueRules(rules, request.query.overwrite);
@@ -179,6 +194,10 @@ export const importRulesRoute = (
exceptions_errors: exceptionsErrors,
exceptions_success: exceptionsSuccess,
exceptions_success_count: exceptionsSuccessCount,
+ // action_connectors_errors: actionConnectorErrors,
+ // action_connectors_warnings: actionConnectorWarnings,
+ action_connectors_success: actionConnectorSuccess,
+ action_connectors_success_count: actionConnectorSuccessCount,
};
const [validated, errors] = validate(importRules, ImportRulesResponse);
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts
index 058559de7db59..88f3e9019d493 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.ts
@@ -7,13 +7,14 @@
import { transformDataToNdjson } from '@kbn/securitysolution-utils';
-import type { Logger } from '@kbn/core/server';
+import type { ISavedObjectsExporter, KibanaRequest, Logger } from '@kbn/core/server';
import type { ExceptionListClient } from '@kbn/lists-plugin/server';
import type { RulesClient, RuleExecutorServices } from '@kbn/alerting-plugin/server';
import { getNonPackagedRules } from '../search/get_existing_prepackaged_rules';
import { getExportDetailsNdjson } from './get_export_details_ndjson';
import { transformAlertsToRules } from '../../utils/utils';
import { getRuleExceptionsForExport } from './get_export_rule_exceptions';
+import { getRuleActionConnectorsForExport } from './get_export_rule_action_connectors';
// eslint-disable-next-line no-restricted-imports
import { legacyGetBulkRuleActionsSavedObject } from '../../../rule_actions_legacy';
@@ -22,11 +23,14 @@ export const getExportAll = async (
rulesClient: RulesClient,
exceptionsClient: ExceptionListClient | undefined,
savedObjectsClient: RuleExecutorServices['savedObjectsClient'],
- logger: Logger
+ logger: Logger,
+ actionsExporter: ISavedObjectsExporter,
+ request: KibanaRequest
): Promise<{
rulesNdjson: string;
exportDetails: string;
exceptionLists: string | null;
+ actionConnectors: string;
}> => {
const ruleAlertTypes = await getNonPackagedRules({ rulesClient });
const alertIds = ruleAlertTypes.map((rule) => rule.id);
@@ -44,7 +48,15 @@ export const getExportAll = async (
const { exportData: exceptionLists, exportDetails: exceptionDetails } =
await getRuleExceptionsForExport(exceptions, exceptionsClient);
+ // Retrieve Action-Connectors
+ const { actionConnectors, actionConnectorDetails } = await getRuleActionConnectorsForExport(
+ rules,
+ actionsExporter,
+ request
+ );
+
const rulesNdjson = transformDataToNdjson(rules);
- const exportDetails = getExportDetailsNdjson(rules, [], exceptionDetails);
- return { rulesNdjson, exportDetails, exceptionLists };
+ const exportDetails = getExportDetailsNdjson(rules, [], exceptionDetails, actionConnectorDetails);
+
+ return { rulesNdjson, exportDetails, exceptionLists, actionConnectors };
};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts
index 67da643d503e4..40a6438954bb2 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts
@@ -6,9 +6,10 @@
*/
import { chunk } from 'lodash';
+
import { transformDataToNdjson } from '@kbn/securitysolution-utils';
-import type { Logger } from '@kbn/core/server';
+import type { ISavedObjectsExporter, KibanaRequest, Logger } from '@kbn/core/server';
import type { ExceptionListClient } from '@kbn/lists-plugin/server';
import type { RulesClient, RuleExecutorServices } from '@kbn/alerting-plugin/server';
@@ -17,6 +18,7 @@ import { getExportDetailsNdjson } from './get_export_details_ndjson';
import { isAlertType } from '../../../rule_schema';
import { findRules } from '../search/find_rules';
import { getRuleExceptionsForExport } from './get_export_rule_exceptions';
+import { getRuleActionConnectorsForExport } from './get_export_rule_action_connectors';
// eslint-disable-next-line no-restricted-imports
import { legacyGetBulkRuleActionsSavedObject } from '../../../rule_actions_legacy';
@@ -44,11 +46,14 @@ export const getExportByObjectIds = async (
exceptionsClient: ExceptionListClient | undefined,
savedObjectsClient: RuleExecutorServices['savedObjectsClient'],
objects: Array<{ rule_id: string }>,
- logger: Logger
+ logger: Logger,
+ actionsExporter: ISavedObjectsExporter,
+ request: KibanaRequest
): Promise<{
rulesNdjson: string;
exportDetails: string;
exceptionLists: string | null;
+ actionConnectors: string;
}> => {
const rulesAndErrors = await getRulesFromObjects(
rulesClient,
@@ -56,23 +61,29 @@ export const getExportByObjectIds = async (
objects,
logger
);
+ const { rules, missingRules } = rulesAndErrors;
// Retrieve exceptions
- const exceptions = rulesAndErrors.rules.flatMap((rule) => rule.exceptions_list ?? []);
+ const exceptions = rules.flatMap((rule) => rule.exceptions_list ?? []);
const { exportData: exceptionLists, exportDetails: exceptionDetails } =
await getRuleExceptionsForExport(exceptions, exceptionsClient);
- const rulesNdjson = transformDataToNdjson(rulesAndErrors.rules);
+ // Retrieve Action-Connectors
+ const actionConnectors = await getRuleActionConnectorsForExport(rules, actionsExporter, request);
+
+ const rulesNdjson = transformDataToNdjson(rules);
const exportDetails = getExportDetailsNdjson(
- rulesAndErrors.rules,
- rulesAndErrors.missingRules,
- exceptionDetails
+ rules,
+ missingRules,
+ exceptionDetails,
+ actionConnectors.actionConnectorDetails
);
return {
rulesNdjson,
exportDetails,
exceptionLists,
+ actionConnectors: actionConnectors.actionConnectors,
};
};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_details_ndjson.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_details_ndjson.ts
index 465c4b53b1e51..8aedcc4b645fd 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_details_ndjson.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_details_ndjson.ts
@@ -8,23 +8,31 @@
import type { ExportExceptionDetails } from '@kbn/securitysolution-io-ts-list-types';
import type { ExportRulesDetails } from '../../../../../../common/detection_engine/rule_management';
import type { RuleResponse } from '../../../../../../common/detection_engine/rule_schema';
+import type { DefaultActionConnectorDetails } from './get_export_rule_action_connectors';
export const getExportDetailsNdjson = (
rules: RuleResponse[],
missingRules: Array<{ rule_id: string }> = [],
- exceptionDetails?: ExportExceptionDetails
+ exceptionDetails?: ExportExceptionDetails,
+ actionConnectorDetails?: DefaultActionConnectorDetails
): string => {
+ let exportedCount = rules.length;
+
+ // TODO check what will be the default
+ if (actionConnectorDetails != null)
+ exportedCount += actionConnectorDetails.exported_action_connector_count;
+ if (exceptionDetails != null)
+ exportedCount +=
+ exceptionDetails.exported_exception_list_count +
+ exceptionDetails.exported_exception_list_item_count;
+
const stringified: ExportRulesDetails = {
- exported_count:
- exceptionDetails == null
- ? rules.length
- : rules.length +
- exceptionDetails.exported_exception_list_count +
- exceptionDetails.exported_exception_list_item_count,
+ exported_count: exportedCount,
exported_rules_count: rules.length,
missing_rules: missingRules,
missing_rules_count: missingRules.length,
...exceptionDetails,
+ ...actionConnectorDetails,
};
return `${JSON.stringify(stringified)}\n`;
};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_rule_action_connectors.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_rule_action_connectors.ts
new file mode 100644
index 0000000000000..332d5b1fc9cd6
--- /dev/null
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_rule_action_connectors.ts
@@ -0,0 +1,81 @@
+/*
+ * 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 type { KibanaRequest } from '@kbn/core-http-server';
+import type { SavedObject, SavedObjectTypeIdTuple } from '@kbn/core-saved-objects-common';
+import type {
+ SavedObjectsExportResultDetails,
+ ISavedObjectsExporter,
+ SavedObjectsExportExcludedObject,
+} from '@kbn/core-saved-objects-server';
+import { createConcatStream, createMapStream, createPromiseFromStreams } from '@kbn/utils';
+import type { RuleResponse } from '../../../../../../common/detection_engine/rule_schema';
+
+export interface DefaultActionConnectorDetails {
+ exported_action_connector_count: number;
+ missing_action_connection_count: number;
+ missing_action_connections: SavedObjectTypeIdTuple[];
+ excluded_action_connection_count: number;
+ excluded_action_connections: SavedObjectsExportExcludedObject[];
+}
+
+const defaultActionConnectorDetails: DefaultActionConnectorDetails = {
+ exported_action_connector_count: 0,
+ missing_action_connection_count: 0,
+ missing_action_connections: [],
+ excluded_action_connection_count: 0,
+ excluded_action_connections: [],
+};
+
+const mapExportedActionConnectorsDetailsToDefault = (
+ exportDetails: SavedObjectsExportResultDetails
+): DefaultActionConnectorDetails => {
+ return {
+ exported_action_connector_count: exportDetails.exportedCount,
+ missing_action_connection_count: exportDetails.missingRefCount,
+ missing_action_connections: exportDetails.missingReferences,
+ excluded_action_connection_count: exportDetails.excludedObjectsCount,
+ excluded_action_connections: exportDetails.excludedObjects,
+ };
+};
+
+export const getRuleActionConnectorsForExport = async (
+ rules: RuleResponse[],
+ actionsExporter: ISavedObjectsExporter,
+ request: KibanaRequest
+) => {
+ const exportedActionConnectors: {
+ actionConnectors: string;
+ actionConnectorDetails: DefaultActionConnectorDetails;
+ } = {
+ actionConnectors: '',
+ actionConnectorDetails: defaultActionConnectorDetails,
+ };
+
+ // TODO combine line 60 and 64
+ const actionsIds = [...new Set(rules.flatMap((rule) => rule.actions.map(({ id }) => id)))];
+
+ if (!actionsIds.length) return exportedActionConnectors;
+
+ const getActionsByObjectsParam = actionsIds.map((id) => ({ type: 'action', id }));
+ const actionDetails = await actionsExporter.exportByObjects({
+ objects: getActionsByObjectsParam,
+ request,
+ });
+
+ const actionsConnectorsToExport: SavedObject[] = await createPromiseFromStreams([
+ actionDetails,
+ createMapStream((obj: SavedObject | SavedObjectsExportResultDetails) => {
+ if ('exportedCount' in obj)
+ exportedActionConnectors.actionConnectorDetails =
+ mapExportedActionConnectorsDetailsToDefault(obj);
+ else return JSON.stringify(obj);
+ }),
+ createConcatStream([]),
+ ]);
+ exportedActionConnectors.actionConnectors = actionsConnectorsToExport.join('\n');
+ return exportedActionConnectors;
+};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.ts
index e325496225d9f..53a30980b8334 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.ts
@@ -24,6 +24,7 @@ import type {
ImportExceptionsListSchema,
} from '@kbn/securitysolution-io-ts-list-types';
+import type { SavedObject } from '@kbn/core-saved-objects-common';
import {
RuleToImport,
validateRuleToImport,
@@ -41,7 +42,9 @@ export const validateRulesStream = (): Transform => {
return createMapStream<{
exceptions: Array;
rules: Array;
+ actionConnectors: SavedObject[];
}>((items) => ({
+ actionConnectors: items.actionConnectors,
exceptions: items.exceptions,
rules: validateRules(items.rules),
}));
@@ -80,10 +83,15 @@ export const sortImports = (): Transform => {
return createReduceStream<{
exceptions: Array;
rules: Array;
+ actionConnectors: SavedObject[];
}>(
(acc, importItem) => {
if (has('list_id', importItem) || has('item_id', importItem) || has('entries', importItem)) {
return { ...acc, exceptions: [...acc.exceptions, importItem] };
+ }
+ // if (has('actionTypeId', importItem)) {
+ if (has('attributes', importItem)) {
+ return { ...acc, actionConnectors: [...acc.actionConnectors, importItem] };
} else {
return { ...acc, rules: [...acc.rules, importItem] };
}
@@ -91,6 +99,7 @@ export const sortImports = (): Transform => {
{
exceptions: [],
rules: [],
+ actionConnectors: [],
}
);
};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_action_connectors.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_action_connectors.ts
new file mode 100644
index 0000000000000..081c7c76c06ad
--- /dev/null
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_action_connectors.ts
@@ -0,0 +1,62 @@
+/*
+ * 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 { Readable } from 'stream';
+
+import type { ActionResult, ActionsClient } from '@kbn/actions-plugin/server';
+import type { SavedObject, SavedObjectsImportResponse } from '@kbn/core-saved-objects-common';
+import type { ISavedObjectsImporter } from '@kbn/core-saved-objects-server';
+
+interface ImportRuleActionConnectorsParams {
+ actionConnectors: SavedObject[];
+ actionsClient: ActionsClient;
+ actionsImporter: ISavedObjectsImporter;
+}
+
+export const importRuleActionConnectors = async ({
+ actionConnectors,
+ actionsClient,
+ actionsImporter,
+}: ImportRuleActionConnectorsParams): Promise => {
+ const importResult: SavedObjectsImportResponse = {
+ success: true,
+ errors: [],
+ successCount: 0,
+ warnings: [],
+ };
+
+ if (!actionConnectors.length) return importResult;
+ let actionConnectorsToImport: SavedObject[] = actionConnectors;
+ let storedActionConnectors: ActionResult[] | [] = [];
+
+ const actionConnectorIds = actionConnectors.map(({ id }) => id);
+ try {
+ // getBulk throws 404 error if the saved_oject wasn't found
+ storedActionConnectors = await actionsClient.getBulk(actionConnectorIds);
+ } catch (error) {
+ // TODO ask if there's a better way
+ if (error.output.statusCode === 400) storedActionConnectors = [];
+ }
+
+ if (storedActionConnectors.length)
+ actionConnectorsToImport = actionConnectors.filter(
+ ({ id }) => !storedActionConnectors.find((stored) => stored.id === id)
+ );
+
+ if (!actionConnectorsToImport.length) return importResult;
+
+ const readStream = Readable.from(actionConnectors);
+
+ // TODO add overwrite & createNewCopies based on request query
+ const result: SavedObjectsImportResponse = await actionsImporter.import({
+ readStream,
+ overwrite: false,
+ createNewCopies: false,
+ });
+
+ // TODO map to errorSchema of the rule
+ return result;
+};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
index 694bc916fefe3..eb01fe76f6d5c 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import type { SavedObjectsClientContract } from '@kbn/core/server';
+import type { SavedObject, SavedObjectsClientContract } from '@kbn/core/server';
import type {
ImportExceptionsListSchema,
ImportExceptionListItemSchema,
@@ -31,6 +31,7 @@ export type PromiseFromStreams = RuleToImport | Error;
export interface RuleExceptionsPromiseFromStreams {
rules: PromiseFromStreams[];
exceptions: Array;
+ actionConnectors: SavedObject[];
}
/**
From dddba87f632d53c95e9c49ca5b647d3b0a2018bf Mon Sep 17 00:00:00 2001
From: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Date: Wed, 11 Jan 2023 08:52:44 +0000
Subject: [PATCH 02/40] [CI] Auto-commit changed files from 'node
scripts/ts_project_linter --fix'
---
x-pack/plugins/security_solution/tsconfig.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json
index ced495e35fbe7..fb9640bca44f4 100644
--- a/x-pack/plugins/security_solution/tsconfig.json
+++ b/x-pack/plugins/security_solution/tsconfig.json
@@ -129,6 +129,7 @@
"@kbn/cypress-config",
"@kbn/controls-plugin",
"@kbn/shared-ux-utility",
+ "@kbn/core-saved-objects-common",
],
"exclude": [
"target/**/*",
From 605ba892cdd095392422f36dc46a786a73b85004 Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Wed, 11 Jan 2023 13:16:28 +0200
Subject: [PATCH 03/40] fix tests
---
.../import_rules/response_schema.test.ts | 23 +++++++++++++++++++
.../api/rules/import_rules/response_schema.ts | 1 +
.../export_rules_details_schema.mock.ts | 11 +++++++++
.../logic/export/get_export_all.test.ts | 20 +++++++++++++---
.../logic/export/get_export_by_object_ids.ts | 10 +++++---
5 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts
index 2f11e1a9c120f..33a59f9b1561c 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts
@@ -14,6 +14,7 @@ import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts
import type { ErrorSchema } from '../../../../schemas/response/error_schema';
import { ImportRulesResponse } from './response_schema';
+// TODO add tests for the action_connectors_success
describe('Import rules response schema', () => {
test('it should validate an empty import response with no errors', () => {
const payload: ImportRulesResponse = {
@@ -24,6 +25,8 @@ describe('Import rules response schema', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -42,6 +45,8 @@ describe('Import rules response schema', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -60,6 +65,8 @@ describe('Import rules response schema', () => {
exceptions_errors: [{ error: { status_code: 400, message: 'some message' } }],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -81,6 +88,8 @@ describe('Import rules response schema', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -102,6 +111,8 @@ describe('Import rules response schema', () => {
],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -120,6 +131,8 @@ describe('Import rules response schema', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -140,6 +153,8 @@ describe('Import rules response schema', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: -1,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -178,6 +193,8 @@ describe('Import rules response schema', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded as UnsafeCastForTest);
@@ -217,6 +234,8 @@ describe('Import rules response schema', () => {
exceptions_errors: [],
exceptions_success: 'hello',
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded as UnsafeCastForTest);
@@ -238,6 +257,8 @@ describe('Import rules response schema', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -262,6 +283,8 @@ describe('Import rules response schema', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts
index ac43f394734e9..23da5791e3044 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts
@@ -19,6 +19,7 @@ export const ImportRulesResponse = t.exact(
success: t.boolean,
success_count: PositiveInteger,
errors: t.array(errorSchema),
+ // TODO need to map SavedObjectsImportFailure to errorschema
// action_connectors_errors: t.array(errorSchema),
// action_connectors_warnings: t.array(),
action_connectors_success: t.boolean,
diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.mock.ts
index 64b82abdb3755..5e23fd3218917 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.mock.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.mock.ts
@@ -8,6 +8,7 @@
import { getExceptionExportDetailsMock } from '@kbn/lists-plugin/common/schemas/response/exception_export_details_schema.mock';
import type { ExportExceptionDetailsMock } from '@kbn/lists-plugin/common/schemas/response/exception_export_details_schema.mock';
import type { ExportRulesDetails } from './export_rules_details_schema';
+import type { DefaultActionConnectorDetails } from '../../../../../server/lib/detection_engine/rule_management/logic/export/get_export_rule_action_connectors';
interface RuleDetailsMock {
totalCount?: number;
@@ -16,6 +17,15 @@ interface RuleDetailsMock {
missingRules?: Array>;
}
+// TODO add the correct type DefaultActionConnectorDetails
+export const getActionConnectorDetailsMock = (): DefaultActionConnectorDetails => ({
+ exported_action_connector_count: 0,
+ missing_action_connection_count: 0,
+ missing_action_connections: [],
+ excluded_action_connection_count: 0,
+ excluded_action_connections: [],
+});
+
export const getOutputDetailsSample = (ruleDetails?: RuleDetailsMock): ExportRulesDetails => ({
exported_count: ruleDetails?.totalCount ?? 0,
exported_rules_count: ruleDetails?.rulesCount ?? 0,
@@ -29,6 +39,7 @@ export const getOutputDetailsSampleWithExceptions = (
): ExportRulesDetails => ({
...getOutputDetailsSample(ruleDetails),
...getExceptionExportDetailsMock(exceptionDetails),
+ ...getActionConnectorDetailsMock(),
});
export const getSampleDetailsAsNdjson = (sample: ExportRulesDetails): string => {
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts
index b7395236a2152..093baded97fd3 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts
@@ -24,13 +24,17 @@ import { getQueryRuleParams } from '../../../rule_schema/mocks';
import { getExceptionListClientMock } from '@kbn/lists-plugin/server/services/exception_lists/exception_list_client.mock';
import type { loggingSystemMock } from '@kbn/core/server/mocks';
import { requestContextMock } from '../../../routes/__mocks__/request_context';
+import { savedObjectsExporterMock } from '@kbn/core-saved-objects-import-export-server-mocks';
+import { mockRouter } from '@kbn/core-http-router-server-mocks';
const exceptionsClient = getExceptionListClientMock();
+// TODO add tests for connectors
describe('getExportAll', () => {
let logger: ReturnType;
const { clients } = requestContextMock.createTools();
-
+ const exporterMock = savedObjectsExporterMock.create();
+ const requestMock = mockRouter.createKibanaRequest();
beforeEach(async () => {
clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse());
});
@@ -55,7 +59,9 @@ describe('getExportAll', () => {
rulesClient,
exceptionsClient,
clients.savedObjectsClient,
- logger
+ logger,
+ exporterMock,
+ requestMock
);
const rulesJson = JSON.parse(exports.rulesNdjson);
const detailsJson = JSON.parse(exports.exportDetails);
@@ -114,6 +120,11 @@ describe('getExportAll', () => {
missing_exception_lists_count: 0,
missing_rules: [],
missing_rules_count: 0,
+ excluded_action_connection_count: 0,
+ excluded_action_connections: [],
+ exported_action_connector_count: 0,
+ missing_action_connection_count: 0,
+ missing_action_connections: [],
});
});
@@ -133,12 +144,15 @@ describe('getExportAll', () => {
rulesClient,
exceptionsClient,
clients.savedObjectsClient,
- logger
+ logger,
+ exporterMock,
+ requestMock
);
expect(exports).toEqual({
rulesNdjson: '',
exportDetails: getSampleDetailsAsNdjson(details),
exceptionLists: '',
+ actionConnectors: '',
});
});
});
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts
index 40a6438954bb2..7269e98a170fb 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts
@@ -69,21 +69,25 @@ export const getExportByObjectIds = async (
await getRuleExceptionsForExport(exceptions, exceptionsClient);
// Retrieve Action-Connectors
- const actionConnectors = await getRuleActionConnectorsForExport(rules, actionsExporter, request);
+ const { actionConnectors, actionConnectorDetails } = await getRuleActionConnectorsForExport(
+ rules,
+ actionsExporter,
+ request
+ );
const rulesNdjson = transformDataToNdjson(rules);
const exportDetails = getExportDetailsNdjson(
rules,
missingRules,
exceptionDetails,
- actionConnectors.actionConnectorDetails
+ actionConnectorDetails
);
return {
rulesNdjson,
exportDetails,
exceptionLists,
- actionConnectors: actionConnectors.actionConnectors,
+ actionConnectors,
};
};
From c9a2656d40e3f724cc16cf4d5fcf85525da43fc2 Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Wed, 11 Jan 2023 13:18:32 +0200
Subject: [PATCH 04/40] fix get export by id
---
.../export/get_export_by_object_ids.test.ts | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts
index 02b83342cd846..c13b3f457ea3e 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts
@@ -22,14 +22,19 @@ import {
} from '../../../../../../common/detection_engine/rule_management/mocks';
import { getQueryRuleParams } from '../../../rule_schema/mocks';
import { getExceptionListClientMock } from '@kbn/lists-plugin/server/services/exception_lists/exception_list_client.mock';
+import { savedObjectsExporterMock } from '@kbn/core-saved-objects-import-export-server-mocks';
+import { mockRouter } from '@kbn/core-http-router-server-mocks';
const exceptionsClient = getExceptionListClientMock();
import type { loggingSystemMock } from '@kbn/core/server/mocks';
import { requestContextMock } from '../../../routes/__mocks__/request_context';
+// TODO add tests for connectors
describe('get_export_by_object_ids', () => {
let logger: ReturnType;
const { clients } = requestContextMock.createTools();
+ const exporterMock = savedObjectsExporterMock.create();
+ const requestMock = mockRouter.createKibanaRequest();
beforeEach(() => {
jest.resetAllMocks();
@@ -50,7 +55,9 @@ describe('get_export_by_object_ids', () => {
exceptionsClient,
clients.savedObjectsClient,
objects,
- logger
+ logger,
+ exporterMock,
+ requestMock
);
const exportsObj = {
rulesNdjson: JSON.parse(exports.rulesNdjson),
@@ -112,6 +119,11 @@ describe('get_export_by_object_ids', () => {
missing_exception_lists_count: 0,
missing_rules: [],
missing_rules_count: 0,
+ excluded_action_connection_count: 0,
+ excluded_action_connections: [],
+ exported_action_connector_count: 0,
+ missing_action_connection_count: 0,
+ missing_action_connections: [],
},
});
});
@@ -137,7 +149,9 @@ describe('get_export_by_object_ids', () => {
exceptionsClient,
clients.savedObjectsClient,
objects,
- logger
+ logger,
+ exporterMock,
+ requestMock
);
const details = getOutputDetailsSampleWithExceptions({
missingRules: [{ rule_id: 'rule-1' }],
@@ -147,6 +161,7 @@ describe('get_export_by_object_ids', () => {
rulesNdjson: '',
exportDetails: getSampleDetailsAsNdjson(details),
exceptionLists: '',
+ actionConnectors: '',
});
});
});
From 9b2cb0e778624cbf83ffd163a346f384ef30d76a Mon Sep 17 00:00:00 2001
From: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Date: Wed, 11 Jan 2023 11:22:57 +0000
Subject: [PATCH 05/40] [CI] Auto-commit changed files from 'node
scripts/lint_ts_projects --fix'
---
x-pack/plugins/security_solution/tsconfig.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json
index 8824971b0fab1..f51e3c8b5a3ba 100644
--- a/x-pack/plugins/security_solution/tsconfig.json
+++ b/x-pack/plugins/security_solution/tsconfig.json
@@ -134,5 +134,6 @@
"@kbn/controls-plugin",
"@kbn/shared-ux-utility",
"@kbn/core-saved-objects-common",
+ "@kbn/core-saved-objects-import-export-server-mocks",
]
}
From f5a199b117cb850f2e6715111b7d78a78035b3f6 Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Wed, 11 Jan 2023 15:59:40 +0200
Subject: [PATCH 06/40] comment warnings until decide if needed
---
.../rule_management/api/rules/import_rules/route.ts | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
index 6bb12762d4492..5ca5bac729767 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
@@ -127,8 +127,9 @@ export const importRulesRoute = (
const {
successCount: actionConnectorSuccessCount,
success: actionConnectorSuccess,
- warnings: actionConnectorWarnings,
- errors: actionConnectorErrors,
+ // TODO revert back after the mapping
+ // warnings: actionConnectorWarnings,
+ // errors: actionConnectorErrors,
} = await importRuleActionConnectors({
actionConnectors,
actionsClient,
From 0a0032681d69fda1e0d3a6605a62276ec505a05f Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Wed, 11 Jan 2023 19:28:37 +0200
Subject: [PATCH 07/40] fix tests
---
.../export_rules_details_schema.test.ts | 9 ++--
.../export/export_rules_details_schema.ts | 46 +++++++++++++------
.../api/rules/import_rules/route.test.ts | 26 +++++++++++
3 files changed, 64 insertions(+), 17 deletions(-)
diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.test.ts
index 2c84a34b34928..907f23f1dc985 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.test.ts
@@ -21,12 +21,13 @@ import {
getOutputDetailsSampleWithExceptions,
} from './export_rules_details_schema.mock';
import type { ExportRulesDetails } from './export_rules_details_schema';
-import { exportRulesDetailsWithExceptionsSchema } from './export_rules_details_schema';
+import { exportRulesDetailsWithExceptionsAndConnectorsSchema } from './export_rules_details_schema';
+// TODO add tests for connectors
describe('exportRulesDetailsWithExceptionsSchema', () => {
test('it should validate export details response', () => {
const payload = getOutputDetailsSample();
- const decoded = exportRulesDetailsWithExceptionsSchema.decode(payload);
+ const decoded = exportRulesDetailsWithExceptionsAndConnectorsSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
@@ -36,7 +37,7 @@ describe('exportRulesDetailsWithExceptionsSchema', () => {
test('it should validate export details with exceptions details response', () => {
const payload = getOutputDetailsSampleWithExceptions();
- const decoded = exportRulesDetailsWithExceptionsSchema.decode(payload);
+ const decoded = exportRulesDetailsWithExceptionsAndConnectorsSchema.decode(payload);
const checked = exactCheck(payload, decoded);
const message = pipe(checked, foldLeftRight);
@@ -49,7 +50,7 @@ describe('exportRulesDetailsWithExceptionsSchema', () => {
extraKey?: string;
} = getOutputDetailsSample();
payload.extraKey = 'some extra key';
- const decoded = exportRulesDetailsWithExceptionsSchema.decode(payload);
+ const decoded = exportRulesDetailsWithExceptionsAndConnectorsSchema.decode(payload);
const message = pipe(decoded, foldLeftRight);
expect(getPaths(left(message.errors))).toEqual([]);
diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.ts
index 85b423135566b..205861bdd42a7 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/export/export_rules_details_schema.ts
@@ -9,13 +9,6 @@ import * as t from 'io-ts';
import { exportExceptionDetails } from '@kbn/securitysolution-io-ts-list-types';
import { NonEmptyString } from '@kbn/securitysolution-io-ts-types';
-const createSchema = (
- requiredFields: Required,
- optionalFields: Optional
-) => {
- return t.intersection([t.exact(t.type(requiredFields)), t.exact(t.partial(optionalFields))]);
-};
-
const exportRulesDetails = {
exported_count: t.number,
exported_rules_count: t.number,
@@ -28,11 +21,38 @@ const exportRulesDetails = {
),
missing_rules_count: t.number,
};
+const excludedActionConnectors = t.intersection([
+ t.exact(
+ t.type({
+ id: NonEmptyString,
+ type: NonEmptyString,
+ })
+ ),
+ t.exact(t.partial({ reason: t.string })),
+]);
+
+const exportRuleActionConnectorsDetails = {
+ exported_action_connector_count: t.number,
+ missing_action_connection_count: t.number,
+ missing_action_connections: t.array(
+ t.exact(
+ t.type({
+ id: NonEmptyString,
+ type: NonEmptyString,
+ })
+ )
+ ),
+ excluded_action_connection_count: t.number,
+ excluded_action_connections: t.array(excludedActionConnectors),
+};
-// With exceptions
-export const exportRulesDetailsWithExceptionsSchema = createSchema(
- exportRulesDetails,
- exportExceptionDetails
-);
+// With exceptions and connectors
+export const exportRulesDetailsWithExceptionsAndConnectorsSchema = t.intersection([
+ t.exact(t.type(exportRulesDetails)),
+ t.exact(t.partial(exportExceptionDetails)),
+ t.exact(t.partial(exportRuleActionConnectorsDetails)),
+]);
-export type ExportRulesDetails = t.TypeOf;
+export type ExportRulesDetails = t.TypeOf<
+ typeof exportRulesDetailsWithExceptionsAndConnectorsSchema
+>;
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts
index 3d466d2505074..0483d4abd60f5 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts
@@ -34,6 +34,8 @@ import { importRulesRoute } from './route';
jest.mock('../../../../../machine_learning/authz');
+// TODO add tests for connectors
+
describe('Import rules route', () => {
let config: ReturnType;
let server: ReturnType;
@@ -107,6 +109,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
@@ -146,6 +150,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
@@ -171,6 +177,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
@@ -196,6 +204,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
@@ -218,6 +228,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
});
@@ -242,6 +254,8 @@ describe('Import rules route', () => {
rules_count: 2,
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
@@ -262,6 +276,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
@@ -302,6 +318,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
@@ -332,6 +350,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
@@ -353,6 +373,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
});
@@ -387,6 +409,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
@@ -407,6 +431,8 @@ describe('Import rules route', () => {
exceptions_errors: [],
exceptions_success: true,
exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
});
});
});
From eca3cf3919589d7fa581fc40a643acbd0a23048e Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Tue, 17 Jan 2023 12:09:51 +0200
Subject: [PATCH 08/40] enable Rule importing even if connectors are missing
secrets
---
.../server/rules_client/methods/create.ts | 13 ++--
.../api/rules/import_rules/response_schema.ts | 7 +--
.../schemas/response/index.ts | 1 +
.../schemas/response/warning_schema/index.ts | 24 ++++++++
.../components/import_data_modal/index.tsx | 60 +++++++++++++++++--
.../rule_management/logic/types.ts | 4 ++
.../api/rules/import_rules/route.ts | 33 ++++------
.../logic/crud/create_rules.ts | 3 +
.../import_rule_action_connectors.ts | 38 ++++++------
.../logic/import/action_connectors/types.ts | 25 ++++++++
...alidate_action_connectors_import_result.ts | 24 ++++++++
.../logic/import/import_rules_utils.ts | 3 +
12 files changed, 179 insertions(+), 56 deletions(-)
create mode 100644 x-pack/plugins/security_solution/common/detection_engine/schemas/response/warning_schema/index.ts
rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/{ => action_connectors}/import_rule_action_connectors.ts (62%)
create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/types.ts
create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/validate_action_connectors_import_result.ts
diff --git a/x-pack/plugins/alerting/server/rules_client/methods/create.ts b/x-pack/plugins/alerting/server/rules_client/methods/create.ts
index e8dcefe4a9ef1..ef78f83edaac2 100644
--- a/x-pack/plugins/alerting/server/rules_client/methods/create.ts
+++ b/x-pack/plugins/alerting/server/rules_client/methods/create.ts
@@ -46,11 +46,12 @@ export interface CreateOptions {
| 'nextRun'
> & { actions: NormalizedAlertAction[] };
options?: SavedObjectOptions;
+ validateRuleActionConnectors?: boolean;
}
export async function create(
context: RulesClientContext,
- { data, options }: CreateOptions
+ { data, options, validateRuleActionConnectors }: CreateOptions
): Promise> {
const id = options?.id || SavedObjectsUtils.generateId();
@@ -104,10 +105,12 @@ export async function create(
}
}
- await validateActions(context, ruleType, data);
- await withSpan({ name: 'validateActions', type: 'rules' }, () =>
- validateActions(context, ruleType, data)
- );
+ if (validateRuleActionConnectors) {
+ await validateActions(context, ruleType, data);
+ await withSpan({ name: 'validateActions', type: 'rules' }, () =>
+ validateActions(context, ruleType, data)
+ );
+ }
// Throw error if schedule interval is less than the minimum and we are enforcing it
const intervalInMs = parseDuration(data.schedule.interval);
if (
diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts
index 23da5791e3044..99212b902c4d3 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.ts
@@ -7,7 +7,7 @@
import * as t from 'io-ts';
import { PositiveInteger } from '@kbn/securitysolution-io-ts-types';
-import { errorSchema } from '../../../../schemas/response/error_schema';
+import { errorSchema, warningSchema } from '../../../../schemas/response';
export type ImportRulesResponse = t.TypeOf;
export const ImportRulesResponse = t.exact(
@@ -19,9 +19,8 @@ export const ImportRulesResponse = t.exact(
success: t.boolean,
success_count: PositiveInteger,
errors: t.array(errorSchema),
- // TODO need to map SavedObjectsImportFailure to errorschema
- // action_connectors_errors: t.array(errorSchema),
- // action_connectors_warnings: t.array(),
+ action_connectors_errors: t.array(errorSchema),
+ action_connectors_warnings: t.array(warningSchema),
action_connectors_success: t.boolean,
action_connectors_success_count: PositiveInteger,
})
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts
index b20a956525e2e..76da687604028 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts
@@ -6,3 +6,4 @@
*/
export * from './error_schema';
+export * from './warning_schema';
diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/warning_schema/index.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/warning_schema/index.ts
new file mode 100644
index 0000000000000..1a401d1941cb0
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/warning_schema/index.ts
@@ -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.
+ */
+
+import * as t from 'io-ts';
+
+const partial = t.exact(
+ t.partial({
+ buttonLabel: t.string,
+ })
+);
+const required = t.exact(
+ t.type({
+ type: t.string,
+ message: t.string,
+ actionPath: t.string,
+ })
+);
+
+export const warningSchema = t.intersection([partial, required]);
+export type WarningSchema = t.TypeOf;
diff --git a/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx b/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx
index a291265bc234d..525d6b826ee15 100644
--- a/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx
@@ -5,11 +5,15 @@
* 2.0.
*/
+import React, { useCallback, useState } from 'react';
import {
EuiButton,
EuiButtonEmpty,
+ EuiCallOut,
EuiCheckbox,
EuiFilePicker,
+ EuiFlexGroup,
+ EuiFlexItem,
EuiModal,
EuiModalBody,
EuiModalFooter,
@@ -18,7 +22,7 @@ import {
EuiSpacer,
EuiText,
} from '@elastic/eui';
-import React, { useCallback, useState } from 'react';
+import type { WarningSchema } from '../../../../common/detection_engine/schemas/response';
import type {
ImportDataResponse,
@@ -27,6 +31,7 @@ import type {
import { useAppToasts } from '../../hooks/use_app_toasts';
import * as i18n from './translations';
import { showToasterMessage } from './utils';
+import { useKibana } from '../../lib/kibana/kibana_react';
interface ImportDataModalProps {
checkBoxLabel: string;
@@ -70,6 +75,14 @@ export const ImportDataModalComponent = ({
const [overwrite, setOverwrite] = useState(false);
const [overwriteExceptions, setOverwriteExceptions] = useState(false);
const { addError, addSuccess } = useAppToasts();
+ // TODO Ask if we use schema on the FE
+ const [actionConnectorsWarnings, setActionConnectorsWarnings] = useState(
+ []
+ );
+ const {
+ http,
+ application: { navigateToApp },
+ } = useKibana().services;
const cleanupAndCloseModal = useCallback(() => {
setIsImporting(false);
@@ -85,12 +98,14 @@ export const ImportDataModalComponent = ({
const abortCtrl = new AbortController();
try {
- const importResponse = await importData({
+ const { action_connectors_warnings: warnings, ...importResponse } = await importData({
fileToImport: selectedFiles[0],
overwrite,
overwriteExceptions,
signal: abortCtrl.signal,
});
+ const showWarnings = !!warnings?.length;
+ setActionConnectorsWarnings(warnings as WarningSchema[]);
showToasterMessage({
importResponse,
@@ -102,19 +117,24 @@ export const ImportDataModalComponent = ({
addSuccess,
});
- importComplete();
- cleanupAndCloseModal();
+ if (!showWarnings) {
+ importComplete();
+ return cleanupAndCloseModal();
+ }
+
+ setIsImporting(false);
+ setSelectedFiles(null);
} catch (error) {
cleanupAndCloseModal();
addError(error, { title: errorMessage(1) });
}
}
}, [
+ showExceptionsCheckBox,
selectedFiles,
- importData,
overwrite,
overwriteExceptions,
- showExceptionsCheckBox,
+ importData,
successMessage,
errorMessage,
failedDetailed,
@@ -163,6 +183,34 @@ export const ImportDataModalComponent = ({
isLoading={isImporting}
/>
+ {!!actionConnectorsWarnings?.length &&
+ actionConnectorsWarnings.map(({ message, actionPath, buttonLabel }) => (
+
+
+
+ {message}
+
+
+ {buttonLabel && (
+
+
+ {buttonLabel}
+
+
+ )}
+
+
+ ))}
+
+
{showCheckBox && (
<>
!(rule instanceof Error));
-
- if (actualRules.some((rule) => rule.actions && rule.actions.length > 0)) {
- const [nonExistentActionErrors, uniqueParsedObjects] = await getInvalidConnectors(
- migratedParsedObjectsWithoutDuplicateErrors,
- actionsClient
- );
- parsedRules = uniqueParsedObjects;
- actionErrors = nonExistentActionErrors;
- } else {
- parsedRules = migratedParsedObjectsWithoutDuplicateErrors;
- }
+ // TODO check why we need to parse rules??
+ const parsedRules = migratedParsedObjectsWithoutDuplicateErrors;
+
// gather all exception lists that the imported rules reference
const foundReferencedExceptionLists = await getReferencedExceptionLists({
rules: parsedRules,
@@ -169,7 +155,7 @@ export const importRulesRoute = (
const importRuleResponse: ImportRuleResponse[] = await importRulesHelper({
ruleChunks: chunkParseObjects,
- rulesResponseAcc: [...actionErrors, ...duplicateIdErrors],
+ rulesResponseAcc: [...actionConnectorErrors, ...duplicateIdErrors],
mlAuthz,
overwriteRules: request.query.overwrite,
rulesClient,
@@ -177,6 +163,7 @@ export const importRulesRoute = (
exceptionsClient,
spaceId: ctx.securitySolution.getSpaceId(),
existingLists: foundReferencedExceptionLists,
+ validateRuleActionConnectors: !actionConnectors.length,
});
const errorsResp = importRuleResponse.filter((resp) => isBulkError(resp)) as BulkError[];
@@ -195,10 +182,10 @@ export const importRulesRoute = (
exceptions_errors: exceptionsErrors,
exceptions_success: exceptionsSuccess,
exceptions_success_count: exceptionsSuccessCount,
- // action_connectors_errors: actionConnectorErrors,
- // action_connectors_warnings: actionConnectorWarnings,
action_connectors_success: actionConnectorSuccess,
action_connectors_success_count: actionConnectorSuccessCount,
+ action_connectors_errors: actionConnectorErrors,
+ action_connectors_warnings: actionConnectorWarnings,
};
const [validated, errors] = validate(importRules, ImportRulesResponse);
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts
index f621542fe433f..0b2069fef75d0 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts
@@ -19,6 +19,7 @@ export interface CreateRulesOptions
id?: string;
immutable?: boolean;
defaultEnabled?: boolean;
+ validateRuleActionConnectors?: boolean;
}
export const createRules = async ({
@@ -27,6 +28,7 @@ export const createRules = async ({
id,
immutable = false,
defaultEnabled = true,
+ validateRuleActionConnectors,
}: CreateRulesOptions): Promise> => {
const internalRule = convertCreateAPIToInternalSchema(params, immutable, defaultEnabled);
const rule = await rulesClient.create({
@@ -34,6 +36,7 @@ export const createRules = async ({
id,
},
data: internalRule,
+ validateRuleActionConnectors,
});
// Mute the rule if it is first created with the explicit no actions
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_action_connectors.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/import_rule_action_connectors.ts
similarity index 62%
rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_action_connectors.ts
rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/import_rule_action_connectors.ts
index 081c7c76c06ad..83388ab6673ac 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rule_action_connectors.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/import_rule_action_connectors.ts
@@ -6,22 +6,18 @@
*/
import { Readable } from 'stream';
-import type { ActionResult, ActionsClient } from '@kbn/actions-plugin/server';
+import type { ActionResult } from '@kbn/actions-plugin/server';
import type { SavedObject, SavedObjectsImportResponse } from '@kbn/core-saved-objects-common';
-import type { ISavedObjectsImporter } from '@kbn/core-saved-objects-server';
-
-interface ImportRuleActionConnectorsParams {
- actionConnectors: SavedObject[];
- actionsClient: ActionsClient;
- actionsImporter: ISavedObjectsImporter;
-}
+import type { WarningSchema } from '../../../../../../../common/detection_engine/schemas/response';
+import { mapSOErrorToRuleError } from './validate_action_connectors_import_result';
+import type { ImportRuleActionConnectorsParams, ImportRuleActionConnectorsResult } from './types';
export const importRuleActionConnectors = async ({
actionConnectors,
actionsClient,
actionsImporter,
-}: ImportRuleActionConnectorsParams): Promise => {
- const importResult: SavedObjectsImportResponse = {
+}: ImportRuleActionConnectorsParams): Promise => {
+ const importResult: ImportRuleActionConnectorsResult = {
success: true,
errors: [],
successCount: 0,
@@ -51,12 +47,18 @@ export const importRuleActionConnectors = async ({
const readStream = Readable.from(actionConnectors);
// TODO add overwrite & createNewCopies based on request query
- const result: SavedObjectsImportResponse = await actionsImporter.import({
- readStream,
- overwrite: false,
- createNewCopies: false,
- });
-
- // TODO map to errorSchema of the rule
- return result;
+ const { success, successCount, successResults, warnings, errors }: SavedObjectsImportResponse =
+ await actionsImporter.import({
+ readStream,
+ overwrite: false,
+ createNewCopies: false,
+ });
+
+ return {
+ success,
+ successCount,
+ successResults,
+ errors: mapSOErrorToRuleError(errors) || [],
+ warnings: (warnings as WarningSchema[]) || [],
+ };
};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/types.ts
new file mode 100644
index 0000000000000..37d16c518adcd
--- /dev/null
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/types.ts
@@ -0,0 +1,25 @@
+/*
+ * 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 type { ISavedObjectsImporter } from '@kbn/core-saved-objects-server';
+import type { ActionsClient } from '@kbn/actions-plugin/server';
+import type { SavedObject, SavedObjectsImportSuccess } from '@kbn/core-saved-objects-common';
+import type { WarningSchema } from '../../../../../../../common/detection_engine/schemas/response';
+import type { BulkError } from '../../../../routes/utils';
+
+export interface ImportRuleActionConnectorsResult {
+ success: boolean;
+ successCount: number;
+ successResults?: SavedObjectsImportSuccess[];
+ errors: BulkError[] | [];
+ warnings: WarningSchema[] | [];
+}
+
+export interface ImportRuleActionConnectorsParams {
+ actionConnectors: SavedObject[];
+ actionsClient: ActionsClient;
+ actionsImporter: ISavedObjectsImporter;
+}
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/validate_action_connectors_import_result.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/validate_action_connectors_import_result.ts
new file mode 100644
index 0000000000000..23f06a407e018
--- /dev/null
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/action_connectors/validate_action_connectors_import_result.ts
@@ -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.
+ */
+
+import type {
+ SavedObjectsImportFailure,
+ SavedObjectsImportUnknownError,
+} from '@kbn/core-saved-objects-common';
+import type { BulkError } from '../../../../routes/utils';
+import { createBulkErrorObject } from '../../../../routes/utils';
+
+export const mapSOErrorToRuleError = (errors?: SavedObjectsImportFailure[]): BulkError[] => {
+ if (!errors) return [];
+ return errors.map(({ id, error }) =>
+ createBulkErrorObject({
+ id,
+ statusCode: (error as SavedObjectsImportUnknownError).statusCode,
+ message: (error as SavedObjectsImportUnknownError).message,
+ })
+ );
+};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
index eb01fe76f6d5c..a275de8af6eb7 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
@@ -61,6 +61,7 @@ export const importRules = async ({
exceptionsClient,
spaceId,
existingLists,
+ validateRuleActionConnectors,
}: {
ruleChunks: PromiseFromStreams[][];
rulesResponseAcc: ImportRuleResponse[];
@@ -71,6 +72,7 @@ export const importRules = async ({
exceptionsClient: ExceptionListClient | undefined;
spaceId: string;
existingLists: Record;
+ validateRuleActionConnectors: boolean;
}) => {
let importRuleResponse: ImportRuleResponse[] = [...rulesResponseAcc];
@@ -119,6 +121,7 @@ export const importRules = async ({
...parsedRule,
exceptions_list: [...exceptions],
},
+ validateRuleActionConnectors,
});
resolve({
rule_id: parsedRule.rule_id,
From 912b6c9c7925c8c30d2a20818a675face335c44c Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Tue, 17 Jan 2023 15:12:46 +0200
Subject: [PATCH 09/40] test: Import rules response schema
---
.../import_rules/response_schema.test.ts | 157 +++++++++++++++++-
1 file changed, 156 insertions(+), 1 deletion(-)
diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts
index 33a59f9b1561c..a63a2006041e2 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts
@@ -14,7 +14,6 @@ import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts
import type { ErrorSchema } from '../../../../schemas/response/error_schema';
import { ImportRulesResponse } from './response_schema';
-// TODO add tests for the action_connectors_success
describe('Import rules response schema', () => {
test('it should validate an empty import response with no errors', () => {
const payload: ImportRulesResponse = {
@@ -27,6 +26,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -47,6 +48,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -67,6 +70,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -90,6 +95,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -113,6 +120,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -133,6 +142,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -155,6 +166,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: -1,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -195,6 +208,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded as UnsafeCastForTest);
@@ -236,6 +251,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded as UnsafeCastForTest);
@@ -259,6 +276,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -285,6 +304,8 @@ describe('Import rules response schema', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
};
const decoded = ImportRulesResponse.decode(payload);
const checked = exactCheck(payload, decoded);
@@ -293,4 +314,138 @@ describe('Import rules response schema', () => {
expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_data"']);
expect(message.schema).toEqual({});
});
+
+ test('it should validate an empty import response with a single connectors error', () => {
+ const payload: ImportRulesResponse = {
+ success: false,
+ success_count: 0,
+ rules_count: 0,
+ errors: [],
+ exceptions_errors: [],
+ exceptions_success: true,
+ exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
+ action_connectors_errors: [{ error: { status_code: 400, message: 'some message' } }],
+ action_connectors_warnings: [],
+ };
+ const decoded = ImportRulesResponse.decode(payload);
+ const checked = exactCheck(payload, decoded);
+ const message = pipe(checked, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([]);
+ expect(message.schema).toEqual(payload);
+ });
+ test('it should validate an empty import response with multiple errors', () => {
+ const payload: ImportRulesResponse = {
+ success: false,
+ success_count: 0,
+ rules_count: 0,
+ errors: [
+ { error: { status_code: 400, message: 'some message' } },
+ { error: { status_code: 500, message: 'some message' } },
+ ],
+ exceptions_errors: [],
+ exceptions_success: true,
+ exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
+ action_connectors_errors: [{ error: { status_code: 400, message: 'some message' } }],
+ action_connectors_warnings: [],
+ };
+ const decoded = ImportRulesResponse.decode(payload);
+ const checked = exactCheck(payload, decoded);
+ const message = pipe(checked, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([]);
+ expect(message.schema).toEqual(payload);
+ });
+ test('it should NOT validate action_connectors_success that is not boolean', () => {
+ type UnsafeCastForTest = Either<
+ Errors,
+ {
+ success: boolean;
+ action_connectors_success: string;
+ success_count: number;
+ errors: Array<
+ {
+ id?: string | undefined;
+ rule_id?: string | undefined;
+ } & {
+ error: {
+ status_code: number;
+ message: string;
+ };
+ }
+ >;
+ }
+ >;
+ const payload: Omit & {
+ action_connectors_success: string;
+ } = {
+ success: true,
+ success_count: 0,
+ rules_count: 0,
+ errors: [],
+ exceptions_errors: [],
+ exceptions_success: true,
+ exceptions_success_count: 0,
+ action_connectors_success: 'invalid',
+ action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
+ };
+ const decoded = ImportRulesResponse.decode(payload);
+ const checked = exactCheck(payload, decoded as UnsafeCastForTest);
+ const message = pipe(checked, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([
+ 'Invalid value "invalid" supplied to "action_connectors_success"',
+ ]);
+ expect(message.schema).toEqual({});
+ });
+ test('it should NOT validate a action_connectors_success_count that is a negative number', () => {
+ const payload: ImportRulesResponse = {
+ success: false,
+ success_count: 0,
+ rules_count: 0,
+ errors: [],
+ exceptions_errors: [],
+ exceptions_success: true,
+ exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: -1,
+ action_connectors_errors: [],
+ action_connectors_warnings: [],
+ };
+ const decoded = ImportRulesResponse.decode(payload);
+ const checked = exactCheck(payload, decoded);
+ const message = pipe(checked, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([
+ 'Invalid value "-1" supplied to "action_connectors_success_count"',
+ ]);
+ expect(message.schema).toEqual({});
+ });
+ test('it should validate a action_connectors_warnings after importing successfully', () => {
+ const payload: ImportRulesResponse = {
+ success: false,
+ success_count: 0,
+ rules_count: 0,
+ errors: [],
+ exceptions_errors: [],
+ exceptions_success: true,
+ exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 1,
+ action_connectors_errors: [],
+ action_connectors_warnings: [{ type: 'type', message: 'message', actionPath: 'actionPath' }],
+ };
+ const decoded = ImportRulesResponse.decode(payload);
+ const checked = exactCheck(payload, decoded);
+ const message = pipe(checked, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([]);
+ expect(message.schema).toEqual(payload);
+ });
});
From d898d3b53fd02f1917505adfc972d9e51c65440e Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Tue, 17 Jan 2023 16:02:16 +0200
Subject: [PATCH 10/40] rename validateRuleActionConnectors to
skipActionConnectorsValidations to negate the boolean
---
.../server/rules_client/methods/create.ts | 6 +-
.../server/rules_client/tests/create.test.ts | 172 ++++++++++++++++++
.../import_rules/response_schema.test.ts | 44 +++++
.../api/rules/import_rules/route.ts | 2 +-
.../logic/crud/create_rules.ts | 6 +-
.../logic/import/import_rules_utils.ts | 6 +-
6 files changed, 226 insertions(+), 10 deletions(-)
diff --git a/x-pack/plugins/alerting/server/rules_client/methods/create.ts b/x-pack/plugins/alerting/server/rules_client/methods/create.ts
index ef78f83edaac2..cb9560c415f32 100644
--- a/x-pack/plugins/alerting/server/rules_client/methods/create.ts
+++ b/x-pack/plugins/alerting/server/rules_client/methods/create.ts
@@ -46,12 +46,12 @@ export interface CreateOptions {
| 'nextRun'
> & { actions: NormalizedAlertAction[] };
options?: SavedObjectOptions;
- validateRuleActionConnectors?: boolean;
+ skipActionConnectorsValidations?: boolean;
}
export async function create(
context: RulesClientContext,
- { data, options, validateRuleActionConnectors }: CreateOptions
+ { data, options, skipActionConnectorsValidations }: CreateOptions
): Promise> {
const id = options?.id || SavedObjectsUtils.generateId();
@@ -105,7 +105,7 @@ export async function create(
}
}
- if (validateRuleActionConnectors) {
+ if (!skipActionConnectorsValidations) {
await validateActions(context, ruleType, data);
await withSpan({ name: 'validateActions', type: 'rules' }, () =>
validateActions(context, ruleType, data)
diff --git a/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts
index 050de16a68a84..fc0b248ed358a 100644
--- a/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts
+++ b/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts
@@ -2889,4 +2889,176 @@ describe('create()', () => {
expect(unsecuredSavedObjectsClient.create).not.toHaveBeenCalled();
expect(taskManager.schedule).not.toHaveBeenCalled();
});
+
+ test('should create a rule and not throw an error when skipActionConnectorsValidations is true even when some actions are missing frequency params', async () => {
+ const data = getMockData({
+ actions: [
+ {
+ group: 'default',
+ id: '1',
+ params: {
+ foo: true,
+ },
+ },
+ {
+ group: 'default',
+ id: '1',
+ params: {
+ foo: true,
+ },
+ },
+ {
+ group: 'default',
+ id: '2',
+ params: {
+ foo: true,
+ },
+ },
+ ],
+ });
+ actionsClient.getBulk.mockReset();
+ actionsClient.getBulk.mockResolvedValue([
+ {
+ id: '1',
+ actionTypeId: 'test',
+ config: {
+ from: 'me@me.com',
+ hasAuth: false,
+ host: 'hello',
+ port: 22,
+ secure: null,
+ service: null,
+ },
+ isMissingSecrets: true,
+ name: 'email connector',
+ isPreconfigured: false,
+ isDeprecated: false,
+ },
+ {
+ id: '2',
+ actionTypeId: 'test',
+ config: {
+ from: 'me@me.com',
+ hasAuth: false,
+ host: 'hello',
+ port: 22,
+ secure: null,
+ service: null,
+ },
+ isMissingSecrets: false,
+ name: 'email connector',
+ isPreconfigured: false,
+ isDeprecated: false,
+ },
+ ]);
+ unsecuredSavedObjectsClient.create.mockResolvedValueOnce({
+ id: '1',
+ type: 'alert',
+ attributes: {
+ alertTypeId: '123',
+ schedule: { interval: '1m' },
+ params: {
+ bar: true,
+ },
+ createdAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString(),
+ notifyWhen: null,
+ actions: [
+ {
+ group: 'default',
+ actionRef: 'action_0',
+ actionTypeId: 'test',
+ params: {
+ foo: true,
+ },
+ },
+ {
+ group: 'default',
+ actionRef: 'action_1',
+ actionTypeId: 'test',
+ params: {
+ foo: true,
+ },
+ },
+ {
+ group: 'default',
+ actionRef: 'action_2',
+ actionTypeId: 'test2',
+ params: {
+ foo: true,
+ },
+ },
+ ],
+ },
+ references: [
+ {
+ name: 'action_0',
+ type: 'action',
+ id: '1',
+ },
+ {
+ name: 'action_1',
+ type: 'action',
+ id: '1',
+ },
+ {
+ name: 'action_2',
+ type: 'action',
+ id: '2',
+ },
+ ],
+ });
+ unsecuredSavedObjectsClient.create.mockResolvedValueOnce({
+ id: '1',
+ type: 'alert',
+ attributes: {
+ actions: [],
+ scheduledTaskId: 'task-123',
+ },
+ references: [],
+ });
+ const result = await rulesClient.create({ data, skipActionConnectorsValidations: true });
+ expect(result).toMatchInlineSnapshot(`
+ Object {
+ "actions": Array [
+ Object {
+ "actionTypeId": "test",
+ "group": "default",
+ "id": "1",
+ "params": Object {
+ "foo": true,
+ },
+ },
+ Object {
+ "actionTypeId": "test",
+ "group": "default",
+ "id": "1",
+ "params": Object {
+ "foo": true,
+ },
+ },
+ Object {
+ "actionTypeId": "test2",
+ "group": "default",
+ "id": "2",
+ "params": Object {
+ "foo": true,
+ },
+ },
+ ],
+ "alertTypeId": "123",
+ "createdAt": 2019-02-12T21:01:22.479Z,
+ "id": "1",
+ "notifyWhen": null,
+ "params": Object {
+ "bar": true,
+ },
+ "schedule": Object {
+ "interval": "1m",
+ },
+ "scheduledTaskId": "task-123",
+ "updatedAt": 2019-02-12T21:01:22.479Z,
+ }
+ `);
+ });
});
diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts
index a63a2006041e2..b2ff257ba2c4e 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/api/rules/import_rules/response_schema.test.ts
@@ -448,4 +448,48 @@ describe('Import rules response schema', () => {
expect(getPaths(left(message.errors))).toEqual([]);
expect(message.schema).toEqual(payload);
});
+ test('it should NOT validate a action_connectors_warnings that is not WarningSchema', () => {
+ type UnsafeCastForTest = Either<
+ Errors,
+ {
+ success: boolean;
+ action_connectors_warnings: string;
+ success_count: number;
+ errors: Array<
+ {
+ id?: string | undefined;
+ rule_id?: string | undefined;
+ } & {
+ error: {
+ status_code: number;
+ message: string;
+ };
+ }
+ >;
+ }
+ >;
+ const payload: Omit & {
+ action_connectors_warnings: string;
+ } = {
+ success: true,
+ success_count: 0,
+ rules_count: 0,
+ errors: [],
+ exceptions_errors: [],
+ exceptions_success: true,
+ exceptions_success_count: 0,
+ action_connectors_success: true,
+ action_connectors_success_count: 0,
+ action_connectors_errors: [],
+ action_connectors_warnings: 'invalid',
+ };
+ const decoded = ImportRulesResponse.decode(payload);
+ const checked = exactCheck(payload, decoded as UnsafeCastForTest);
+ const message = pipe(checked, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([
+ 'Invalid value "invalid" supplied to "action_connectors_warnings"',
+ ]);
+ expect(message.schema).toEqual({});
+ });
});
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
index 9b166f7d726f1..ec207b1e525f1 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
@@ -163,7 +163,7 @@ export const importRulesRoute = (
exceptionsClient,
spaceId: ctx.securitySolution.getSpaceId(),
existingLists: foundReferencedExceptionLists,
- validateRuleActionConnectors: !actionConnectors.length,
+ skipActionConnectorsValidations: !actionConnectors.length,
});
const errorsResp = importRuleResponse.filter((resp) => isBulkError(resp)) as BulkError[];
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts
index 0b2069fef75d0..d8bbc4783eb89 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/create_rules.ts
@@ -19,7 +19,7 @@ export interface CreateRulesOptions
id?: string;
immutable?: boolean;
defaultEnabled?: boolean;
- validateRuleActionConnectors?: boolean;
+ skipActionConnectorsValidations?: boolean;
}
export const createRules = async ({
@@ -28,7 +28,7 @@ export const createRules = async ({
id,
immutable = false,
defaultEnabled = true,
- validateRuleActionConnectors,
+ skipActionConnectorsValidations,
}: CreateRulesOptions): Promise> => {
const internalRule = convertCreateAPIToInternalSchema(params, immutable, defaultEnabled);
const rule = await rulesClient.create({
@@ -36,7 +36,7 @@ export const createRules = async ({
id,
},
data: internalRule,
- validateRuleActionConnectors,
+ skipActionConnectorsValidations,
});
// Mute the rule if it is first created with the explicit no actions
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
index a275de8af6eb7..1eef058fbfa40 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
@@ -61,7 +61,7 @@ export const importRules = async ({
exceptionsClient,
spaceId,
existingLists,
- validateRuleActionConnectors,
+ skipActionConnectorsValidations,
}: {
ruleChunks: PromiseFromStreams[][];
rulesResponseAcc: ImportRuleResponse[];
@@ -72,7 +72,7 @@ export const importRules = async ({
exceptionsClient: ExceptionListClient | undefined;
spaceId: string;
existingLists: Record;
- validateRuleActionConnectors: boolean;
+ skipActionConnectorsValidations: boolean;
}) => {
let importRuleResponse: ImportRuleResponse[] = [...rulesResponseAcc];
@@ -121,7 +121,7 @@ export const importRules = async ({
...parsedRule,
exceptions_list: [...exceptions],
},
- validateRuleActionConnectors,
+ skipActionConnectorsValidations,
});
resolve({
rule_id: parsedRule.rule_id,
From f69890b749909484332ef679fa894f232a1ca9d4 Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Tue, 17 Jan 2023 16:04:09 +0200
Subject: [PATCH 11/40] remove unused var
---
.../public/common/components/import_data_modal/index.tsx | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx b/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx
index 525d6b826ee15..bcf6565f8318b 100644
--- a/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/import_data_modal/index.tsx
@@ -79,10 +79,7 @@ export const ImportDataModalComponent = ({
const [actionConnectorsWarnings, setActionConnectorsWarnings] = useState(
[]
);
- const {
- http,
- application: { navigateToApp },
- } = useKibana().services;
+ const { http } = useKibana().services;
const cleanupAndCloseModal = useCallback(() => {
setIsImporting(false);
From b9f4fb381092f1a6f6ff424e237b30099f6eaabc Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Tue, 17 Jan 2023 16:06:22 +0200
Subject: [PATCH 12/40] optional skipActionConnectorsValidations
---
.../rule_management/logic/import/import_rules_utils.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
index 1eef058fbfa40..d7dda57213545 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts
@@ -72,7 +72,7 @@ export const importRules = async ({
exceptionsClient: ExceptionListClient | undefined;
spaceId: string;
existingLists: Record;
- skipActionConnectorsValidations: boolean;
+ skipActionConnectorsValidations?: boolean;
}) => {
let importRuleResponse: ImportRuleResponse[] = [...rulesResponseAcc];
From 3b6106b9dc9d35cf17c86ae6d1e77499e31570da Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Tue, 17 Jan 2023 16:08:54 +0200
Subject: [PATCH 13/40] fix /rules/import_rules/route.test.ts
---
.../api/rules/import_rules/route.test.ts | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts
index 0483d4abd60f5..201335207754a 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.test.ts
@@ -111,6 +111,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
@@ -152,6 +154,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
@@ -179,6 +183,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
@@ -206,6 +212,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
@@ -230,6 +238,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
});
@@ -256,6 +266,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
@@ -278,6 +290,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
@@ -320,6 +334,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
@@ -352,6 +368,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
@@ -375,6 +393,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
});
@@ -411,6 +431,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
@@ -433,6 +455,8 @@ describe('Import rules route', () => {
exceptions_success_count: 0,
action_connectors_success: true,
action_connectors_success_count: 0,
+ action_connectors_warnings: [],
+ action_connectors_errors: [],
});
});
});
From 2d7c90375a7e211aca8c47575920cfe087847f35 Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Tue, 17 Jan 2023 17:34:20 +0200
Subject: [PATCH 14/40] fix condition
---
.../rule_management/api/rules/import_rules/route.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
index ec207b1e525f1..d44ee84be3881 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts
@@ -163,7 +163,7 @@ export const importRulesRoute = (
exceptionsClient,
spaceId: ctx.securitySolution.getSpaceId(),
existingLists: foundReferencedExceptionLists,
- skipActionConnectorsValidations: !actionConnectors.length,
+ skipActionConnectorsValidations: !!actionConnectors.length,
});
const errorsResp = importRuleResponse.filter((resp) => isBulkError(resp)) as BulkError[];
From 67e800659a1c532890ed15d41dc2f7e92488bfef Mon Sep 17 00:00:00 2001
From: wafaanasr
Date: Wed, 18 Jan 2023 13:55:30 +0200
Subject: [PATCH 15/40] refactor closing Modal
---
.../__snapshots__/index.test.tsx.snap | 276 ++++++++++++++++++
.../import_data_modal/index.test.tsx | 49 ++++
.../components/import_data_modal/index.tsx | 55 ++--
3 files changed, 355 insertions(+), 25 deletions(-)
diff --git a/x-pack/plugins/security_solution/public/common/components/import_data_modal/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/import_data_modal/__snapshots__/index.test.tsx.snap
index 47dd897f71ffb..9b1106043cb6a 100644
--- a/x-pack/plugins/security_solution/public/common/components/import_data_modal/__snapshots__/index.test.tsx.snap
+++ b/x-pack/plugins/security_solution/public/common/components/import_data_modal/__snapshots__/index.test.tsx.snap
@@ -90,6 +90,282 @@ Object {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+