From 41b232b1321a8e8bfc54fc057481ce0c4d45d806 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Wed, 3 Feb 2021 22:22:36 -0700 Subject: [PATCH 1/8] Adds a warning banner whenever the user has not updated to the latest alerting migration --- ...ts_detection_callouts_platform_engineer.ts | 84 ++++++++++ ...louts_platform_engineer_need_admin.spec.ts | 93 ++++++++++++ ...alerts_detection_callouts_readonly.spec.ts | 7 + ...ction_callouts_readonly_need_admin.spec.ts | 143 ++++++++++++++++++ ...erts_detection_callouts_t1_analyst.spec.ts | 84 ++++++++++ .../components/callouts/callout.test.tsx | 112 ++++++++++++++ .../common/components/callouts/callout.tsx | 13 +- .../callouts/callout_description.tsx | 25 --- .../callouts/callout_persistent_switcher.tsx | 23 +++ .../components/callouts/callout_types.ts | 4 +- .../common/components/callouts/index.ts | 1 + .../index.test.tsx | 64 ++++++++ .../need_admin_for_update_callout/index.tsx | 35 +++++ .../translations.tsx | 51 +++++++ .../detection_engine/detection_engine.tsx | 2 + .../detection_engine/rules/details/index.tsx | 2 + .../pages/detection_engine/rules/index.tsx | 2 + 17 files changed, 713 insertions(+), 32 deletions(-) create mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts create mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts create mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts create mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/common/components/callouts/callout_description.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/callouts/callout_persistent_switcher.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts new file mode 100644 index 0000000000000..fc1ee8c17a7af --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ROLES } from '../../../common/test'; +import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; +import { newRule } from '../../objects/rule'; +import { PAGE_TITLE } from '../../screens/common/page'; + +import { + loginAndWaitForPageWithoutDateRange, + waitForPageWithoutDateRange, +} from '../../tasks/login'; +import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; +import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; +import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; +import { getCallOut } from '../../tasks/common/callouts'; +import { cleanKibana } from '../../tasks/common'; + +const loadPageAsPlatformEngineerUser = (url: string) => { + waitForPageWithoutDateRange(url, ROLES.platform_engineer); + waitForPageTitleToBeShown(); +}; + +const waitForPageTitleToBeShown = () => { + cy.get(PAGE_TITLE).should('be.visible'); +}; + +describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { + const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; + const ALERTS_CALLOUT = 'read-only-access-to-alerts'; + const RULES_CALLOUT = 'read-only-access-to-rules'; + + before(() => { + cleanKibana(); + loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.platform_engineer); + waitForAlertsIndexToBeCreated(); + }); + + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_URL); + }); + + it('We show no callouts', () => { + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show no callouts', () => { + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createCustomRule(newRule); + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show no callouts', () => { + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts new file mode 100644 index 0000000000000..3645854e67468 --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ROLES } from '../../../common/test'; +import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; +import { newRule } from '../../objects/rule'; +import { PAGE_TITLE } from '../../screens/common/page'; + +import { + loginAndWaitForPageWithoutDateRange, + waitForPageWithoutDateRange, +} from '../../tasks/login'; +import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; +import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; +import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; +import { getCallOut, waitForCallOutToBeShown } from '../../tasks/common/callouts'; +import { cleanKibana } from '../../tasks/common'; + +const loadPageAsPlatformEngineerUser = (url: string) => { + waitForPageWithoutDateRange(url, ROLES.platform_engineer); + waitForPageTitleToBeShown(); +}; + +const waitForPageTitleToBeShown = () => { + cy.get(PAGE_TITLE).should('be.visible'); +}; + +describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { + const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; + const ALERTS_CALLOUT = 'read-only-access-to-alerts'; + const RULES_CALLOUT = 'read-only-access-to-rules'; + + before(() => { + cleanKibana(); + loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.platform_engineer); + waitForAlertsIndexToBeCreated(); + }); + + beforeEach(() => { + // Index mapping is forced to return true as being outdated so that we get the + // need admin callouts being shown. + cy.intercept('GET', '/api/detection_engine/index', { + index_mapping_outdated: true, + name: '.siem-signals-default', + }); + }); + + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_URL); + }); + + it('We show the need admin primary callout', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show 1 primary callout of need admin', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createCustomRule(newRule); + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show 1 primary callout', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly.spec.ts index c88697502ed08..1371f2cc4738e 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly.spec.ts @@ -37,6 +37,7 @@ const waitForPageTitleToBeShown = () => { describe('Detections > Callouts indicating read-only access to resources', () => { const ALERTS_CALLOUT = 'read-only-access-to-alerts'; const RULES_CALLOUT = 'read-only-access-to-rules'; + const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; before(() => { // First, we have to open the app on behalf of a privileged user in order to initialize it. @@ -56,6 +57,7 @@ describe('Detections > Callouts indicating read-only access to resources', () => it('We show one primary callout', () => { waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); }); context('When a user clicks Dismiss on the callout', () => { @@ -75,6 +77,7 @@ describe('Detections > Callouts indicating read-only access to resources', () => it('We show one primary callout', () => { waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); }); context('When a user clicks Dismiss on the callout', () => { @@ -102,24 +105,28 @@ describe('Detections > Callouts indicating read-only access to resources', () => it('We show two primary callouts', () => { waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); }); context('When a user clicks Dismiss on the callouts', () => { it('We hide them and persist the dismissal', () => { waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); dismissCallOut(ALERTS_CALLOUT); reloadPage(); getCallOut(ALERTS_CALLOUT).should('not.exist'); getCallOut(RULES_CALLOUT).should('be.visible'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); dismissCallOut(RULES_CALLOUT); reloadPage(); getCallOut(ALERTS_CALLOUT).should('not.exist'); getCallOut(RULES_CALLOUT).should('not.exist'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts new file mode 100644 index 0000000000000..4406190aaa3f2 --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ROLES } from '../../../common/test'; +import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; +import { newRule } from '../../objects/rule'; +import { PAGE_TITLE } from '../../screens/common/page'; + +import { + login, + loginAndWaitForPageWithoutDateRange, + waitForPageWithoutDateRange, +} from '../../tasks/login'; +import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; +import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; +import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; +import { getCallOut, waitForCallOutToBeShown, dismissCallOut } from '../../tasks/common/callouts'; +import { cleanKibana } from '../../tasks/common'; + +const loadPageAsReadOnlyUser = (url: string) => { + waitForPageWithoutDateRange(url, ROLES.reader); + waitForPageTitleToBeShown(); +}; + +const reloadPage = () => { + cy.reload(); + waitForPageTitleToBeShown(); +}; + +const waitForPageTitleToBeShown = () => { + cy.get(PAGE_TITLE).should('be.visible'); +}; + +describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { + const ALERTS_CALLOUT = 'read-only-access-to-alerts'; + const RULES_CALLOUT = 'read-only-access-to-rules'; + const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; + + before(() => { + // First, we have to open the app on behalf of a privileged user in order to initialize it. + // Otherwise the app will be disabled and show a "welcome"-like page. + cleanKibana(); + loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.platform_engineer); + waitForAlertsIndexToBeCreated(); + + // After that we can login as a read-only user. + login(ROLES.reader); + }); + + beforeEach(() => { + // Index mapping is forced to return true as being outdated so that we get the + // need admin callouts being shown. + cy.intercept('GET', '/api/detection_engine/index', { + index_mapping_outdated: true, + name: '.siem-signals-default', + }); + }); + + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsReadOnlyUser(DETECTIONS_URL); + }); + + it('We show the alerts and admin primary callout', () => { + waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + + context('When a user clicks Dismiss on the callout', () => { + it('We hide it and persist the dismissal but still show the admin callout', () => { + waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); + dismissCallOut(ALERTS_CALLOUT); + reloadPage(); + getCallOut(ALERTS_CALLOUT).should('not.exist'); + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsReadOnlyUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show two primary callouts of the alert and the admin', () => { + waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + + context('When a user clicks Dismiss on the callout', () => { + it('We hide it and persist the dismissal', () => { + waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); + dismissCallOut(RULES_CALLOUT); + reloadPage(); + getCallOut(RULES_CALLOUT).should('not.exist'); + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createCustomRule(newRule); + loadPageAsReadOnlyUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show three primary callouts', () => { + waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); + waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + + context('When a user clicks Dismiss on the callouts', () => { + it('We hide them and persist the dismissal', () => { + waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); + waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + + dismissCallOut(ALERTS_CALLOUT); + reloadPage(); + + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('be.visible'); + + dismissCallOut(RULES_CALLOUT); + reloadPage(); + + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts new file mode 100644 index 0000000000000..9892e3a27fb3a --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ROLES } from '../../../common/test'; +import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; +import { newRule } from '../../objects/rule'; +import { PAGE_TITLE } from '../../screens/common/page'; + +import { + loginAndWaitForPageWithoutDateRange, + waitForPageWithoutDateRange, +} from '../../tasks/login'; +import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; +import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; +import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; +import { getCallOut } from '../../tasks/common/callouts'; +import { cleanKibana } from '../../tasks/common'; + +const loadPageAsPlatformEngineerUser = (url: string) => { + waitForPageWithoutDateRange(url, ROLES.t1_analyst); + waitForPageTitleToBeShown(); +}; + +const waitForPageTitleToBeShown = () => { + cy.get(PAGE_TITLE).should('be.visible'); +}; + +describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { + const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; + const ALERTS_CALLOUT = 'read-only-access-to-alerts'; + const RULES_CALLOUT = 'read-only-access-to-rules'; + + before(() => { + cleanKibana(); + loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.t1_analyst); + waitForAlertsIndexToBeCreated(); + }); + + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_URL); + }); + + it('We show no callouts', () => { + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show no callouts', () => { + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createCustomRule(newRule); + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show no callouts', () => { + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx b/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx new file mode 100644 index 0000000000000..8b4c4e6d5c800 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { mount } from 'enzyme'; +import React from 'react'; +import { CallOut, CallOutMessage } from '.'; +import { TestProviders } from '../../mock'; + +describe('callout', () => { + let message: CallOutMessage = { + type: 'primary', + id: 'some-id', + title: 'title', + description: <>{'some description'}, + }; + + beforeEach(() => { + message = { + type: 'primary', + id: 'some-id', + title: 'title', + description: <>{'some description'}, + }; + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + test('renders the callout data-test-subj from the given id', () => { + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-some-id"]')).toEqual(true); + }); + + test('renders the callout dismiss button by default', () => { + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-dismiss-btn"]')).toEqual(true); + }); + + test('renders the callout dismiss button if given an explicit true to enable it', () => { + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-dismiss-btn"]')).toEqual(true); + }); + + test('Does NOT render the callout dismiss button if given an explicit false to disable it', () => { + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-dismiss-btn"]')).toEqual(false); + }); + + test('onDismiss callback operates when dismiss button is clicked', () => { + const onDismiss = jest.fn(); + const wrapper = mount( + + + + ); + wrapper.find('[data-test-subj="callout-dismiss-btn"]').first().simulate('click'); + expect(onDismiss).toBeCalledWith(message); + }); + + test('dismissButtonText can be set', () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="callout-dismiss-btn"]').first().text()).toEqual( + 'Some other text' + ); + }); + + test('a default icon type of "iInCircle" will be chosen if no iconType is set and the message type is "primary"', () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="callout-some-id"]').first().prop('iconType')).toEqual( + 'iInCircle' + ); + }); + + test('icon type can be changed from the type within the message', () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="callout-some-id"]').first().prop('iconType')).toEqual( + 'something_else' + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/callouts/callout.tsx b/x-pack/plugins/security_solution/public/common/components/callouts/callout.tsx index 1eb048f7dd24e..1af59f9ef64ed 100644 --- a/x-pack/plugins/security_solution/public/common/components/callouts/callout.tsx +++ b/x-pack/plugins/security_solution/public/common/components/callouts/callout.tsx @@ -8,7 +8,6 @@ import React, { FC, memo } from 'react'; import { EuiCallOut } from '@elastic/eui'; import { CallOutType, CallOutMessage } from './callout_types'; -import { CallOutDescription } from './callout_description'; import { CallOutDismissButton } from './callout_dismiss_button'; export interface CallOutProps { @@ -16,6 +15,7 @@ export interface CallOutProps { iconType?: string; dismissButtonText?: string; onDismiss?: (message: CallOutMessage) => void; + showDismissButton?: boolean; } const CallOutComponent: FC = ({ @@ -23,8 +23,9 @@ const CallOutComponent: FC = ({ iconType, dismissButtonText, onDismiss, + showDismissButton = true, }) => { - const { type, id, title } = message; + const { type, id, title, description } = message; const finalIconType = iconType ?? getDefaultIconType(type); return ( @@ -35,8 +36,10 @@ const CallOutComponent: FC = ({ data-test-subj={`callout-${id}`} data-test-messages={`[${id}]`} > - - + {description} + {showDismissButton && ( + + )} ); }; @@ -51,8 +54,6 @@ const getDefaultIconType = (type: CallOutType): string => { return 'help'; case 'danger': return 'alert'; - default: - return ''; } }; diff --git a/x-pack/plugins/security_solution/public/common/components/callouts/callout_description.tsx b/x-pack/plugins/security_solution/public/common/components/callouts/callout_description.tsx deleted file mode 100644 index d8b419f02d631..0000000000000 --- a/x-pack/plugins/security_solution/public/common/components/callouts/callout_description.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { FC } from 'react'; -import { EuiDescriptionList } from '@elastic/eui'; -import { CallOutMessage } from './callout_types'; - -export interface CallOutDescriptionProps { - messages: CallOutMessage | CallOutMessage[]; -} - -export const CallOutDescription: FC = ({ messages }) => { - if (!Array.isArray(messages)) { - return messages.description; - } - - if (messages.length < 1) { - return null; - } - - return ; -}; diff --git a/x-pack/plugins/security_solution/public/common/components/callouts/callout_persistent_switcher.tsx b/x-pack/plugins/security_solution/public/common/components/callouts/callout_persistent_switcher.tsx new file mode 100644 index 0000000000000..072e9ba5b288a --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/callouts/callout_persistent_switcher.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC, memo } from 'react'; + +import { CallOutMessage } from './callout_types'; +import { CallOut } from './callout'; + +export interface CallOutPersistentSwitcherProps { + condition: boolean; + message: CallOutMessage; +} + +const CallOutPersistentSwitcherComponent: FC = ({ + condition, + message, +}): JSX.Element | null => + condition ? : null; + +export const CallOutPersistentSwitcher = memo(CallOutPersistentSwitcherComponent); diff --git a/x-pack/plugins/security_solution/public/common/components/callouts/callout_types.ts b/x-pack/plugins/security_solution/public/common/components/callouts/callout_types.ts index c72fe487af99b..1768038a92e30 100644 --- a/x-pack/plugins/security_solution/public/common/components/callouts/callout_types.ts +++ b/x-pack/plugins/security_solution/public/common/components/callouts/callout_types.ts @@ -4,7 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -export type CallOutType = 'primary' | 'success' | 'warning' | 'danger'; +import { EuiCallOutProps } from '@elastic/eui'; + +export type CallOutType = NonNullable; export interface CallOutMessage { type: CallOutType; diff --git a/x-pack/plugins/security_solution/public/common/components/callouts/index.ts b/x-pack/plugins/security_solution/public/common/components/callouts/index.ts index 8b636ce1bfae9..a3cd2fb7c1619 100644 --- a/x-pack/plugins/security_solution/public/common/components/callouts/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/callouts/index.ts @@ -7,3 +7,4 @@ export * from './callout_switcher'; export * from './callout_types'; export * from './callout'; +export * from './callout_persistent_switcher'; diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx new file mode 100644 index 0000000000000..1cf1d1bd53f0e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { mount } from 'enzyme'; +import React from 'react'; +import { TestProviders } from '../../../../common/mock'; +import { NeedAdminForUpdateRulesCallOut } from '.'; +import * as userInfo from '../../user_info'; + +describe('need_admin_for_update_callout', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + test('renders when signalIndexMappingOutdated is true', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: true }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual(true); + }); + + test('Does not render a button as this is always persistent', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: true }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-dismiss-btn"]')).toEqual(false); + }); + + test('Does NOT render when signalIndexMappingOutdated is false', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: false }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual(false); + }); + + test('Does NOT render when signalIndexMappingOutdated is null', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: null }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual(false); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx new file mode 100644 index 0000000000000..86cd8434cebe6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { memo } from 'react'; +import { CallOutMessage, CallOutPersistentSwitcher } from '../../../../common/components/callouts'; +import { useUserData } from '../../user_info'; + +import * as i18n from './translations'; + +const needAdminForUpdateRulesMessage: CallOutMessage = { + type: 'primary', + id: 'need-admin-for-update-rules', + title: i18n.NEED_ADMIN_CALLOUT_TITLE, + description: i18n.needAdminForUpdateCallOutBody(), +}; + +/** + * Callout component that lets the user know that an administrator is needed for performing + * and auto-update of signals or not. + */ +const NeedAdminForUpdateCallOutComponent = (): JSX.Element => { + const [{ signalIndexMappingOutdated }] = useUserData(); + + return ( + + ); +}; + +export const NeedAdminForUpdateRulesCallOut = memo(NeedAdminForUpdateCallOutComponent); diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx new file mode 100644 index 0000000000000..9dd0fe30d9282 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + SecuritySolutionRequirementsLink, + DetectionsRequirementsLink, +} from '../../../../common/components/links_to_docs'; + +export const NEED_ADMIN_CALLOUT_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.needAdminForUpdateCallOutBody.messageTitle', + { + defaultMessage: 'Administration permissions required for alert migration', + } +); + +/** + * Returns the formatted message of the call out body as a JSX Element with both the message + * and two documentation links. + */ +export const needAdminForUpdateCallOutBody = (): JSX.Element => ( + + +

+ ), + docs: ( +
    +
  • + +
  • +
  • + +
  • +
+ ), + }} + /> +); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx index e6cf858b7fb5d..8202b52366b09 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx @@ -52,6 +52,7 @@ import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import { buildShowBuildingBlockFilter } from '../../components/alerts_table/default_config'; import { useSourcererScope } from '../../../common/containers/sourcerer'; import { SourcererScopeName } from '../../../common/store/sourcerer/model'; +import { NeedAdminForUpdateRulesCallOut } from '../../components/callouts/need_admin_for_update_callout'; /** * Need a 100% height here to account for the graph/analyze tool, which sets no explicit height parameters, but fills the available space. @@ -192,6 +193,7 @@ const DetectionEnginePageComponent = () => { <> {hasEncryptionKey != null && !hasEncryptionKey && } + {indicesExist ? ( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index 78c1732f30ef4..c61a4002ad3d7 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -102,6 +102,7 @@ import * as detectionI18n from '../../translations'; import * as ruleI18n from '../translations'; import * as i18n from './translations'; import { isTab } from '../../../../../common/components/accessibility/helpers'; +import { NeedAdminForUpdateRulesCallOut } from '../../../../components/callouts/need_admin_for_update_callout'; /** * Need a 100% height here to account for the graph/analyze tool, which sets no explicit height parameters, but fills the available space. @@ -467,6 +468,7 @@ const RuleDetailsPageComponent = () => { return ( <> + {indicesExist ? ( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx index 9423604e546e9..a7a08dee670ff 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx @@ -34,6 +34,7 @@ import * as i18n from './translations'; import { SecurityPageName } from '../../../../app/types'; import { LinkButton } from '../../../../common/components/links'; import { useFormatUrl } from '../../../../common/components/link_to'; +import { NeedAdminForUpdateRulesCallOut } from '../../../components/callouts/need_admin_for_update_callout'; type Func = () => Promise; @@ -157,6 +158,7 @@ const RulesPageComponent: React.FC = () => { return ( <> + Date: Wed, 3 Feb 2021 23:00:57 -0700 Subject: [PATCH 2/8] Updated license headers --- .../alerts_detection_callouts_platform_engineer.ts | 5 +++-- ..._detection_callouts_platform_engineer_need_admin.spec.ts | 5 +++-- .../alerts_detection_callouts_readonly_need_admin.spec.ts | 5 +++-- .../alerts_detection_callouts_t1_analyst.spec.ts | 5 +++-- .../public/common/components/callouts/callout.test.tsx | 5 +++-- .../components/callouts/callout_persistent_switcher.tsx | 5 +++-- .../callouts/need_admin_for_update_callout/index.test.tsx | 6 ++++-- .../callouts/need_admin_for_update_callout/index.tsx | 5 +++-- .../callouts/need_admin_for_update_callout/translations.tsx | 5 +++-- 9 files changed, 28 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts index fc1ee8c17a7af..eafb1aefba1fe 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts @@ -1,7 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * 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 { ROLES } from '../../../common/test'; diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts index 3645854e67468..d8bf78cbd2017 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts @@ -1,7 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * 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 { ROLES } from '../../../common/test'; diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts index 4406190aaa3f2..6fedfb942965d 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts @@ -1,7 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * 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 { ROLES } from '../../../common/test'; diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts index 9892e3a27fb3a..b558405185f7e 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts @@ -1,7 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * 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 { ROLES } from '../../../common/test'; diff --git a/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx b/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx index 8b4c4e6d5c800..d6a4b8c8afa1a 100644 --- a/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx @@ -1,7 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * 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 { mount } from 'enzyme'; diff --git a/x-pack/plugins/security_solution/public/common/components/callouts/callout_persistent_switcher.tsx b/x-pack/plugins/security_solution/public/common/components/callouts/callout_persistent_switcher.tsx index 072e9ba5b288a..5b67410bb904a 100644 --- a/x-pack/plugins/security_solution/public/common/components/callouts/callout_persistent_switcher.tsx +++ b/x-pack/plugins/security_solution/public/common/components/callouts/callout_persistent_switcher.tsx @@ -1,7 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * 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 React, { FC, memo } from 'react'; diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx index 1cf1d1bd53f0e..364320859676b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx @@ -1,8 +1,10 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * 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 { mount } from 'enzyme'; import React from 'react'; import { TestProviders } from '../../../../common/mock'; diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx index 86cd8434cebe6..83f800529a8f1 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx @@ -1,7 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * 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 React, { memo } from 'react'; diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx index 9dd0fe30d9282..a2fd45e933c14 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx @@ -1,7 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * 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 React from 'react'; From b715ed825b3e065c33ef1f4a3f971953e39e83bc Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Wed, 3 Feb 2021 23:11:58 -0700 Subject: [PATCH 3/8] Updated some wording --- ...erts_detection_callouts_platform_engineer_need_admin.spec.ts | 2 +- .../alerts_detection_callouts_readonly_need_admin.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts index d8bf78cbd2017..51f4ce24cee66 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts @@ -41,7 +41,7 @@ describe('Detections > Need Admin Callouts indicating an admin is needed to migr }); beforeEach(() => { - // Index mapping is forced to return true as being outdated so that we get the + // Index mapping outdated is forced to return true as being outdated so that we get the // need admin callouts being shown. cy.intercept('GET', '/api/detection_engine/index', { index_mapping_outdated: true, diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts index 6fedfb942965d..ae769c7228537 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts @@ -52,7 +52,7 @@ describe('Detections > Need Admin Callouts indicating an admin is needed to migr }); beforeEach(() => { - // Index mapping is forced to return true as being outdated so that we get the + // Index mapping outdated is forced to return true as being outdated so that we get the // need admin callouts being shown. cy.intercept('GET', '/api/detection_engine/index', { index_mapping_outdated: true, From 03404135874bb1ad4393bb86f200b0cd287b5554 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Fri, 5 Feb 2021 13:45:45 -0700 Subject: [PATCH 4/8] Fixed it so that the warning banner does not show up whenever you have the priviledges to migrate the index in which case should be happening --- ...louts_platform_engineer_need_admin.spec.ts | 8 +- ...on_callouts_soc_manager_need_admin.spec.ts | 94 ++++++++ .../index.test.tsx | 211 ++++++++++++++---- .../need_admin_for_update_callout/index.tsx | 17 +- 4 files changed, 282 insertions(+), 48 deletions(-) create mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_soc_manager_need_admin.spec.ts diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts index 51f4ce24cee66..8320944f665f3 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts @@ -17,7 +17,7 @@ import { import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; -import { getCallOut, waitForCallOutToBeShown } from '../../tasks/common/callouts'; +import { getCallOut } from '../../tasks/common/callouts'; import { cleanKibana } from '../../tasks/common'; const loadPageAsPlatformEngineerUser = (url: string) => { @@ -55,9 +55,9 @@ describe('Detections > Need Admin Callouts indicating an admin is needed to migr }); it('We show the need admin primary callout', () => { - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); getCallOut(ALERTS_CALLOUT).should('not.exist'); getCallOut(RULES_CALLOUT).should('not.exist'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); }); }); @@ -67,9 +67,9 @@ describe('Detections > Need Admin Callouts indicating an admin is needed to migr }); it('We show 1 primary callout of need admin', () => { - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); getCallOut(ALERTS_CALLOUT).should('not.exist'); getCallOut(RULES_CALLOUT).should('not.exist'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); }); }); @@ -86,9 +86,9 @@ describe('Detections > Need Admin Callouts indicating an admin is needed to migr }); it('We show 1 primary callout', () => { - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); getCallOut(ALERTS_CALLOUT).should('not.exist'); getCallOut(RULES_CALLOUT).should('not.exist'); + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_soc_manager_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_soc_manager_need_admin.spec.ts new file mode 100644 index 0000000000000..cb4658f524777 --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_soc_manager_need_admin.spec.ts @@ -0,0 +1,94 @@ +/* + * 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 { ROLES } from '../../../common/test'; +import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; +import { newRule } from '../../objects/rule'; +import { PAGE_TITLE } from '../../screens/common/page'; + +import { + loginAndWaitForPageWithoutDateRange, + waitForPageWithoutDateRange, +} from '../../tasks/login'; +import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; +import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; +import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; +import { getCallOut, waitForCallOutToBeShown } from '../../tasks/common/callouts'; +import { cleanKibana } from '../../tasks/common'; + +const loadPageAsPlatformEngineerUser = (url: string) => { + waitForPageWithoutDateRange(url, ROLES.soc_manager); + waitForPageTitleToBeShown(); +}; + +const waitForPageTitleToBeShown = () => { + cy.get(PAGE_TITLE).should('be.visible'); +}; + +describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { + const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; + const ALERTS_CALLOUT = 'read-only-access-to-alerts'; + const RULES_CALLOUT = 'read-only-access-to-rules'; + + before(() => { + cleanKibana(); + loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.soc_manager); + waitForAlertsIndexToBeCreated(); + }); + + beforeEach(() => { + // Index mapping outdated is forced to return true as being outdated so that we get the + // need admin callouts being shown. + cy.intercept('GET', '/api/detection_engine/index', { + index_mapping_outdated: true, + name: '.siem-signals-default', + }); + }); + + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_URL); + }); + + it('We show the need admin primary callout', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show 1 primary callout of need admin', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createCustomRule(newRule); + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show 1 primary callout', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx index 364320859676b..8798249ca5682 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx @@ -16,51 +16,180 @@ describe('need_admin_for_update_callout', () => { jest.resetAllMocks(); }); - test('renders when signalIndexMappingOutdated is true', () => { - jest - .spyOn(userInfo, 'useUserData') - .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: true }])); - const wrapper = mount( - - - - ); - expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual(true); - }); + describe('hasIndexManage is "null"', () => { + const hasIndexManage = null; + test('renders when "signalIndexMappingOutdated" is true', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation( + jest.fn().mockReturnValue([{ signalIndexMappingOutdated: true, hasIndexManage }]) + ); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual( + true + ); + }); + + test('Does not render a button as this is always persistent', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: true }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-dismiss-btn"]')).toEqual(false); + }); + + test('Does NOT render when signalIndexMappingOutdated is false', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: false }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual( + false + ); + }); - test('Does not render a button as this is always persistent', () => { - jest - .spyOn(userInfo, 'useUserData') - .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: true }])); - const wrapper = mount( - - - - ); - expect(wrapper.exists('[data-test-subj="callout-dismiss-btn"]')).toEqual(false); + test('Does NOT render when signalIndexMappingOutdated is null', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: null }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual( + false + ); + }); }); - test('Does NOT render when signalIndexMappingOutdated is false', () => { - jest - .spyOn(userInfo, 'useUserData') - .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: false }])); - const wrapper = mount( - - - - ); - expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual(false); + describe('hasIndexManage is "false"', () => { + const hasIndexManage = false; + test('renders when "signalIndexMappingOutdated" is true', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation( + jest.fn().mockReturnValue([{ signalIndexMappingOutdated: true, hasIndexManage }]) + ); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual( + true + ); + }); + + test('Does not render a button as this is always persistent', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: true }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-dismiss-btn"]')).toEqual(false); + }); + + test('Does NOT render when signalIndexMappingOutdated is false', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: false }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual( + false + ); + }); + + test('Does NOT render when signalIndexMappingOutdated is null', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: null }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual( + false + ); + }); }); - test('Does NOT render when signalIndexMappingOutdated is null', () => { - jest - .spyOn(userInfo, 'useUserData') - .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: null }])); - const wrapper = mount( - - - - ); - expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual(false); + describe('hasIndexManage is "true"', () => { + const hasIndexManage = true; + test('Does not render when "signalIndexMappingOutdated" is true', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation( + jest.fn().mockReturnValue([{ signalIndexMappingOutdated: true, hasIndexManage }]) + ); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual( + false + ); + }); + + test('Does not render a button as this is always persistent', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: true }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-dismiss-btn"]')).toEqual(false); + }); + + test('Does NOT render when signalIndexMappingOutdated is false', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: false }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual( + false + ); + }); + + test('Does NOT render when signalIndexMappingOutdated is null', () => { + jest + .spyOn(userInfo, 'useUserData') + .mockImplementation(jest.fn().mockReturnValue([{ signalIndexMappingOutdated: null }])); + const wrapper = mount( + + + + ); + expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual( + false + ); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx index 83f800529a8f1..ea31c0c24ef08 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx @@ -20,14 +20,25 @@ const needAdminForUpdateRulesMessage: CallOutMessage = { /** * Callout component that lets the user know that an administrator is needed for performing - * and auto-update of signals or not. + * and auto-update of signals or not. For this component to render the user must: + * - Have the permissions to be able to read "signalIndexMappingOutdated" and that condition is "true" + * - Have the permissions to be able to read "hasIndexManage" and that condition is "false" + * + * If the user has the permissions to see that signalIndexMappingOutdated is true and that + * hasIndexManage is also true, then the user should be performing the update on the page which is + * why we do not show it for that condition. */ const NeedAdminForUpdateCallOutComponent = (): JSX.Element => { - const [{ signalIndexMappingOutdated }] = useUserData(); + const [{ signalIndexMappingOutdated, hasIndexManage }] = useUserData(); + + const signalIndexMappingIsOutdated = + signalIndexMappingOutdated != null && signalIndexMappingOutdated; + + const userHasIndexManage = hasIndexManage != null && hasIndexManage; return ( ); From 68b8cd17bfaee3a57cc276115f29bd43e7153667 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Fri, 5 Feb 2021 14:03:00 -0700 Subject: [PATCH 5/8] Fixed wording by removing the dash in auto-migrate --- .../callouts/need_admin_for_update_callout/translations.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx index a2fd45e933c14..791093788b8e1 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/translations.tsx @@ -33,7 +33,7 @@ export const needAdminForUpdateCallOutBody = (): JSX.Element => (

), From e2be038a5c597f5b10c201c310c646aaeb8429cb Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Mon, 8 Feb 2021 21:55:25 -0700 Subject: [PATCH 6/8] Fixes from PR review --- .../public/common/components/callouts/callout.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x-pack/plugins/security_solution/public/common/components/callouts/callout.tsx b/x-pack/plugins/security_solution/public/common/components/callouts/callout.tsx index 997589d548e93..2077e421c427a 100644 --- a/x-pack/plugins/security_solution/public/common/components/callouts/callout.tsx +++ b/x-pack/plugins/security_solution/public/common/components/callouts/callout.tsx @@ -8,6 +8,7 @@ import React, { FC, memo } from 'react'; import { EuiCallOut } from '@elastic/eui'; +import { assertUnreachable } from '../../../../common/utility_types'; import { CallOutType, CallOutMessage } from './callout_types'; import { CallOutDismissButton } from './callout_dismiss_button'; @@ -55,6 +56,8 @@ const getDefaultIconType = (type: CallOutType): string => { return 'help'; case 'danger': return 'alert'; + default: + return assertUnreachable(type); } }; From dc62dc7dcb09f57b18ce1659cb036cd0eebdc380 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Tue, 9 Feb 2021 14:42:42 -0700 Subject: [PATCH 7/8] Updates from PR review --- .../public/common/components/callouts/callout.test.tsx | 3 ++- .../need_admin_for_update_callout/index.test.tsx | 6 +++--- .../callouts/need_admin_for_update_callout/index.tsx | 9 +++++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx b/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx index d6a4b8c8afa1a..f908a79361d0a 100644 --- a/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/callouts/callout.test.tsx @@ -7,8 +7,9 @@ import { mount } from 'enzyme'; import React from 'react'; -import { CallOut, CallOutMessage } from '.'; import { TestProviders } from '../../mock'; +import { CallOut } from './callout'; +import { CallOutMessage } from './callout_types'; describe('callout', () => { let message: CallOutMessage = { diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx index 8798249ca5682..66b2bae98c1ae 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.test.tsx @@ -7,8 +7,8 @@ import { mount } from 'enzyme'; import React from 'react'; +import { NeedAdminForUpdateRulesCallOut } from './index'; import { TestProviders } from '../../../../common/mock'; -import { NeedAdminForUpdateRulesCallOut } from '.'; import * as userInfo from '../../user_info'; describe('need_admin_for_update_callout', () => { @@ -18,7 +18,7 @@ describe('need_admin_for_update_callout', () => { describe('hasIndexManage is "null"', () => { const hasIndexManage = null; - test('renders when "signalIndexMappingOutdated" is true', () => { + test('Does NOT render when "signalIndexMappingOutdated" is true', () => { jest .spyOn(userInfo, 'useUserData') .mockImplementation( @@ -30,7 +30,7 @@ describe('need_admin_for_update_callout', () => { ); expect(wrapper.exists('[data-test-subj="callout-need-admin-for-update-rules"]')).toEqual( - true + false ); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx index ea31c0c24ef08..fd0be8e002193 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/need_admin_for_update_callout/index.tsx @@ -24,6 +24,11 @@ const needAdminForUpdateRulesMessage: CallOutMessage = { * - Have the permissions to be able to read "signalIndexMappingOutdated" and that condition is "true" * - Have the permissions to be able to read "hasIndexManage" and that condition is "false" * + * Some users do not have sufficient privileges to be able to determine if "signalIndexMappingOutdated" + * is outdated or not. Same could apply to "hasIndexManage". When users do not have enough permissions + * to determine if "signalIndexMappingOutdated" is true or false, the permissions system returns a "null" + * instead. + * * If the user has the permissions to see that signalIndexMappingOutdated is true and that * hasIndexManage is also true, then the user should be performing the update on the page which is * why we do not show it for that condition. @@ -34,11 +39,11 @@ const NeedAdminForUpdateCallOutComponent = (): JSX.Element => { const signalIndexMappingIsOutdated = signalIndexMappingOutdated != null && signalIndexMappingOutdated; - const userHasIndexManage = hasIndexManage != null && hasIndexManage; + const userDoesntHaveIndexManage = hasIndexManage != null && !hasIndexManage; return ( ); From efec9c301a319804c3bd48fe31f590dd2115a851 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Tue, 16 Feb 2021 18:39:32 -0700 Subject: [PATCH 8/8] Fixes tests from PR feedback --- .../security_solution/common/utility_types.ts | 6 + ..._detection_callouts_index_outdated.spec.ts | 196 ++++++++++++++++++ ...ts_detection_callouts_platform_engineer.ts | 85 -------- ...louts_platform_engineer_need_admin.spec.ts | 94 --------- ...alerts_detection_callouts_readonly.spec.ts | 154 +++++++++----- ...ction_callouts_readonly_need_admin.spec.ts | 144 ------------- ...on_callouts_soc_manager_need_admin.spec.ts | 94 --------- ...erts_detection_callouts_t1_analyst.spec.ts | 85 -------- .../cypress/tasks/common/callouts.ts | 6 +- .../factory/hosts/all/query.all_hosts.dsl.ts | 2 +- 10 files changed, 303 insertions(+), 563 deletions(-) create mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_index_outdated.spec.ts delete mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts delete mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts delete mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts delete mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_soc_manager_need_admin.spec.ts delete mode 100644 x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts diff --git a/x-pack/plugins/security_solution/common/utility_types.ts b/x-pack/plugins/security_solution/common/utility_types.ts index 3c13e6af837bc..498b18dccaca5 100644 --- a/x-pack/plugins/security_solution/common/utility_types.ts +++ b/x-pack/plugins/security_solution/common/utility_types.ts @@ -36,6 +36,12 @@ export const stringEnum = (enumObj: T, enumName = 'enum') => * * Optionally you can avoid the use of this by using early returns and TypeScript will clear your type checking without complaints * but there are situations and times where this function might still be needed. + * + * If you see an error, DO NOT cast "as never" such as: + * assertUnreachable(x as never) // BUG IN YOUR CODE NOW AND IT WILL THROW DURING RUNTIME + * If you see code like that remove it, as that deactivates the intent of this utility. + * If you need to do that, then you should remove assertUnreachable from your code and + * use a default at the end of the switch instead. * @param x Unreachable field * @param message Message of error thrown */ diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_index_outdated.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_index_outdated.spec.ts new file mode 100644 index 0000000000000..1c6c604b84fbb --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_index_outdated.spec.ts @@ -0,0 +1,196 @@ +/* + * 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 { ROLES } from '../../../common/test'; +import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; +import { newRule } from '../../objects/rule'; +import { PAGE_TITLE } from '../../screens/common/page'; + +import { + login, + loginAndWaitForPageWithoutDateRange, + waitForPageWithoutDateRange, +} from '../../tasks/login'; +import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; +import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; +import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; +import { getCallOut, waitForCallOutToBeShown } from '../../tasks/common/callouts'; +import { cleanKibana } from '../../tasks/common'; + +const loadPageAsPlatformEngineerUser = (url: string) => { + waitForPageWithoutDateRange(url, ROLES.soc_manager); + waitForPageTitleToBeShown(); +}; + +const waitForPageTitleToBeShown = () => { + cy.get(PAGE_TITLE).should('be.visible'); +}; + +describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { + const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; + + before(() => { + // First, we have to open the app on behalf of a privileged user in order to initialize it. + // Otherwise the app will be disabled and show a "welcome"-like page. + cleanKibana(); + loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.platform_engineer); + waitForAlertsIndexToBeCreated(); + + // After that we can login as a soc manager. + login(ROLES.soc_manager); + }); + + context( + 'The users index_mapping_outdated is "true" and their admin callouts should show up', + () => { + beforeEach(() => { + // Index mapping outdated is forced to return true as being outdated so that we get the + // need admin callouts being shown. + cy.intercept('GET', '/api/detection_engine/index', { + index_mapping_outdated: true, + name: '.siem-signals-default', + }); + }); + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_URL); + }); + + it('We show the need admin primary callout', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show 1 primary callout of need admin', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createCustomRule(newRule); + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show 1 primary callout', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + }); + } + ); + + context( + 'The users index_mapping_outdated is "false" and their admin callouts should not show up ', + () => { + beforeEach(() => { + // Index mapping outdated is forced to return true as being outdated so that we get the + // need admin callouts being shown. + cy.intercept('GET', '/api/detection_engine/index', { + index_mapping_outdated: false, + name: '.siem-signals-default', + }); + }); + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_URL); + }); + + it('We show the need admin primary callout', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show 1 primary callout of need admin', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createCustomRule(newRule); + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show 1 primary callout', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + } + ); + + context( + 'The users index_mapping_outdated is "null" and their admin callouts should not show up ', + () => { + beforeEach(() => { + // Index mapping outdated is forced to return true as being outdated so that we get the + // need admin callouts being shown. + cy.intercept('GET', '/api/detection_engine/index', { + index_mapping_outdated: null, + name: '.siem-signals-default', + }); + }); + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_URL); + }); + + it('We show the need admin primary callout', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show 1 primary callout of need admin', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createCustomRule(newRule); + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show 1 primary callout', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + } + ); +}); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts deleted file mode 100644 index eafb1aefba1fe..0000000000000 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ROLES } from '../../../common/test'; -import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; -import { newRule } from '../../objects/rule'; -import { PAGE_TITLE } from '../../screens/common/page'; - -import { - loginAndWaitForPageWithoutDateRange, - waitForPageWithoutDateRange, -} from '../../tasks/login'; -import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; -import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; -import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; -import { getCallOut } from '../../tasks/common/callouts'; -import { cleanKibana } from '../../tasks/common'; - -const loadPageAsPlatformEngineerUser = (url: string) => { - waitForPageWithoutDateRange(url, ROLES.platform_engineer); - waitForPageTitleToBeShown(); -}; - -const waitForPageTitleToBeShown = () => { - cy.get(PAGE_TITLE).should('be.visible'); -}; - -describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { - const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; - const ALERTS_CALLOUT = 'read-only-access-to-alerts'; - const RULES_CALLOUT = 'read-only-access-to-rules'; - - before(() => { - cleanKibana(); - loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.platform_engineer); - waitForAlertsIndexToBeCreated(); - }); - - context('On Detections home page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_URL); - }); - - it('We show no callouts', () => { - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - - context('On Rules Management page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - }); - - it('We show no callouts', () => { - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - - context('On Rule Details page', () => { - beforeEach(() => { - createCustomRule(newRule); - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - waitForPageTitleToBeShown(); - goToRuleDetails(); - }); - - afterEach(() => { - deleteCustomRule(); - }); - - it('We show no callouts', () => { - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts deleted file mode 100644 index 8320944f665f3..0000000000000 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_platform_engineer_need_admin.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ROLES } from '../../../common/test'; -import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; -import { newRule } from '../../objects/rule'; -import { PAGE_TITLE } from '../../screens/common/page'; - -import { - loginAndWaitForPageWithoutDateRange, - waitForPageWithoutDateRange, -} from '../../tasks/login'; -import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; -import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; -import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; -import { getCallOut } from '../../tasks/common/callouts'; -import { cleanKibana } from '../../tasks/common'; - -const loadPageAsPlatformEngineerUser = (url: string) => { - waitForPageWithoutDateRange(url, ROLES.platform_engineer); - waitForPageTitleToBeShown(); -}; - -const waitForPageTitleToBeShown = () => { - cy.get(PAGE_TITLE).should('be.visible'); -}; - -describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { - const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; - const ALERTS_CALLOUT = 'read-only-access-to-alerts'; - const RULES_CALLOUT = 'read-only-access-to-rules'; - - before(() => { - cleanKibana(); - loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.platform_engineer); - waitForAlertsIndexToBeCreated(); - }); - - beforeEach(() => { - // Index mapping outdated is forced to return true as being outdated so that we get the - // need admin callouts being shown. - cy.intercept('GET', '/api/detection_engine/index', { - index_mapping_outdated: true, - name: '.siem-signals-default', - }); - }); - - context('On Detections home page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_URL); - }); - - it('We show the need admin primary callout', () => { - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - - context('On Rules Management page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - }); - - it('We show 1 primary callout of need admin', () => { - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - - context('On Rule Details page', () => { - beforeEach(() => { - createCustomRule(newRule); - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - waitForPageTitleToBeShown(); - goToRuleDetails(); - }); - - afterEach(() => { - deleteCustomRule(); - }); - - it('We show 1 primary callout', () => { - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly.spec.ts index 8f1ed00ffd10d..d807857cd72bd 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly.spec.ts @@ -26,6 +26,11 @@ const loadPageAsReadOnlyUser = (url: string) => { waitForPageTitleToBeShown(); }; +const loadPageAsPlatformEngineer = (url: string) => { + waitForPageWithoutDateRange(url, ROLES.platform_engineer); + waitForPageTitleToBeShown(); +}; + const reloadPage = () => { cy.reload(); waitForPageTitleToBeShown(); @@ -35,10 +40,9 @@ const waitForPageTitleToBeShown = () => { cy.get(PAGE_TITLE).should('be.visible'); }; -describe('Detections > Callouts indicating read-only access to resources', () => { +describe('Detections > Callouts', () => { const ALERTS_CALLOUT = 'read-only-access-to-alerts'; const RULES_CALLOUT = 'read-only-access-to-rules'; - const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; before(() => { // First, we have to open the app on behalf of a privileged user in order to initialize it. @@ -51,83 +55,121 @@ describe('Detections > Callouts indicating read-only access to resources', () => login(ROLES.reader); }); - context('On Detections home page', () => { - beforeEach(() => { - loadPageAsReadOnlyUser(DETECTIONS_URL); - }); - - it('We show one primary callout', () => { - waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); + context('indicating read-only access to resources', () => { + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsReadOnlyUser(DETECTIONS_URL); + }); - context('When a user clicks Dismiss on the callout', () => { - it('We hide it and persist the dismissal', () => { + it('We show one primary callout', () => { waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); - dismissCallOut(ALERTS_CALLOUT); - reloadPage(); - getCallOut(ALERTS_CALLOUT).should('not.exist'); }); - }); - }); - context('On Rules Management page', () => { - beforeEach(() => { - loadPageAsReadOnlyUser(DETECTIONS_RULE_MANAGEMENT_URL); + context('When a user clicks Dismiss on the callout', () => { + it('We hide it and persist the dismissal', () => { + waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); + dismissCallOut(ALERTS_CALLOUT); + reloadPage(); + getCallOut(ALERTS_CALLOUT).should('not.exist'); + }); + }); }); - it('We show one primary callout', () => { - waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsReadOnlyUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); - context('When a user clicks Dismiss on the callout', () => { - it('We hide it and persist the dismissal', () => { + it('We show one primary callout', () => { waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); - dismissCallOut(RULES_CALLOUT); - reloadPage(); - getCallOut(RULES_CALLOUT).should('not.exist'); }); - }); - }); - context('On Rule Details page', () => { - beforeEach(() => { - createCustomRule(newRule); - loadPageAsReadOnlyUser(DETECTIONS_RULE_MANAGEMENT_URL); - waitForPageTitleToBeShown(); - goToRuleDetails(); + context('When a user clicks Dismiss on the callout', () => { + it('We hide it and persist the dismissal', () => { + waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); + dismissCallOut(RULES_CALLOUT); + reloadPage(); + getCallOut(RULES_CALLOUT).should('not.exist'); + }); + }); }); - afterEach(() => { - deleteCustomRule(); - }); + context('On Rule Details page', () => { + beforeEach(() => { + createCustomRule(newRule); + loadPageAsReadOnlyUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); - it('We show two primary callouts', () => { - waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); - waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); + afterEach(() => { + deleteCustomRule(); + }); - context('When a user clicks Dismiss on the callouts', () => { - it('We hide them and persist the dismissal', () => { + it('We show two primary callouts', () => { waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); - dismissCallOut(ALERTS_CALLOUT); - reloadPage(); + context('When a user clicks Dismiss on the callouts', () => { + it('We hide them and persist the dismissal', () => { + waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); + waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); + dismissCallOut(ALERTS_CALLOUT); + reloadPage(); + + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('be.visible'); + + dismissCallOut(RULES_CALLOUT); + reloadPage(); + + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + }); + }); + }); + }); + + context('indicating read-write access to resources', () => { + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineer(DETECTIONS_URL); + }); + + it('We show no callout', () => { + getCallOut(ALERTS_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineer(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show no callout', () => { getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('be.visible'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + getCallOut(RULES_CALLOUT).should('not.exist'); + }); + }); - dismissCallOut(RULES_CALLOUT); - reloadPage(); + context('On Rule Details page', () => { + beforeEach(() => { + createCustomRule(newRule); + loadPageAsPlatformEngineer(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + it('We show no callouts', () => { getCallOut(ALERTS_CALLOUT).should('not.exist'); getCallOut(RULES_CALLOUT).should('not.exist'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts deleted file mode 100644 index ae769c7228537..0000000000000 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_readonly_need_admin.spec.ts +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ROLES } from '../../../common/test'; -import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; -import { newRule } from '../../objects/rule'; -import { PAGE_TITLE } from '../../screens/common/page'; - -import { - login, - loginAndWaitForPageWithoutDateRange, - waitForPageWithoutDateRange, -} from '../../tasks/login'; -import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; -import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; -import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; -import { getCallOut, waitForCallOutToBeShown, dismissCallOut } from '../../tasks/common/callouts'; -import { cleanKibana } from '../../tasks/common'; - -const loadPageAsReadOnlyUser = (url: string) => { - waitForPageWithoutDateRange(url, ROLES.reader); - waitForPageTitleToBeShown(); -}; - -const reloadPage = () => { - cy.reload(); - waitForPageTitleToBeShown(); -}; - -const waitForPageTitleToBeShown = () => { - cy.get(PAGE_TITLE).should('be.visible'); -}; - -describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { - const ALERTS_CALLOUT = 'read-only-access-to-alerts'; - const RULES_CALLOUT = 'read-only-access-to-rules'; - const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; - - before(() => { - // First, we have to open the app on behalf of a privileged user in order to initialize it. - // Otherwise the app will be disabled and show a "welcome"-like page. - cleanKibana(); - loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.platform_engineer); - waitForAlertsIndexToBeCreated(); - - // After that we can login as a read-only user. - login(ROLES.reader); - }); - - beforeEach(() => { - // Index mapping outdated is forced to return true as being outdated so that we get the - // need admin callouts being shown. - cy.intercept('GET', '/api/detection_engine/index', { - index_mapping_outdated: true, - name: '.siem-signals-default', - }); - }); - - context('On Detections home page', () => { - beforeEach(() => { - loadPageAsReadOnlyUser(DETECTIONS_URL); - }); - - it('We show the alerts and admin primary callout', () => { - waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - }); - - context('When a user clicks Dismiss on the callout', () => { - it('We hide it and persist the dismissal but still show the admin callout', () => { - waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); - dismissCallOut(ALERTS_CALLOUT); - reloadPage(); - getCallOut(ALERTS_CALLOUT).should('not.exist'); - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - }); - }); - }); - - context('On Rules Management page', () => { - beforeEach(() => { - loadPageAsReadOnlyUser(DETECTIONS_RULE_MANAGEMENT_URL); - }); - - it('We show two primary callouts of the alert and the admin', () => { - waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - }); - - context('When a user clicks Dismiss on the callout', () => { - it('We hide it and persist the dismissal', () => { - waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); - dismissCallOut(RULES_CALLOUT); - reloadPage(); - getCallOut(RULES_CALLOUT).should('not.exist'); - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - }); - }); - }); - - context('On Rule Details page', () => { - beforeEach(() => { - createCustomRule(newRule); - loadPageAsReadOnlyUser(DETECTIONS_RULE_MANAGEMENT_URL); - waitForPageTitleToBeShown(); - goToRuleDetails(); - }); - - afterEach(() => { - deleteCustomRule(); - }); - - it('We show three primary callouts', () => { - waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); - waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - }); - - context('When a user clicks Dismiss on the callouts', () => { - it('We hide them and persist the dismissal', () => { - waitForCallOutToBeShown(ALERTS_CALLOUT, 'primary'); - waitForCallOutToBeShown(RULES_CALLOUT, 'primary'); - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - - dismissCallOut(ALERTS_CALLOUT); - reloadPage(); - - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('be.visible'); - - dismissCallOut(RULES_CALLOUT); - reloadPage(); - - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_soc_manager_need_admin.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_soc_manager_need_admin.spec.ts deleted file mode 100644 index cb4658f524777..0000000000000 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_soc_manager_need_admin.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ROLES } from '../../../common/test'; -import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; -import { newRule } from '../../objects/rule'; -import { PAGE_TITLE } from '../../screens/common/page'; - -import { - loginAndWaitForPageWithoutDateRange, - waitForPageWithoutDateRange, -} from '../../tasks/login'; -import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; -import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; -import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; -import { getCallOut, waitForCallOutToBeShown } from '../../tasks/common/callouts'; -import { cleanKibana } from '../../tasks/common'; - -const loadPageAsPlatformEngineerUser = (url: string) => { - waitForPageWithoutDateRange(url, ROLES.soc_manager); - waitForPageTitleToBeShown(); -}; - -const waitForPageTitleToBeShown = () => { - cy.get(PAGE_TITLE).should('be.visible'); -}; - -describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { - const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; - const ALERTS_CALLOUT = 'read-only-access-to-alerts'; - const RULES_CALLOUT = 'read-only-access-to-rules'; - - before(() => { - cleanKibana(); - loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.soc_manager); - waitForAlertsIndexToBeCreated(); - }); - - beforeEach(() => { - // Index mapping outdated is forced to return true as being outdated so that we get the - // need admin callouts being shown. - cy.intercept('GET', '/api/detection_engine/index', { - index_mapping_outdated: true, - name: '.siem-signals-default', - }); - }); - - context('On Detections home page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_URL); - }); - - it('We show the need admin primary callout', () => { - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - }); - }); - - context('On Rules Management page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - }); - - it('We show 1 primary callout of need admin', () => { - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - }); - }); - - context('On Rule Details page', () => { - beforeEach(() => { - createCustomRule(newRule); - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - waitForPageTitleToBeShown(); - goToRuleDetails(); - }); - - afterEach(() => { - deleteCustomRule(); - }); - - it('We show 1 primary callout', () => { - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts deleted file mode 100644 index b558405185f7e..0000000000000 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_detection_callouts_t1_analyst.spec.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ROLES } from '../../../common/test'; -import { DETECTIONS_RULE_MANAGEMENT_URL, DETECTIONS_URL } from '../../urls/navigation'; -import { newRule } from '../../objects/rule'; -import { PAGE_TITLE } from '../../screens/common/page'; - -import { - loginAndWaitForPageWithoutDateRange, - waitForPageWithoutDateRange, -} from '../../tasks/login'; -import { waitForAlertsIndexToBeCreated } from '../../tasks/alerts'; -import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; -import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules'; -import { getCallOut } from '../../tasks/common/callouts'; -import { cleanKibana } from '../../tasks/common'; - -const loadPageAsPlatformEngineerUser = (url: string) => { - waitForPageWithoutDateRange(url, ROLES.t1_analyst); - waitForPageTitleToBeShown(); -}; - -const waitForPageTitleToBeShown = () => { - cy.get(PAGE_TITLE).should('be.visible'); -}; - -describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { - const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; - const ALERTS_CALLOUT = 'read-only-access-to-alerts'; - const RULES_CALLOUT = 'read-only-access-to-rules'; - - before(() => { - cleanKibana(); - loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.t1_analyst); - waitForAlertsIndexToBeCreated(); - }); - - context('On Detections home page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_URL); - }); - - it('We show no callouts', () => { - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - - context('On Rules Management page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - }); - - it('We show no callouts', () => { - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - - context('On Rule Details page', () => { - beforeEach(() => { - createCustomRule(newRule); - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - waitForPageTitleToBeShown(); - goToRuleDetails(); - }); - - afterEach(() => { - deleteCustomRule(); - }); - - it('We show no callouts', () => { - getCallOut(ALERTS_CALLOUT).should('not.exist'); - getCallOut(RULES_CALLOUT).should('not.exist'); - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/tasks/common/callouts.ts b/x-pack/plugins/security_solution/cypress/tasks/common/callouts.ts index 4139c911e4063..8440409f80f38 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/common/callouts.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/common/callouts.ts @@ -12,13 +12,11 @@ export const getCallOut = (id: string, options?: Cypress.Timeoutable) => { }; export const waitForCallOutToBeShown = (id: string, color: string) => { - getCallOut(id, { timeout: 10000 }) - .should('be.visible') - .should('have.class', `euiCallOut--${color}`); + getCallOut(id).should('be.visible').should('have.class', `euiCallOut--${color}`); }; export const dismissCallOut = (id: string) => { - getCallOut(id, { timeout: 10000 }).within(() => { + getCallOut(id).within(() => { cy.get(CALLOUT_DISMISS_BTN).should('be.visible').click(); cy.root().should('not.exist'); }); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/query.all_hosts.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/query.all_hosts.dsl.ts index 08c9711794978..892801a3aed0b 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/query.all_hosts.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/query.all_hosts.dsl.ts @@ -87,6 +87,6 @@ const getQueryOrder = (sort: SortField): QueryOrder => { case HostsFields.hostName: return { _key: sort.direction }; default: - return assertUnreachable(sort.field as never); + return assertUnreachable(sort.field); } };