From 3d11c3520c572676a6b73cc26ba4ec726eb949d8 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 18 Jan 2022 20:08:53 -0500 Subject: [PATCH] [Security Solution][Exceptions] Fix export toast text (#123307) (#123326) ### Summary Fix bug on rule export where toaster reports export total as being rule objects + exceptions objects, but should just be rule objects total. Adds cypress test. (cherry picked from commit b2c9f10691837d6411b665715f24ed75db3cc85d) Co-authored-by: Yara Tercero --- .../detection_rules/export_rule.spec.ts | 5 ++++- .../detection_rules/import_rules.spec.ts | 14 ++++++++---- .../cypress/tasks/alerts_detection_rules.ts | 2 +- .../detection_engine/rules/all/helpers.ts | 22 +++++++++++++++---- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts index 18b7b122f0967..1923343f65e61 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts @@ -11,7 +11,7 @@ import { waitForAlertsIndexToBeCreated, waitForAlertsPanelToBeLoaded, } from '../../tasks/alerts'; -import { exportFirstRule } from '../../tasks/alerts_detection_rules'; +import { exportFirstRule, getRulesImportExportToast } from '../../tasks/alerts_detection_rules'; import { createCustomRule } from '../../tasks/api_calls/rules'; import { cleanKibana } from '../../tasks/common'; import { loginAndWaitForPageWithoutDateRange } from '../../tasks/login'; @@ -36,6 +36,9 @@ describe('Export rules', () => { exportFirstRule(); cy.wait('@export').then(({ response }) => { cy.wrap(response?.body).should('eql', expectedExportedRule(this.ruleResponse)); + getRulesImportExportToast([ + 'Successfully exported 1 of 1 rule. Prebuilt rules were excluded from the resulting file.', + ]); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/import_rules.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/import_rules.spec.ts index f12df0bf7f026..f6aeafaa97e7a 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/import_rules.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/import_rules.spec.ts @@ -11,7 +11,7 @@ import { waitForAlertsPanelToBeLoaded, } from '../../tasks/alerts'; import { - getRulesImportToast, + getRulesImportExportToast, importRules, importRulesWithOverwriteAll, } from '../../tasks/alerts_detection_rules'; @@ -35,7 +35,10 @@ describe('Import rules', () => { cy.wait('@import').then(({ response }) => { cy.wrap(response?.statusCode).should('eql', 200); - getRulesImportToast(['Successfully imported 1 rule', 'Successfully imported 2 exceptions.']); + getRulesImportExportToast([ + 'Successfully imported 1 rule', + 'Successfully imported 2 exceptions.', + ]); }); }); @@ -51,7 +54,7 @@ describe('Import rules', () => { cy.wait('@import').then(({ response }) => { cy.wrap(response?.statusCode).should('eql', 200); - getRulesImportToast(['Failed to import 1 rule', 'Failed to import 2 exceptions']); + getRulesImportExportToast(['Failed to import 1 rule', 'Failed to import 2 exceptions']); }); }); @@ -67,7 +70,10 @@ describe('Import rules', () => { cy.wait('@import').then(({ response }) => { cy.wrap(response?.statusCode).should('eql', 200); - getRulesImportToast(['Successfully imported 1 rule', 'Successfully imported 2 exceptions.']); + getRulesImportExportToast([ + 'Successfully imported 1 rule', + 'Successfully imported 2 exceptions.', + ]); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts index e2c3882d10b8c..a000607d0a803 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts @@ -275,7 +275,7 @@ export const importRules = (rulesFile: string) => { cy.get(INPUT_FILE).should('not.exist'); }; -export const getRulesImportToast = (headers: string[]) => { +export const getRulesImportExportToast = (headers: string[]) => { cy.get(TOASTER) .should('exist') .then(($els) => { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts index b03c5ebc84688..99fc72b9d0c2b 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts @@ -6,6 +6,7 @@ */ import { Query } from '@elastic/eui'; +import { ExportRulesDetails } from '../../../../../../common/detection_engine/schemas/response/export_rules_details_schema'; import { BulkRuleResponse, RuleResponseBuckets, @@ -71,16 +72,29 @@ export const getSearchFilters = ({ /** * This function helps to parse NDJSON with exported rules - * and retrieve the number of successfully exported rules. + * and retrieve the metadata of exported rules. * * @param blob a Blob received from an _export endpoint - * @returns Number of exported rules + * @returns Export details */ -export const getExportedRulesCount = async (blob: Blob): Promise => { +export const getExportedRulesDetails = async (blob: Blob): Promise => { const blobContent = await blob.text(); // The Blob content is an NDJSON file, the last line of which contains export details. const exportDetailsJson = blobContent.split('\n').filter(Boolean).slice(-1)[0]; const exportDetails = JSON.parse(exportDetailsJson); - return exportDetails.exported_count; + return exportDetails; +}; + +/** + * This function helps to parse NDJSON with exported rules + * and retrieve the number of successfully exported rules. + * + * @param blob a Blob received from an _export endpoint + * @returns Number of exported rules + */ +export const getExportedRulesCount = async (blob: Blob): Promise => { + const details = await getExportedRulesDetails(blob); + + return details.exported_rules_count; };