diff --git a/.buildkite/disabled_jest_configs.json b/.buildkite/disabled_jest_configs.json index 9727d38158520c..ce6235823b0abc 100644 --- a/.buildkite/disabled_jest_configs.json +++ b/.buildkite/disabled_jest_configs.json @@ -1,4 +1,5 @@ [ "x-pack/plugins/triggers_actions_ui/jest.config.js", - "x-pack/plugins/watcher/jest.config.js" + "x-pack/plugins/watcher/jest.config.js", + "src/core/server/integration_tests/ui_settings/jest.integration.config.js" ] diff --git a/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts b/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts index b7c223b3ca595b..dfb384d7e3998a 100644 --- a/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts +++ b/.buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts @@ -234,6 +234,7 @@ export async function pickTestGroupRunOrder() { ? globby.sync(['**/jest.integration.config.js', '!**/__fixtures__/**'], { cwd: process.cwd(), absolute: false, + ignore: DISABLED_JEST_CONFIGS, }) : []; diff --git a/docs/api/actions-and-connectors/execute.asciidoc b/docs/api/actions-and-connectors/execute.asciidoc index b5c59bb86bc70b..8b046038b8d079 100644 --- a/docs/api/actions-and-connectors/execute.asciidoc +++ b/docs/api/actions-and-connectors/execute.asciidoc @@ -60,8 +60,7 @@ refer to <>. `documents`:: (Required, array of objects) The documents to index in JSON format. -For more information, refer to -{kibana-ref}/index-action-type.html[Index connector and action]. +For more information, refer to <>. ===== .Jira connectors @@ -158,10 +157,124 @@ the knowledge base. ======= ====== -For more information, refer to -{kibana-ref}/jira-action-type.html[{jira} connector and action]. +For more information, refer to <>. ===== +.{opsgenie} connectors +[%collapsible%open] +===== +`subAction`:: +(Required, string) The action to test. Valid values include: `createAlert` and +`closeAlert`. + +`subActionParams`:: +(Required, object) The set of configuration properties, which vary depending on +the `subAction` value. ++ +.Properties when `subAction` is `createAlert` +[%collapsible%open] +====== +`actions`:::: +(Optional, array of strings) The custom actions available to the alert. + +`alias`:::: +(Optional, string) The unique identifier used for alert de-duplication in {opsgenie}. + +`description`:::: +(Optional, string) A description that provides detailed information about the alert. + +`details`:::: +(Optional, object) The custom properties of the alert. For example: +`{"key1":"value1","key2":"value2"}`. + +`entity`:::: +(Optional, string) The domain of the alert. For example, the application or server +name. + +`message`:::: +(Required, string) The alert message. + +`note`:::: +(Optional, string) Additional information for the alert. + +`priority`:::: +(Optional, string) The priority level for the alert. Valid values are: `P1`, +`P2`, `P3`, `P4`, and `P5`. + +`responders`:::: +(Optional, array of objects) The entities to receive notifications about the +alert. If `type` is `user`, either `id` or `username` is required. If `type` is +`team`, either `id` or `name` is required. ++ +.Properties of `responders` objects +[%collapsible%open] +======= +`id`:::: +(Required^*^, string) The identifier for the entity. + +`name`:::: +(Required^*^, string) The name of the entity. + +`type`:::: +(Required, string) Valid values are `escalation`, `schedule`, `team`, and `user`. + +`username`:::: +(Required^*^, string) A valid email address for the user. +======= + +`source`:::: +(Optional, string) The display name for the source of the alert. + +`tags`:::: +(Optional, array of strings) The tags for the alert. + +`user`:::: +(Optional, string) The display name for the owner. + +`visibleTo`:::: +(Optional, array of objects) The teams and users that the alert will be visible +to without sending a notification. Only one of `id`, `name`, or `username` is +required. ++ +.Properties of `visibleTo` objects +[%collapsible%open] +======= +`id`:::: +(Required^*^, string) The identifier for the entity. + +`name`:::: +(Required^*^, string) The name of the entity. + +`type`:::: +(Required, string) Valid values are `team` and `user`. + +`username`:::: +(Required^*^, string) The user name. This property is required only when the +`type` is `user`. +======= +====== ++ +.Properties when `subAction` is `closeAlert` +[%collapsible%open] +====== +`alias`:::: +(Required, string) The unique identifier used for alert de-duplication in {opsgenie}. +The alias must match the value used when creating the alert. + +`note`:::: +(Optional, string) Additional information for the alert. + +`source`:::: +(Optional, string) The display name for the source of the alert. + +`user`:::: +(Optional, string) The display name for the owner. +====== + +For more information, refer to <>. +===== + + .{sn-itom} connectors [%collapsible%open] ===== diff --git a/docs/management/action-types.asciidoc b/docs/management/action-types.asciidoc index 74738a8fddeb1d..330f05734cb6af 100644 --- a/docs/management/action-types.asciidoc +++ b/docs/management/action-types.asciidoc @@ -91,6 +91,7 @@ Rules use connectors to route actions to different destinations like log files, [role="screenshot"] image::images/connector-listing.png[Example connector listing in the {rules-ui} UI] +// NOTE: This is an autogenerated screenshot. Do not edit it directly. [float] === Required permissions diff --git a/docs/management/connectors/images/connector-listing.png b/docs/management/connectors/images/connector-listing.png index 3c743ede804d38..aef38f84d4b543 100644 Binary files a/docs/management/connectors/images/connector-listing.png and b/docs/management/connectors/images/connector-listing.png differ diff --git a/docs/management/connectors/index.asciidoc b/docs/management/connectors/index.asciidoc index fe65120e4b2b99..b443ffd967a6ff 100644 --- a/docs/management/connectors/index.asciidoc +++ b/docs/management/connectors/index.asciidoc @@ -3,6 +3,7 @@ include::action-types/resilient.asciidoc[] include::action-types/index.asciidoc[] include::action-types/jira.asciidoc[] include::action-types/teams.asciidoc[] +include::action-types/opsgenie.asciidoc[] include::action-types/pagerduty.asciidoc[] include::action-types/server-log.asciidoc[] include::action-types/servicenow.asciidoc[leveloffset=+1] @@ -10,9 +11,8 @@ include::action-types/servicenow-sir.asciidoc[leveloffset=+1] include::action-types/servicenow-itom.asciidoc[leveloffset=+1] include::action-types/swimlane.asciidoc[] include::action-types/slack.asciidoc[] +include::action-types/tines.asciidoc[leveloffset=+1] include::action-types/webhook.asciidoc[] include::action-types/cases-webhook.asciidoc[leveloffset=+1] -include::action-types/opsgenie.asciidoc[] include::action-types/xmatters.asciidoc[] -include::action-types/tines.asciidoc[leveloffset=+1] include::pre-configured-connectors.asciidoc[] diff --git a/src/plugins/guided_onboarding/server/helpers/plugin_state_utils.ts b/src/plugins/guided_onboarding/server/helpers/plugin_state_utils.ts index f24fdf814f83b4..06fc211f1864f4 100644 --- a/src/plugins/guided_onboarding/server/helpers/plugin_state_utils.ts +++ b/src/plugins/guided_onboarding/server/helpers/plugin_state_utils.ts @@ -40,7 +40,14 @@ export const getPluginState = async (savedObjectsClient: SavedObjectsClient) => return pluginState; } else { // create a SO to keep track of the correct creation date - await updatePluginStatus(savedObjectsClient, 'not_started'); + try { + await updatePluginStatus(savedObjectsClient, 'not_started'); + // @yulia, we need to add a user permissions + // check here instead of swallowing this error + // see issue: https://github.com/elastic/kibana/issues/145434 + // eslint-disable-next-line no-empty + } catch (e) {} + return { status: 'not_started', isActivePeriod: true, diff --git a/x-pack/plugins/security_solution/cypress/e2e/guided_onboarding/tour.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/guided_onboarding/tour.cy.ts index 0339445bc8240b..e1dc50d8d28c84 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/guided_onboarding/tour.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/guided_onboarding/tour.cy.ts @@ -5,58 +5,100 @@ * 2.0. */ -import { login, visit } from '../../tasks/login'; -import { completeTour, goToNextStep, skipTour } from '../../tasks/guided_onboarding'; -import { OVERVIEW_URL } from '../../urls/navigation'; +import { navigateFromHeaderTo } from '../../tasks/security_header'; +import { ALERTS, TIMELINES } from '../../screens/security_header'; +import { closeAlertFlyout, expandFirstAlert } from '../../tasks/alerts'; import { - WELCOME_STEP, - MANAGE_STEP, - ALERTS_STEP, - CASES_STEP, - DATA_STEP, -} from '../../screens/guided_onboarding'; - -before(() => { - login(); -}); + assertTourStepExist, + assertTourStepNotExist, + closeCreateCaseFlyout, + completeTourWithActions, + completeTourWithNextButton, + addToCase, + finishTour, + goToStep, + startTour, +} from '../../tasks/guided_onboarding'; +import { cleanKibana } from '../../tasks/common'; +import { createCustomRuleEnabled } from '../../tasks/api_calls/rules'; +import { getNewRule } from '../../objects/rule'; +import { ALERTS_URL, DASHBOARDS_URL } from '../../urls/navigation'; +import { waitForAlertsToPopulate } from '../../tasks/create_new_rule'; +import { login, visit } from '../../tasks/login'; +import { quitGlobalTour, startAlertsCasesTour } from '../../tasks/api_calls/tour'; +import { AlertsCasesTourSteps } from '../../../public/common/components/guided_onboarding_tour/tour_config'; -// need to redo these tests for new implementation -describe.skip('Guided onboarding tour', () => { - describe('Tour is enabled', () => { - beforeEach(() => { - visit(OVERVIEW_URL); - }); +describe('Guided onboarding tour', () => { + before(() => { + cleanKibana(); + login(); + createCustomRuleEnabled({ ...getNewRule(), customQuery: 'user.name:*' }); + }); + beforeEach(() => { + startAlertsCasesTour(); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + }); + after(() => { + quitGlobalTour(); + }); + it('Completes the tour with next button clicks', () => { + startTour(); + completeTourWithNextButton(); + finishTour(); + cy.url().should('include', DASHBOARDS_URL); + }); - it('can be completed', () => { - // Step 1: Overview - cy.get(WELCOME_STEP).should('be.visible'); - goToNextStep(WELCOME_STEP); + it('Completes the tour with action clicks', () => { + startTour(); + completeTourWithActions(); + finishTour(); + cy.url().should('include', DASHBOARDS_URL); + }); - // Step 2: Manage - cy.get(MANAGE_STEP).should('be.visible'); - goToNextStep(MANAGE_STEP); + // unhappy paths + it('Resets the tour to step 1 when we navigate away', () => { + startTour(); + goToStep(AlertsCasesTourSteps.expandEvent); + assertTourStepExist(AlertsCasesTourSteps.expandEvent); + assertTourStepNotExist(AlertsCasesTourSteps.pointToAlertName); + navigateFromHeaderTo(TIMELINES); + navigateFromHeaderTo(ALERTS); + assertTourStepNotExist(AlertsCasesTourSteps.expandEvent); + assertTourStepExist(AlertsCasesTourSteps.pointToAlertName); + }); - // Step 3: Alerts - cy.get(ALERTS_STEP).should('be.visible'); - goToNextStep(ALERTS_STEP); + describe('persists tour steps in flyout on flyout toggle', () => { + const stepsInAlertsFlyout = [ + AlertsCasesTourSteps.reviewAlertDetailsFlyout, + AlertsCasesTourSteps.addAlertToCase, + AlertsCasesTourSteps.viewCase, + ]; - // Step 4: Cases - cy.get(CASES_STEP).should('be.visible'); - goToNextStep(CASES_STEP); + const stepsInCasesFlyout = [AlertsCasesTourSteps.createCase, AlertsCasesTourSteps.submitCase]; - // Step 5: Add data - cy.get(DATA_STEP).should('be.visible'); - completeTour(); + stepsInAlertsFlyout.forEach((step) => { + it(`step: ${step}, resets to ${step}`, () => { + startTour(); + goToStep(step); + assertTourStepExist(step); + closeAlertFlyout(); + assertTourStepNotExist(step); + expandFirstAlert(); + assertTourStepExist(step); + }); }); - it('can be skipped', () => { - cy.get(WELCOME_STEP).should('be.visible'); - - skipTour(); - // step 1 is not displayed - cy.get(WELCOME_STEP).should('not.exist'); - // step 2 is not displayed - cy.get(MANAGE_STEP).should('not.exist'); + stepsInCasesFlyout.forEach((step) => { + it(`step: ${step}, resets to ${AlertsCasesTourSteps.createCase}`, () => { + startTour(); + goToStep(step); + assertTourStepExist(step); + closeCreateCaseFlyout(); + assertTourStepNotExist(step); + addToCase(); + assertTourStepExist(AlertsCasesTourSteps.createCase); + }); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/screens/guided_onboarding.ts b/x-pack/plugins/security_solution/cypress/screens/guided_onboarding.ts index 6b3f4bc20ac037..f11c18817e1ba6 100644 --- a/x-pack/plugins/security_solution/cypress/screens/guided_onboarding.ts +++ b/x-pack/plugins/security_solution/cypress/screens/guided_onboarding.ts @@ -5,12 +5,13 @@ * 2.0. */ -export const WELCOME_STEP = '[data-test-subj="welcomeStep"]'; -export const MANAGE_STEP = '[data-test-subj="manageStep"]'; -export const ALERTS_STEP = '[data-test-subj="alertsStep"]'; -export const CASES_STEP = '[data-test-subj="casesStep"]'; -export const DATA_STEP = '[data-test-subj="dataStep"]'; +export const ALERTS_STEP_GUIDE_BUTTON = '[data-test-subj="onboarding--stepButton--siem--step3"]'; +export const COMPLETE_SIEM_GUIDE_BUTTON = + '[data-test-subj="onboarding--completeGuideButton--siem"]'; export const NEXT_STEP_BUTTON = '[data-test-subj="onboarding--securityTourNextStepButton"]'; -export const END_TOUR_BUTTON = '[data-test-subj="onboarding--securityTourEndButton"]'; -export const SKIP_TOUR_BUTTON = '[data-test-subj="onboarding--securityTourSkipButton"]'; +export const COMPLETION_POPOVER = '[data-test-subj="manualCompletionPopover"]'; + +export const GLOBAL_TOUR_BUTTON = `[data-test-subj="guideButton"]`; + +export const CLOSE_CREATE_CASE_FLYOUT = `[data-test-subj="create-case-flyout"] [data-test-subj="euiFlyoutCloseButton"]`; diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/tour.ts b/x-pack/plugins/security_solution/cypress/tasks/api_calls/tour.ts new file mode 100644 index 00000000000000..5eac1af18745ff --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/tasks/api_calls/tour.ts @@ -0,0 +1,42 @@ +/* + * 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. + */ + +const alertsGuideActiveState = { + isActive: true, + status: 'in_progress', + steps: [ + { id: 'add_data', status: 'complete' }, + { id: 'rules', status: 'complete' }, + { id: 'alertsCases', status: 'active' }, + ], + guideId: 'security', +}; + +export const startAlertsCasesTour = () => + cy.request({ + method: 'PUT', + url: 'api/guided_onboarding/state', + headers: { 'kbn-xsrf': 'cypress-creds' }, + body: { + status: 'in_progress', + guide: alertsGuideActiveState, + }, + }); + +export const quitGlobalTour = () => + cy.request({ + method: 'PUT', + url: 'api/guided_onboarding/state', + headers: { 'kbn-xsrf': 'cypress-creds' }, + body: { + status: 'quit', + guide: { + ...alertsGuideActiveState, + isActive: false, + }, + }, + }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/guided_onboarding.ts b/x-pack/plugins/security_solution/cypress/tasks/guided_onboarding.ts index 2e5c54a396b240..fe3170b31e9510 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/guided_onboarding.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/guided_onboarding.ts @@ -5,21 +5,75 @@ * 2.0. */ +import { ATTACH_TO_NEW_CASE_BUTTON, TAKE_ACTION_BTN } from '../screens/alerts'; +import { createCase } from './create_new_case'; import { NEXT_STEP_BUTTON, - END_TOUR_BUTTON, - DATA_STEP, - SKIP_TOUR_BUTTON, + GLOBAL_TOUR_BUTTON, + ALERTS_STEP_GUIDE_BUTTON, + COMPLETION_POPOVER, + COMPLETE_SIEM_GUIDE_BUTTON, + CLOSE_CREATE_CASE_FLYOUT, } from '../screens/guided_onboarding'; +import { expandFirstAlert } from './alerts'; -export const goToNextStep = (currentStep: string) => { - cy.get(`${currentStep} ${NEXT_STEP_BUTTON}`).click(); +export const goToNextStep = (currentStep: number) => { + cy.get( + `[data-test-subj="tourStepAnchor-alertsCases-${currentStep}"] ${NEXT_STEP_BUTTON}` + ).click(); }; -export const completeTour = () => { - cy.get(`${DATA_STEP} ${END_TOUR_BUTTON}`).click(); +export const startTour = () => { + cy.get(GLOBAL_TOUR_BUTTON).click(); + cy.get(ALERTS_STEP_GUIDE_BUTTON).click(); }; -export const skipTour = () => { - cy.get(SKIP_TOUR_BUTTON).click(); +export const finishTour = () => { + cy.get(COMPLETION_POPOVER).should('exist'); + cy.get(GLOBAL_TOUR_BUTTON).click(); + cy.get(ALERTS_STEP_GUIDE_BUTTON).click(); + cy.get(COMPLETE_SIEM_GUIDE_BUTTON).click(); }; + +export const completeTourWithNextButton = () => { + for (let i = 1; i < 6; i++) { + goToNextStep(i); + } + createCase(); + goToNextStep(7); +}; + +export const addToCase = () => { + cy.get(TAKE_ACTION_BTN).click(); + cy.get(ATTACH_TO_NEW_CASE_BUTTON).click(); +}; + +export const completeTourWithActions = () => { + goToNextStep(1); + expandFirstAlert(); + goToNextStep(3); + addToCase(); + goToNextStep(5); + createCase(); + goToNextStep(7); +}; + +export const goToStep = (step: number) => { + for (let i = 1; i < 6; i++) { + if (i === step) { + break; + } + goToNextStep(i); + } + if (step === 7) { + createCase(); + } +}; + +export const assertTourStepExist = (step: number) => + cy.get(`[data-test-subj="tourStepAnchor-alertsCases-${step}"]`).should('exist'); + +export const assertTourStepNotExist = (step: number) => + cy.get(`[data-test-subj="tourStepAnchor-alertsCases-${step}"]`).should('not.exist'); + +export const closeCreateCaseFlyout = () => cy.get(CLOSE_CREATE_CASE_FLYOUT).click(); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index f1633386a6ea95..d2a97e17a58824 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -27372,11 +27372,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.columns.tagsTitle": "Balises", "xpack.securitySolution.detectionEngine.rules.allRules.columns.versionTitle": "Version", "xpack.securitySolution.detectionEngine.rules.allRules.exportFilenameTitle": "rules_export", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.nextStepLabel": "Aller à l'étape suivante", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.previousStepLabel": "Revenir à l'étape précédente", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.searchCapabilitiesDescription": "Il est maintenant possible de rechercher des règles par modèle d'indexation, tel que \"filebeat-*\", ou par tactique ou technique MITRE ATT&CK™, telle que \"Évasion par la défense \" ou \"TA0005\".", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.searchCapabilitiesTitle": "Capacités de recherche améliorées", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.tourTitle": "Nouveautés", "xpack.securitySolution.detectionEngine.rules.allRules.filters.customRulesTitle": "Règles personnalisées", "xpack.securitySolution.detectionEngine.rules.allRules.filters.elasticRulesTitle": "Règles Elastic", "xpack.securitySolution.detectionEngine.rules.allRules.filters.noRulesBodyTitle": "Nous n'avons trouvé aucune règle avec les filtres ci-dessus.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f817015c2ee9ae..5ad47b09d93de1 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -27347,11 +27347,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.columns.tagsTitle": "タグ", "xpack.securitySolution.detectionEngine.rules.allRules.columns.versionTitle": "バージョン", "xpack.securitySolution.detectionEngine.rules.allRules.exportFilenameTitle": "rules_export", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.nextStepLabel": "次のステップに進む", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.previousStepLabel": "前のステップに戻る", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.searchCapabilitiesDescription": "「filebeat-*」などのインデックスパターンや、「Defense Evasion」や「TA0005」などのMITRE ATT&CK™方式または手法でルールを検索できます。", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.searchCapabilitiesTitle": "拡張検索機能", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.tourTitle": "新機能", "xpack.securitySolution.detectionEngine.rules.allRules.filters.customRulesTitle": "カスタムルール", "xpack.securitySolution.detectionEngine.rules.allRules.filters.elasticRulesTitle": "Elasticルール", "xpack.securitySolution.detectionEngine.rules.allRules.filters.noRulesBodyTitle": "上記のフィルターでルールが見つかりませんでした。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 02e20106947ea7..ea64b3b043ab0d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -27381,11 +27381,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.columns.tagsTitle": "标签", "xpack.securitySolution.detectionEngine.rules.allRules.columns.versionTitle": "版本", "xpack.securitySolution.detectionEngine.rules.allRules.exportFilenameTitle": "rules_export", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.nextStepLabel": "前往下一步", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.previousStepLabel": "前往上一步", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.searchCapabilitiesDescription": "现在可以按搜索模式(如“filebeat-*”) 或者 MITRE ATT&CK™ 策略或技术(如“Defense Evasion”或“TA0005”)搜索规则。", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.searchCapabilitiesTitle": "已增强搜索功能", - "xpack.securitySolution.detectionEngine.rules.allRules.featureTour.tourTitle": "最新动态", "xpack.securitySolution.detectionEngine.rules.allRules.filters.customRulesTitle": "定制规则", "xpack.securitySolution.detectionEngine.rules.allRules.filters.elasticRulesTitle": "Elastic 规则", "xpack.securitySolution.detectionEngine.rules.allRules.filters.noRulesBodyTitle": "使用上述筛选,我们无法找到任何规则。", diff --git a/x-pack/test/functional/config.base.js b/x-pack/test/functional/config.base.js index f9953dc861ea03..7ed28068485b34 100644 --- a/x-pack/test/functional/config.base.js +++ b/x-pack/test/functional/config.base.js @@ -169,6 +169,9 @@ export default async function ({ readConfigFile }) { observability: { pathname: '/app/observability', }, + connectors: { + pathname: '/app/management/insightsAndAlerting/triggersActionsConnectors/', + }, }, // choose where screenshots should be saved diff --git a/x-pack/test/functional/services/actions/api.ts b/x-pack/test/functional/services/actions/api.ts new file mode 100644 index 00000000000000..a6ea0a2666119b --- /dev/null +++ b/x-pack/test/functional/services/actions/api.ts @@ -0,0 +1,46 @@ +/* + * 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 { FtrProviderContext } from '../../ftr_provider_context'; + +export function ActionsAPIServiceProvider({ getService }: FtrProviderContext) { + const kbnSupertest = getService('supertest'); + + return { + async createConnector({ + name, + config, + secrets, + connectorTypeId, + }: { + name: string; + config: Record; + secrets: Record; + connectorTypeId: string; + }) { + const { body: createdAction } = await kbnSupertest + .post(`/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name, + config, + secrets, + connector_type_id: connectorTypeId, + }) + .expect(200); + + return createdAction; + }, + + async deleteConnector(id: string) { + return kbnSupertest + .delete(`/api/actions/connector/${id}`) + .set('kbn-xsrf', 'foo') + .expect(204, ''); + }, + }; +} diff --git a/x-pack/test/functional/services/actions/index.ts b/x-pack/test/functional/services/actions/index.ts index 852a74d1d544d7..c7539c37f2c32c 100644 --- a/x-pack/test/functional/services/actions/index.ts +++ b/x-pack/test/functional/services/actions/index.ts @@ -9,11 +9,13 @@ import { FtrProviderContext } from '../../ftr_provider_context'; import { ActionsCommonServiceProvider } from './common'; import { ActionsOpsgenieServiceProvider } from './opsgenie'; import { ActionsTinesServiceProvider } from './tines'; +import { ActionsAPIServiceProvider } from './api'; export function ActionsServiceProvider(context: FtrProviderContext) { const common = ActionsCommonServiceProvider(context); return { + api: ActionsAPIServiceProvider(context), common: ActionsCommonServiceProvider(context), opsgenie: ActionsOpsgenieServiceProvider(context, common), tines: ActionsTinesServiceProvider(context, common), diff --git a/x-pack/test/functional/services/index.ts b/x-pack/test/functional/services/index.ts index ce18ca46813101..6165c5a22d63b5 100644 --- a/x-pack/test/functional/services/index.ts +++ b/x-pack/test/functional/services/index.ts @@ -73,6 +73,7 @@ import { CasesServiceProvider } from './cases'; import { ActionsServiceProvider } from './actions'; import { RulesServiceProvider } from './rules'; import { AiopsProvider } from './aiops'; +import { SampleDataServiceProvider } from './sample_data'; // define the name and providers for services that should be // available to your tests. If you don't specify anything here @@ -136,4 +137,5 @@ export const services = { rules: RulesServiceProvider, cases: CasesServiceProvider, aiops: AiopsProvider, + sampleData: SampleDataServiceProvider, }; diff --git a/x-pack/test/functional/services/ml/test_resources.ts b/x-pack/test/functional/services/ml/test_resources.ts index 56d01a4f1a8670..03cf56c3322ad9 100644 --- a/x-pack/test/functional/services/ml/test_resources.ts +++ b/x-pack/test/functional/services/ml/test_resources.ts @@ -630,39 +630,5 @@ export function MachineLearningTestResourcesProvider( async clearAdvancedSettingProperty(propertyName: string) { await kibanaServer.uiSettings.unset(propertyName); }, - - async installKibanaSampleData(sampleDataId: 'ecommerce' | 'flights' | 'logs') { - log.debug(`Installing Kibana sample data '${sampleDataId}'`); - - const { body, status } = await supertest - .post(`/api/sample_data/${sampleDataId}`) - .set(COMMON_REQUEST_HEADERS); - mlApi.assertResponseStatusCode(200, status, body); - - log.debug(` > Installed`); - }, - - async removeKibanaSampleData(sampleDataId: 'ecommerce' | 'flights' | 'logs') { - log.debug(`Removing Kibana sample data '${sampleDataId}'`); - - const { body, status } = await supertest - .delete(`/api/sample_data/${sampleDataId}`) - .set(COMMON_REQUEST_HEADERS); - mlApi.assertResponseStatusCode(204, status, body); - - log.debug(` > Removed`); - }, - - async installAllKibanaSampleData() { - await this.installKibanaSampleData('ecommerce'); - await this.installKibanaSampleData('flights'); - await this.installKibanaSampleData('logs'); - }, - - async removeAllKibanaSampleData() { - await this.removeKibanaSampleData('ecommerce'); - await this.removeKibanaSampleData('flights'); - await this.removeKibanaSampleData('logs'); - }, }; } diff --git a/x-pack/test/functional/services/sample_data/index.ts b/x-pack/test/functional/services/sample_data/index.ts new file mode 100644 index 00000000000000..dc0e764093854a --- /dev/null +++ b/x-pack/test/functional/services/sample_data/index.ts @@ -0,0 +1,15 @@ +/* + * 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 { FtrProviderContext } from '../../ftr_provider_context'; +import { SampleDataTestResourcesServiceProvider } from './test_resources'; + +export function SampleDataServiceProvider(context: FtrProviderContext) { + return { + testResources: SampleDataTestResourcesServiceProvider(context), + }; +} diff --git a/x-pack/test/functional/services/sample_data/test_resources.ts b/x-pack/test/functional/services/sample_data/test_resources.ts new file mode 100644 index 00000000000000..776cb4ad408ee1 --- /dev/null +++ b/x-pack/test/functional/services/sample_data/test_resources.ts @@ -0,0 +1,37 @@ +/* + * 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 { FtrProviderContext } from '../../ftr_provider_context'; + +export function SampleDataTestResourcesServiceProvider({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + return { + async installKibanaSampleData(sampleDataId: 'ecommerce' | 'flights' | 'logs') { + await supertest.post(`/api/sample_data/${sampleDataId}`).set('kbn-xsrf', 'true').expect(200); + }, + + async removeKibanaSampleData(sampleDataId: 'ecommerce' | 'flights' | 'logs') { + await supertest + .delete(`/api/sample_data/${sampleDataId}`) + .set('kbn-xsrf', 'true') + .expect(204); + }, + + async installAllKibanaSampleData() { + await this.installKibanaSampleData('ecommerce'); + await this.installKibanaSampleData('flights'); + await this.installKibanaSampleData('logs'); + }, + + async removeAllKibanaSampleData() { + await this.removeKibanaSampleData('ecommerce'); + await this.removeKibanaSampleData('flights'); + await this.removeKibanaSampleData('logs'); + }, + }; +} diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/general.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/general.ts index c0ee2bed54a02f..bb6c01b6fd53fe 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/general.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/general.ts @@ -77,7 +77,7 @@ export default ({ getPageObjects, getPageObject, getService }: FtrProviderContex const updatedConnectorName = `${connectorName}updated`; const createdAction = await createSlackConnector({ name: connectorName, - supertest, + getService, }); objectRemover.add(createdAction.id, 'action', 'actions'); await browser.refresh(); @@ -176,7 +176,7 @@ export default ({ getPageObjects, getPageObject, getService }: FtrProviderContex const connectorName = generateUniqueKey(); const createdAction = await createSlackConnector({ name: connectorName, - supertest, + getService, }); objectRemover.add(createdAction.id, 'action', 'actions'); await browser.refresh(); @@ -205,10 +205,10 @@ export default ({ getPageObjects, getPageObject, getService }: FtrProviderContex it('should delete a connector', async () => { const connectorName = generateUniqueKey(); - await createSlackConnector({ name: connectorName, supertest }); + await createSlackConnector({ name: connectorName, getService }); const createdAction = await createSlackConnector({ name: generateUniqueKey(), - supertest, + getService, }); objectRemover.add(createdAction.id, 'action', 'actions'); await browser.refresh(); @@ -234,10 +234,10 @@ export default ({ getPageObjects, getPageObject, getService }: FtrProviderContex it('should bulk delete connectors', async () => { const connectorName = generateUniqueKey(); - await createSlackConnector({ name: connectorName, supertest }); + await createSlackConnector({ name: connectorName, getService }); const createdAction = await createSlackConnector({ name: generateUniqueKey(), - supertest, + getService, }); objectRemover.add(createdAction.id, 'action', 'actions'); await browser.refresh(); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/opsgenie.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/opsgenie.ts index 574505a7c4e880..e88c776f498c69 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/opsgenie.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/opsgenie.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { ObjectRemover } from '../../../lib/object_remover'; import { generateUniqueKey } from '../../../lib/get_test_data'; -import { createConnector, createSlackConnectorAndObjectRemover, getConnectorByName } from './utils'; +import { createSlackConnectorAndObjectRemover, getConnectorByName } from './utils'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); @@ -366,12 +366,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }; const createOpsgenieConnector = async (name: string) => { - return createConnector({ + return actions.api.createConnector({ name, config: { apiUrl: 'https//test.com' }, secrets: { apiKey: '1234' }, connectorTypeId: '.opsgenie', - supertest, }); }; }); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/tines.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/tines.ts index 5335b24a725b99..c6e9f4aec0fc11 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/tines.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/tines.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { ObjectRemover } from '../../../lib/object_remover'; import { generateUniqueKey } from '../../../lib/get_test_data'; -import { createConnector, getConnectorByName } from './utils'; +import { getConnectorByName } from './utils'; import { tinesAgentWebhook, tinesStory1, @@ -267,12 +267,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); const createTinesConnector = async (name: string) => { - return createConnector({ + return actions.api.createConnector({ name, config: { url: simulatorUrl }, secrets: { email: 'test@foo.com', token: 'apiToken' }, connectorTypeId: '.tines', - supertest, }); }; }); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/utils.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/utils.ts index f8b7ea162c0ffe..ffae007307fcdb 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/utils.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/utils.ts @@ -23,7 +23,7 @@ export const createSlackConnectorAndObjectRemover = async ({ const testData = getTestActionData(); const createdAction = await createSlackConnector({ name: testData.name, - supertest, + getService, }); objectRemover.add(createdAction.id, 'action', 'actions'); @@ -32,17 +32,17 @@ export const createSlackConnectorAndObjectRemover = async ({ export const createSlackConnector = async ({ name, - supertest, + getService, }: { name: string; - supertest: SuperTest.SuperTest; + getService: FtrProviderContext['getService']; }) => { - const connector = await createConnector({ + const actions = getService('actions'); + const connector = await actions.api.createConnector({ name, config: {}, secrets: { webhookUrl: 'https://test.com' }, connectorTypeId: '.slack', - supertest, }); return connector; @@ -59,30 +59,3 @@ export const getConnectorByName = async ( const i = findIndex(body, (c: any) => c.name === name); return body[i]; }; - -export const createConnector = async ({ - name, - config, - secrets, - connectorTypeId, - supertest, -}: { - name: string; - config: Record; - secrets: Record; - connectorTypeId: string; - supertest: SuperTest.SuperTest; -}) => { - const { body: createdAction } = await supertest - .post(`/api/actions/connector`) - .set('kbn-xsrf', 'foo') - .send({ - name, - config, - secrets, - connector_type_id: connectorTypeId, - }) - .expect(200); - - return createdAction; -}; diff --git a/x-pack/test/screenshot_creation/apps/ml_docs/index.ts b/x-pack/test/screenshot_creation/apps/ml_docs/index.ts index 806414939cd845..6d1e8792696604 100644 --- a/x-pack/test/screenshot_creation/apps/ml_docs/index.ts +++ b/x-pack/test/screenshot_creation/apps/ml_docs/index.ts @@ -14,13 +14,14 @@ export const LOGS_INDEX_PATTERN = 'kibana_sample_data_logs'; export default function ({ getPageObject, getService, loadTestFile }: FtrProviderContext) { const browser = getService('browser'); const ml = getService('ml'); + const sampleData = getService('sampleData'); const securityPage = getPageObject('security'); describe('machine learning docs', function () { this.tags(['ml']); before(async () => { - await ml.testResources.installAllKibanaSampleData(); + await sampleData.testResources.installAllKibanaSampleData(); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.testResources.disableKibanaAnnouncements(); await browser.setWindowSize(1920, 1080); @@ -28,7 +29,7 @@ export default function ({ getPageObject, getService, loadTestFile }: FtrProvide after(async () => { await securityPage.forceLogout(); - await ml.testResources.removeAllKibanaSampleData(); + await sampleData.testResources.removeAllKibanaSampleData(); await ml.testResources.resetKibanaTimeZone(); await ml.testResources.resetKibanaAnnouncements(); }); diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/index.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/index.ts index e836e3e63c9b7c..6302300641c760 100644 --- a/x-pack/test/screenshot_creation/apps/response_ops_docs/index.ts +++ b/x-pack/test/screenshot_creation/apps/response_ops_docs/index.ts @@ -15,13 +15,14 @@ export const LOGS_INDEX_PATTERN = 'kibana_sample_data_logs'; export default function ({ getPageObject, getService, loadTestFile }: FtrProviderContext) { const browser = getService('browser'); const ml = getService('ml'); + const sampleData = getService('sampleData'); const securityPage = getPageObject('security'); describe('response ops docs', function () { this.tags(['responseOps']); before(async () => { - await ml.testResources.installAllKibanaSampleData(); + await sampleData.testResources.installAllKibanaSampleData(); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.testResources.disableKibanaAnnouncements(); await browser.setWindowSize(1920, 1080); @@ -33,11 +34,12 @@ export default function ({ getPageObject, getService, loadTestFile }: FtrProvide after(async () => { await securityPage.forceLogout(); - await ml.testResources.removeAllKibanaSampleData(); + await sampleData.testResources.removeAllKibanaSampleData(); await ml.testResources.resetKibanaTimeZone(); await ml.testResources.resetKibanaAnnouncements(); }); + loadTestFile(require.resolve('./stack_alerting')); loadTestFile(require.resolve('./stack_cases')); loadTestFile(require.resolve('./observability_cases')); }); diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_alerting/index.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_alerting/index.ts new file mode 100644 index 00000000000000..200a3ae1e8793c --- /dev/null +++ b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_alerting/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('stack alerting', function () { + loadTestFile(require.resolve('./list_view')); + }); +} diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_alerting/list_view.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_alerting/list_view.ts new file mode 100644 index 00000000000000..4c87ced8a0cb3c --- /dev/null +++ b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_alerting/list_view.ts @@ -0,0 +1,48 @@ +/* + * 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 { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const commonScreenshots = getService('commonScreenshots'); + const screenshotDirectories = ['response_ops_docs', 'stack_alerting']; + const pageObjects = getPageObjects(['common', 'header']); + const actions = getService('actions'); + + describe('list view', function () { + let serverLogConnectorId: string; + + before(async () => { + const connectorName = `server-log-connector`; + ({ id: serverLogConnectorId } = await createServerLogConnector(connectorName)); + }); + + after(async () => { + await actions.api.deleteConnector(serverLogConnectorId); + }); + + it('connectors list screenshot', async () => { + await pageObjects.common.navigateToApp('connectors'); + await pageObjects.header.waitUntilLoadingHasFinished(); + await commonScreenshots.takeScreenshot( + 'connector-listing', + screenshotDirectories, + 1400, + 1024 + ); + }); + }); + + const createServerLogConnector = async (name: string) => { + return actions.api.createConnector({ + name, + config: {}, + secrets: {}, + connectorTypeId: '.server-log', + }); + }; +} diff --git a/x-pack/test/screenshot_creation/ftr_provider_context.d.ts b/x-pack/test/screenshot_creation/ftr_provider_context.d.ts index 2cd67b6698a70d..24f5087ef7fe2f 100644 --- a/x-pack/test/screenshot_creation/ftr_provider_context.d.ts +++ b/x-pack/test/screenshot_creation/ftr_provider_context.d.ts @@ -7,7 +7,7 @@ import { GenericFtrProviderContext } from '@kbn/test'; -import { pageObjects } from '../functional/page_objects'; +import { pageObjects } from './page_objects'; import { services } from './services'; export type FtrProviderContext = GenericFtrProviderContext; diff --git a/x-pack/test/screenshot_creation/page_objects/index.ts b/x-pack/test/screenshot_creation/page_objects/index.ts new file mode 100644 index 00000000000000..087ae675ed669a --- /dev/null +++ b/x-pack/test/screenshot_creation/page_objects/index.ts @@ -0,0 +1,16 @@ +/* + * 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 { pageObjects as xpackFunctionalPageObjects } from '../../functional/page_objects'; +import { TriggersActionsPageProvider } from '../../functional_with_es_ssl/page_objects/triggers_actions_ui_page'; +import { RuleDetailsPageProvider } from '../../functional_with_es_ssl/page_objects/rule_details'; + +export const pageObjects = { + ...xpackFunctionalPageObjects, + triggersActionsUI: TriggersActionsPageProvider, + ruleDetailsUI: RuleDetailsPageProvider, +}; diff --git a/x-pack/test/security_solution_cypress/config.ts b/x-pack/test/security_solution_cypress/config.ts index 18d7577516fd9e..843d6457b55f11 100644 --- a/x-pack/test/security_solution_cypress/config.ts +++ b/x-pack/test/security_solution_cypress/config.ts @@ -52,6 +52,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--xpack.securitySolution.enableExperimental=${JSON.stringify([ 'alertDetailsPageEnabled', ])}`, + // mock cloud to enable the guided onboarding tour in e2e tests + '--xpack.cloud.id=test', `--home.disableWelcomeScreen=true`, ], },