diff --git a/.buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh b/.buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh index 56b44315bf064..9d353b167ea47 100755 --- a/.buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh +++ b/.buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh @@ -16,6 +16,9 @@ export JOB=kibana-security-solution-chrome buildkite-agent meta-data set "${BUILDKITE_JOB_ID}_is_test_execution_step" "true" +mkdir .ftr +retry 5 5 vault kv get -format=json -field=data secret/kibana-issues/dev/security-quality-gate/role-users > .ftr/role_users.json + cd x-pack/test/security_solution_cypress set +e diff --git a/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts b/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts index 22b51692eb33f..f3a7070aa7e33 100644 --- a/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts +++ b/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts @@ -61,7 +61,7 @@ const DEFAULT_CONFIGURATION: Readonly = [ const DEFAULT_REGION = 'aws-eu-west-1'; const PROJECT_NAME_PREFIX = 'kibana-cypress-security-solution-ephemeral'; -const BASE_ENV_URL = 'https://global.qa.cld.elstc.co'; +const BASE_ENV_URL = 'https://console.qa.cld.elstc.co'; let log: ToolingLog; const API_HEADERS = Object.freeze({ 'kbn-xsrf': 'cypress-creds', @@ -571,6 +571,7 @@ ${JSON.stringify(cypressConfigFile, null, 2)} KIBANA_PASSWORD: credentials.password, CLOUD_SERVERLESS: true, + IS_SERVERLESS: true, }; if (process.env.DEBUG && !process.env.CI) { @@ -582,6 +583,7 @@ ${JSON.stringify(cypressConfigFile, null, 2)} ---------------------------------------------- `); } + process.env.TEST_CLOUD_HOST_NAME = new URL(BASE_ENV_URL).hostname; if (isOpen) { await cypress.open({ diff --git a/x-pack/test/security_solution_cypress/cypress/README.md b/x-pack/test/security_solution_cypress/cypress/README.md index 16a93f0c3b5d5..0fa6bae6e2164 100644 --- a/x-pack/test/security_solution_cypress/cypress/README.md +++ b/x-pack/test/security_solution_cypress/cypress/README.md @@ -304,8 +304,51 @@ Store the saved key on `~/.elastic/cloud.json` using the following format: } ``` -#### Known limitations -- Currently RBAC cannot be tested. +Store the email and password of the account you used to login in the QA Environment at the root directory of your Kibana project on `.ftr/role_users.json`, using the following format: + +```json +{ + "admin": { + "email": "", + "password": "" + } +} +``` + +#### Testing with different roles + +If you want to execute a test using Cypress on visual mode with MKI, you need to make sure you have the user created in your organization, and add it tot he `.ftr/role_users.json`: + +```json +{ + "admin": { + "email": "", + "password": "" + }, + "": { + "email": "", + "password": "" + } +} +``` + +As role names please use: +- admin +- detections_admin +- editor +- endpoint_operations_analyst +- endpoint_policy_manager +- none +- platform_engineer +- rule_author +- soc_manager +- t1_analyst +- t2_analyst +- t3_analyst +- threat_intelligence_analyst +- viewer + +The above should be the same used on the automation. #### PLIs diff --git a/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts b/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts index 3a1be3ed0221a..62aec8c49e787 100644 --- a/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts +++ b/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts @@ -7,6 +7,7 @@ import { defineCypressConfig } from '@kbn/cypress-config'; import { esArchiver } from './support/es_archiver'; +import { samlAuthentication } from './support/saml_auth'; // eslint-disable-next-line import/no-default-export export default defineCypressConfig({ @@ -39,6 +40,7 @@ export default defineCypressConfig({ specPattern: './cypress/e2e/**/*.cy.ts', setupNodeEvents(on, config) { esArchiver(on, config); + samlAuthentication(on, config); // eslint-disable-next-line @typescript-eslint/no-var-requires require('@cypress/grep/src/plugin')(config); return config; diff --git a/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless_qa.config.ts b/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless_qa.config.ts index 342c3da34bef6..c88faf0d9cfe3 100644 --- a/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless_qa.config.ts +++ b/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless_qa.config.ts @@ -7,6 +7,7 @@ import { defineCypressConfig } from '@kbn/cypress-config'; import { esArchiver } from './support/es_archiver'; +import { samlAuthentication } from './support/saml_auth'; // eslint-disable-next-line import/no-default-export export default defineCypressConfig({ @@ -41,6 +42,7 @@ export default defineCypressConfig({ specPattern: './cypress/e2e/**/*.cy.ts', setupNodeEvents(on, config) { esArchiver(on, config); + samlAuthentication(on, config); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // eslint-disable-next-line @typescript-eslint/no-var-requires require('@cypress/grep/src/plugin')(config); diff --git a/x-pack/test/security_solution_cypress/cypress/cypress_serverless.config.ts b/x-pack/test/security_solution_cypress/cypress/cypress_serverless.config.ts index b925e18a83478..b76c7ff22bcbc 100644 --- a/x-pack/test/security_solution_cypress/cypress/cypress_serverless.config.ts +++ b/x-pack/test/security_solution_cypress/cypress/cypress_serverless.config.ts @@ -7,6 +7,7 @@ import { defineCypressConfig } from '@kbn/cypress-config'; import { esArchiver } from './support/es_archiver'; +import { samlAuthentication } from './support/saml_auth'; // eslint-disable-next-line import/no-default-export export default defineCypressConfig({ @@ -31,6 +32,7 @@ export default defineCypressConfig({ experimentalMemoryManagement: true, setupNodeEvents(on, config) { esArchiver(on, config); + samlAuthentication(on, config); // eslint-disable-next-line @typescript-eslint/no-var-requires require('@cypress/grep/src/plugin')(config); return config; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts index 8891a835b1fd7..698a97df6b5d6 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts @@ -106,10 +106,10 @@ describe('Cases', { tags: ['@ess', '@serverless'] }, () => { ); cy.get(CASE_DETAILS_USERNAMES) .eq(REPORTER) - .should('have.text', Cypress.env(ELASTICSEARCH_USERNAME)); + .should('contain', Cypress.env(ELASTICSEARCH_USERNAME)); cy.get(CASE_DETAILS_USERNAMES) .eq(PARTICIPANTS) - .should('have.text', Cypress.env(ELASTICSEARCH_USERNAME)); + .should('contain', Cypress.env(ELASTICSEARCH_USERNAME)); cy.get(CASE_DETAILS_TAGS).should('have.text', expectedTags); EXPECTED_METRICS.forEach((metric) => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts index f857805462877..b0b1a11bc69e0 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts @@ -46,7 +46,8 @@ describe('Overview Page', { tags: ['@ess', '@serverless'] }, () => { }); }); - describe('Favorite Timelines', () => { + // https://github.com/elastic/kibana/issues/173168 + describe('Favorite Timelines', { tags: ['@brokenInServerless'] }, () => { it('should appear on overview page', () => { createTimeline(getTimeline()) .then((response) => response.body.data.persistTimeline.timeline.savedObjectId) diff --git a/x-pack/test/security_solution_cypress/cypress/screens/alerts.ts b/x-pack/test/security_solution_cypress/cypress/screens/alerts.ts index 0f1a513fc5d86..83de06466f251 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/alerts.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/alerts.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { IS_SERVERLESS, CLOUD_SERVERLESS } from '../env_var_names_constants'; import { getDataTestSubjectSelector } from '../helpers/common'; import { GLOBAL_FILTERS_CONTAINER } from './date_picker'; @@ -204,9 +205,15 @@ export const ALERT_ASSIGNEES_SELECT_PANEL = export const ALERT_ASSIGNEES_UPDATE_BUTTON = '[data-test-subj="securitySolutionAssigneesApplyButton"]'; -export const ALERT_USER_AVATAR = (assignee: string) => - `[data-test-subj="securitySolutionUsersAvatar-${assignee}"][title='${assignee}']`; +export const ALERT_USER_AVATAR = (assignee: string) => { + let expectedAssignee = assignee; + if (Cypress.env(IS_SERVERLESS) && !Cypress.env(CLOUD_SERVERLESS)) { + expectedAssignee = `test ${expectedAssignee}`; + } + + return `[data-test-subj^="securitySolutionUsersAvatar-"][title='${expectedAssignee}']`; +}; export const ALERT_AVATARS_PANEL = '[data-test-subj="securitySolutionUsersAvatarsPanel"]'; export const ALERT_ASIGNEES_COLUMN = diff --git a/x-pack/test/security_solution_cypress/cypress/support/es_archiver.ts b/x-pack/test/security_solution_cypress/cypress/support/es_archiver.ts index c9f271265a1d1..a5149b9df1e12 100644 --- a/x-pack/test/security_solution_cypress/cypress/support/es_archiver.ts +++ b/x-pack/test/security_solution_cypress/cypress/support/es_archiver.ts @@ -18,7 +18,7 @@ export const esArchiver = ( ): EsArchiver => { const log = new ToolingLog({ level: 'verbose', writeTo: process.stdout }); - const isSnapshotServerless = config.env.IS_SERVERLESS; + const isServerless = config.env.IS_SERVERLESS; const isCloudServerless = config.env.CLOUD_SERVERLESS; const serverlessCloudUser = { @@ -27,7 +27,7 @@ export const esArchiver = ( }; let authOverride; - if (!isSnapshotServerless) { + if (isServerless) { authOverride = isCloudServerless ? serverlessCloudUser : systemIndicesSuperuser; } diff --git a/x-pack/test/security_solution_cypress/cypress/support/saml_auth.ts b/x-pack/test/security_solution_cypress/cypress/support/saml_auth.ts new file mode 100644 index 0000000000000..0026f6c91ec27 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/support/saml_auth.ts @@ -0,0 +1,41 @@ +/* + * 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 { ToolingLog } from '@kbn/tooling-log'; + +import { SecurityRoleName } from '@kbn/security-solution-plugin/common/test'; +import { HostOptions, SamlSessionManager } from '@kbn/test'; + +export const samlAuthentication = async ( + on: Cypress.PluginEvents, + config: Cypress.PluginConfigOptions +): Promise => { + const log = new ToolingLog({ level: 'verbose', writeTo: process.stdout }); + + const kbnHost = config.env.KIBANA_URL || config.env.BASE_URL; + + const kbnUrl = new URL(kbnHost); + + const hostOptions: HostOptions = { + protocol: kbnUrl.protocol as 'http' | 'https', + hostname: kbnUrl.hostname, + port: parseInt(kbnUrl.port, 10), + username: config.env.ELASTICSEARCH_USERNAME, + password: config.env.ELASTICSEARCH_PASSWORD, + }; + + on('task', { + getSessionCookie: async (role: string | SecurityRoleName): Promise => { + const sessionManager = new SamlSessionManager({ + hostOptions, + log, + isCloud: config.env.CLOUD_SERVERLESS, + }); + return sessionManager.getSessionCookieForRole(role); + }, + }); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/support/setup_users.ts b/x-pack/test/security_solution_cypress/cypress/support/setup_users.ts index 02ebebb6c10ea..73d17b26ab93b 100644 --- a/x-pack/test/security_solution_cypress/cypress/support/setup_users.ts +++ b/x-pack/test/security_solution_cypress/cypress/support/setup_users.ts @@ -39,7 +39,7 @@ function createUser(username: string, password: string, roles: string[] = []): v password, roles, full_name: username, - email: '', + email: `${username}@elastic.co`, }; rootRequest({ diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/login.ts b/x-pack/test/security_solution_cypress/cypress/tasks/login.ts index fb2a93770f8e7..90c9d245c3bba 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/login.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/login.ts @@ -41,8 +41,22 @@ export const getEnvAuth = (role: SecurityRoleName): User => { }; export const login = (role?: SecurityRoleName): void => { - const user = role ? getEnvAuth(role) : defaultUser; - loginWithUser(user); + let testRole = ''; + + if (Cypress.env(IS_SERVERLESS)) { + if (!role) { + testRole = Cypress.env(CLOUD_SERVERLESS) ? 'admin' : 'system_indices_superuser'; + } else { + testRole = role; + } + cy.task('getSessionCookie', testRole).then((cookie) => { + cy.setCookie('sid', cookie as string); + }); + cy.visit('/'); + } else { + const user = role ? getEnvAuth(role) : defaultUser; + loginWithUser(user); + } }; export const loginWithUser = (user: User): void => { diff --git a/x-pack/test/security_solution_cypress/cypress/tsconfig.json b/x-pack/test/security_solution_cypress/cypress/tsconfig.json index 45b526793e98e..d6a08efd3073f 100644 --- a/x-pack/test/security_solution_cypress/cypress/tsconfig.json +++ b/x-pack/test/security_solution_cypress/cypress/tsconfig.json @@ -40,6 +40,6 @@ "@kbn/management-settings-ids", "@kbn/es-query", "@kbn/ml-plugin", - "@kbn/license-management-plugin" + "@kbn/license-management-plugin", ] }