diff --git a/.buildkite/ftr_oblt_stateful_configs.yml b/.buildkite/ftr_oblt_stateful_configs.yml index c64841fea3ca5..a6a23a2221e82 100644 --- a/.buildkite/ftr_oblt_stateful_configs.yml +++ b/.buildkite/ftr_oblt_stateful_configs.yml @@ -10,6 +10,7 @@ disabled: #FTR configs - x-pack/solutions/observability/plugins/uptime/e2e/config.ts - x-pack/solutions/observability/test/api_integration/config.ts + - x-pack/solutions/observability/test/functional/config.base.ts # Elastic Synthetics configs - x-pack/solutions/observability/plugins/uptime/e2e/uptime/synthetics_run.ts @@ -34,7 +35,6 @@ enabled: - x-pack/test/dataset_quality_api_integration/basic/config.ts - x-pack/test/functional/apps/observability_logs_explorer/config.ts - x-pack/test/functional/apps/dataset_quality/config.ts - - x-pack/test/functional/apps/slo/embeddables/config.ts - x-pack/test/functional/apps/uptime/config.ts - x-pack/test/observability_api_integration/basic/config.ts - x-pack/test/observability_api_integration/trial/config.ts @@ -45,6 +45,9 @@ enabled: - x-pack/solutions/observability/test/api_integration/profiling/cloud/config.ts - x-pack/test/functional/apps/apm/config.ts - x-pack/test/functional_with_es_ssl/apps/config.ts + - x-pack/solutions/observability/test/api_integration/apis/cases/config.ts + - x-pack/solutions/observability/test/functional/apps/slo/embeddables/config.ts + - x-pack/solutions/observability/test/api_integration/apis/security/config.ts # stateful configs that run deployment-agnostic tests - x-pack/solutions/observability/test/api_integration_deployment_agnostic/configs/stateful/oblt.stateful.config.ts - x-pack/solutions/observability/test/api_integration_deployment_agnostic/configs/stateful/oblt.apm.stateful.config.ts diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index c77dea94cab0e..92289a9c08c11 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -156,8 +156,6 @@ enabled: - x-pack/platform/test/alerting_api_integration/spaces_only/tests/alerting/group4/config_with_schedule_circuit_breaker.ts - x-pack/platform/test/alerting_api_integration/spaces_only/tests/actions/config.ts - x-pack/platform/test/alerting_api_integration/spaces_only/tests/action_task_params/config.ts - - x-pack/test/api_integration/apis/cases/config.ts - - x-pack/test/api_integration/apis/security/config.ts - x-pack/platform/test/banners_functional/config.ts - x-pack/platform/test/cases_api_integration/security_and_spaces/config_basic.ts - x-pack/platform/test/cases_api_integration/security_and_spaces/config_trial.ts @@ -362,6 +360,7 @@ enabled: - x-pack/platform/test/api_integration_deployment_agnostic/configs/stateful/platform.stateful.config.ts # configs migrated to the new Kibana architecture - x-pack/platform/test/api_integration/apis/aiops/config.ts + - x-pack/platform/test/api_integration/apis/cases/config.ts - x-pack/platform/test/api_integration/apis/cloud/config.ts - x-pack/platform/test/api_integration/apis/cloud/saml.config.ts - x-pack/platform/test/api_integration/apis/console/config.ts diff --git a/.buildkite/ftr_security_stateful_configs.yml b/.buildkite/ftr_security_stateful_configs.yml index ccf0bbb6a0705..8025bfd9f5574 100644 --- a/.buildkite/ftr_security_stateful_configs.yml +++ b/.buildkite/ftr_security_stateful_configs.yml @@ -120,3 +120,4 @@ enabled: - x-pack/solutions/security/test/cases_api_integration/security_and_spaces/config_trial.ts - x-pack/solutions/security/test/cases_api_integration/security_and_spaces/config_basic.ts - x-pack/solutions/security/test/api_integration_basic/config.ts + - x-pack/solutions/security/test/api_integration/apis/cases/config.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 573276ca63d7e..12b35f74df215 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1373,15 +1373,18 @@ x-pack/solutions/observability/plugins/observability/server/lib/esql_extensions # Observability UX management team ^/src/platform/test/api_integration/apis/suggestions @elastic/obs-ux-management-team # Assigned per https://github.com/elastic/kibana/pull/200950#discussion_r1853705079 /x-pack/test/api_integration/services/slo.ts @elastic/obs-ux-management-team -/x-pack/test/functional/services/slo @elastic/obs-ux-management-team -/x-pack/test/functional/apps/slo @elastic/obs-ux-management-team +/x-pack/solutions/observability/test/api_integration/services/slo.ts @elastic/obs-ux-management-team +/x-pack/solutions/observability/test/services/slo @elastic/obs-ux-management-team +/x-pack/solutions/observability/test/functional/apps/slo @elastic/obs-ux-management-team /x-pack/test/observability_api_integration @elastic/obs-ux-management-team # Assigned per https://github.com/elastic/kibana/pull/182243 /x-pack/test/functional/services/observability @elastic/obs-ux-management-team /x-pack/test/api_integration/apis/slos @elastic/obs-ux-management-team /x-pack/test/accessibility/apps/group1/uptime.ts @elastic/obs-ux-management-team /x-pack/test/accessibility/apps/group3/observability.ts @elastic/obs-ux-management-team +/x-pack/solutions/observability/test/functional/services/slo/ @elastic/obs-ux-management-team /x-pack/packages/observability/alert_details @elastic/obs-ux-management-team /x-pack/test/observability_functional @elastic/obs-ux-management-team +/x-pack/solutions/observability/test/api_integration/apis/security/ @elastic/obs-ux-management-team /x-pack/solutions/observability/plugins/infra/public/alerting @elastic/obs-ux-management-team /x-pack/solutions/observability/plugins/infra/server/lib/alerting @elastic/obs-ux-management-team /x-pack/solutions/observability/packages/kbn-observability-schema @elastic/obs-ux-management-team @@ -1825,6 +1828,10 @@ x-pack/platform/plugins/shared/ml/server/models/data_recognizer/modules/security /x-pack/test/api_integration/deployment_agnostic @elastic/appex-qa /x-pack/platform/test/functional/services/ml/api.ts @elastic/appex-qa # temporarily due to SKA tests relocation /x-pack/test/api_integration/deployment_agnostic/apis/ @elastic/appex-qa # temporarily due to SKA tests relocation +/x-pack/solutions/observability/test/functional/config.base.ts @elastic/appex-qa +/x-pack/solutions/observability/test/functional/ftr_provider_context.d.ts @elastic/appex-qa +/x-pack/solutions/observability/test/functional/page_objects/index.ts @elastic/appex-qa +/x-pack/solutions/observability/test/functional/services/index.ts @elastic/appex-qa # Core ^/src/platform/test/api_integration/fixtures/kbn_archiver/management/saved_objects/relationships.json @elastic/kibana-core @elastic/kibana-data-discovery @@ -2012,7 +2019,6 @@ x-pack/platform/plugins/private/cloud_integrations/cloud_full_story/server/confi /x-pack/test/accessibility/apps/group1/roles.ts @elastic/kibana-security /x-pack/test/accessibility/apps/group1/spaces.ts @elastic/kibana-security /x-pack/test/accessibility/apps/group1/users.ts @elastic/kibana-security -/x-pack/test/api_integration/apis/security/ @elastic/kibana-security /x-pack/platform/test/api_integration/apis/security/ @elastic/kibana-security /x-pack/platform/test/api_integration/apis/spaces/ @elastic/kibana-security /x-pack/platform/test/api_integration_basic/apis/security/ @elastic/kibana-security @@ -2088,7 +2094,9 @@ x-pack/platform/plugins/private/cloud_integrations/cloud_full_story/server/confi /x-pack/solutions/security/test/cases_api_integration/ @elastic/kibana-cases /x-pack/platform/test/functional/services/cases/ @elastic/kibana-cases /x-pack/platform/test/functional_with_es_ssl/apps/cases/ @elastic/kibana-cases -/x-pack/test/api_integration/apis/cases/ @elastic/kibana-cases +/x-pack/platform/test/api_integration/apis/cases/ @elastic/kibana-cases +/x-pack/solutions/observability/test/api_integration/apis/cases/ @elastic/response-ops @elastic/kibana-cases +/x-pack/solutions/security/test/api_integration/apis/cases/ @elastic/response-ops @elastic/kibana-cases /x-pack/test_serverless/functional/test_suites/observability/cases @elastic/kibana-cases /x-pack/test_serverless/functional/test_suites/search/cases/ @elastic/kibana-cases /x-pack/test_serverless/functional/test_suites/security/ftr/cases/ @elastic/kibana-cases diff --git a/x-pack/test/api_integration/apis/cases/bulk_get_user_profiles.ts b/x-pack/platform/test/api_integration/apis/cases/bulk_get_user_profiles.ts similarity index 80% rename from x-pack/test/api_integration/apis/cases/bulk_get_user_profiles.ts rename to x-pack/platform/test/api_integration/apis/cases/bulk_get_user_profiles.ts index 5a250f039cd5b..ad7f25ac0b71a 100644 --- a/x-pack/test/api_integration/apis/cases/bulk_get_user_profiles.ts +++ b/x-pack/platform/test/api_integration/apis/cases/bulk_get_user_profiles.ts @@ -7,21 +7,16 @@ import expect from '@kbn/expect'; import { APP_ID as CASES_APP_ID } from '@kbn/cases-plugin/common/constants'; -import { APP_ID as SECURITY_SOLUTION_APP_ID } from '@kbn/security-solution-plugin/common/constants'; -import { observabilityFeatureId as OBSERVABILITY_APP_ID } from '@kbn/observability-plugin/common'; - -import { deleteAllCaseItems } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api'; +import { deleteAllCaseItems } from '../../../cases_api_integration/common/lib/api'; import { bulkGetUserProfiles, suggestUserProfiles, -} from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api/user_profiles'; +} from '../../../cases_api_integration/common/lib/api/user_profiles'; import type { FtrProviderContext } from '../../ftr_provider_context'; import { casesAllUser, casesReadUser, - obsCasesAllUser, obsCasesReadUser, - secAllUser, secReadCasesReadUser, secAllCasesNoneUser, secNoneUser, @@ -36,11 +31,7 @@ export default ({ getService }: FtrProviderContext): void => { await deleteAllCaseItems(es); }); - for (const { user, owner } of [ - { user: secAllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesAllUser, owner: CASES_APP_ID }, - { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, - ]) { + for (const { user, owner } of [{ user: casesAllUser, owner: CASES_APP_ID }]) { it(`User ${ user.username } with roles(s) ${user.roles.join()} can bulk get valid user profiles`, async () => { diff --git a/x-pack/test/api_integration/apis/cases/common/roles.ts b/x-pack/platform/test/api_integration/apis/cases/common/roles.ts similarity index 99% rename from x-pack/test/api_integration/apis/cases/common/roles.ts rename to x-pack/platform/test/api_integration/apis/cases/common/roles.ts index 51e40c76123d9..b117c07c42fbd 100644 --- a/x-pack/test/api_integration/apis/cases/common/roles.ts +++ b/x-pack/platform/test/api_integration/apis/cases/common/roles.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { Role } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/authentication/types'; +import type { Role } from '../../../../cases_api_integration/common/lib/authentication/types'; /** * Roles for Cases in Security Solution diff --git a/x-pack/test/api_integration/apis/cases/common/users.ts b/x-pack/platform/test/api_integration/apis/cases/common/users.ts similarity index 98% rename from x-pack/test/api_integration/apis/cases/common/users.ts rename to x-pack/platform/test/api_integration/apis/cases/common/users.ts index 27ed43515576b..c00f1aae2cdb6 100644 --- a/x-pack/test/api_integration/apis/cases/common/users.ts +++ b/x-pack/platform/test/api_integration/apis/cases/common/users.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { User } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/authentication/types'; +import type { User } from '../../../../cases_api_integration/common/lib/authentication/types'; import { casesAll, casesV2All, diff --git a/x-pack/test/api_integration/apis/cases/config.ts b/x-pack/platform/test/api_integration/apis/cases/config.ts similarity index 100% rename from x-pack/test/api_integration/apis/cases/config.ts rename to x-pack/platform/test/api_integration/apis/cases/config.ts diff --git a/x-pack/test/api_integration/apis/cases/files.ts b/x-pack/platform/test/api_integration/apis/cases/files.ts similarity index 97% rename from x-pack/test/api_integration/apis/cases/files.ts rename to x-pack/platform/test/api_integration/apis/cases/files.ts index 9baf90402492f..4b502cbbe4a8e 100644 --- a/x-pack/test/api_integration/apis/cases/files.ts +++ b/x-pack/platform/test/api_integration/apis/cases/files.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import type { BaseFilesClient } from '@kbn/shared-ux-file-types'; -import type { User } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/authentication/types'; +import type { User } from '../../../cases_api_integration/common/lib/authentication/types'; import { createFile, uploadFile, @@ -18,12 +18,12 @@ import { getFileById, deleteAllFilesForKind, deleteFileForFileKind, -} from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api'; +} from '../../../cases_api_integration/common/lib/api'; import { CASES_FILE_KIND, OBSERVABILITY_FILE_KIND, SECURITY_SOLUTION_FILE_KIND, -} from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/constants'; +} from '../../../cases_api_integration/common/lib/constants'; import type { FtrProviderContext } from '../../ftr_provider_context'; import { casesAllUser, diff --git a/x-pack/platform/test/api_integration/apis/cases/index.ts b/x-pack/platform/test/api_integration/apis/cases/index.ts new file mode 100644 index 0000000000000..e9dd73ba7773e --- /dev/null +++ b/x-pack/platform/test/api_integration/apis/cases/index.ts @@ -0,0 +1,38 @@ +/* + * 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 { + createUsersAndRoles, + deleteUsersAndRoles, +} from '../../../cases_api_integration/common/lib/authentication'; + +import { loginUsers } from '../../../cases_api_integration/common/lib/api/user_profiles'; +import { casesAllUser, obsCasesAllUser, secAllUser, users } from './common/users'; +import { roles } from './common/roles'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile, getService }: FtrProviderContext) { + describe('cases', function () { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + before(async () => { + await createUsersAndRoles(getService, users, roles); + await loginUsers({ + supertest: supertestWithoutAuth, + users: [casesAllUser, secAllUser, obsCasesAllUser], + }); + }); + + after(async () => { + await deleteUsersAndRoles(getService, users, roles); + }); + + loadTestFile(require.resolve('./privileges')); + loadTestFile(require.resolve('./bulk_get_user_profiles')); + loadTestFile(require.resolve('./files')); + }); +} diff --git a/x-pack/platform/test/api_integration/apis/cases/privileges.ts b/x-pack/platform/test/api_integration/apis/cases/privileges.ts new file mode 100644 index 0000000000000..ea02a8e682256 --- /dev/null +++ b/x-pack/platform/test/api_integration/apis/cases/privileges.ts @@ -0,0 +1,356 @@ +/* + * 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 expect from '@kbn/expect'; +import { APP_ID as CASES_APP_ID } from '@kbn/cases-plugin/common/constants'; +import { AttachmentType } from '@kbn/cases-plugin/common'; +import type { + CaseStatuses, + UserCommentAttachmentPayload, +} from '@kbn/cases-plugin/common/types/domain'; + +import { + createCase, + deleteAllCaseItems, + deleteCases, + getCase, + createComment, + updateCaseStatus, + updateCaseAssignee, +} from '../../../cases_api_integration/common/lib/api'; +import { getPostCaseRequest } from '../../../cases_api_integration/common/lib/mock'; +import { suggestUserProfiles } from '../../../cases_api_integration/common/lib/api/user_profiles'; +import { + casesAllUser, + casesV2AllUser, + casesV3AllUser, + casesV3NoAssigneeUser, + casesV3ReadAndAssignUser, + casesNoDeleteUser, + casesOnlyDeleteUser, + casesV2NoReopenWithCreateCommentUser, + casesV2NoCreateCommentWithReopenUser, +} from './common/users'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext): void => { + describe('feature privilege', () => { + const es = getService('es'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const supertest = getService('supertest'); + + afterEach(async () => { + await deleteAllCaseItems(es); + }); + + for (const { user, owner } of [ + { user: casesAllUser, owner: CASES_APP_ID }, + { user: casesV2AllUser, owner: CASES_APP_ID }, + { user: casesNoDeleteUser, owner: CASES_APP_ID }, + { user: casesV3AllUser, owner: CASES_APP_ID }, + { user: casesV3NoAssigneeUser, owner: CASES_APP_ID }, + ]) { + it(`User ${user.username} with role(s) ${user.roles.join()} can create a case`, async () => { + await createCase(supertest, getPostCaseRequest({ owner }), 200, { + user, + space: null, + }); + }); + } + + for (const { user, owner } of [ + { user: casesAllUser, owner: CASES_APP_ID }, + { user: casesV2AllUser, owner: CASES_APP_ID }, + { user: casesNoDeleteUser, owner: CASES_APP_ID }, + { user: casesV3AllUser, owner: CASES_APP_ID }, + { user: casesV3NoAssigneeUser, owner: CASES_APP_ID }, + ]) { + it(`User ${user.username} with role(s) ${user.roles.join()} can get a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const retrievedCase = await getCase({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + expect(caseInfo.owner).to.eql(retrievedCase.owner); + }); + } + + for (const { user, owner } of [ + { user: casesOnlyDeleteUser, owner: CASES_APP_ID }, + { user: casesV3NoAssigneeUser, owner: CASES_APP_ID }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} cannot create a case`, async () => { + await createCase(supertestWithoutAuth, getPostCaseRequest({ owner }), 403, { + user, + space: null, + }); + }); + } + + for (const { user, owner } of [{ user: casesOnlyDeleteUser, owner: CASES_APP_ID }]) { + it(`User ${user.username} with role(s) ${user.roles.join()} cannot get a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + + await getCase({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 403, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner } of [ + { user: casesAllUser, owner: CASES_APP_ID }, + { user: casesV2AllUser, owner: CASES_APP_ID }, + { user: casesOnlyDeleteUser, owner: CASES_APP_ID }, + { user: casesV3AllUser, owner: CASES_APP_ID }, + { user: casesV3NoAssigneeUser, owner: CASES_APP_ID }, + ]) { + it(`User ${user.username} with role(s) ${user.roles.join()} can delete a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await deleteCases({ + caseIDs: [caseInfo.id], + supertest: supertestWithoutAuth, + expectedHttpCode: 204, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner } of [{ user: casesNoDeleteUser, owner: CASES_APP_ID }]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} cannot delete a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await deleteCases({ + caseIDs: [caseInfo.id], + supertest: supertestWithoutAuth, + expectedHttpCode: 403, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner } of [ + { user: casesAllUser, owner: CASES_APP_ID }, + { user: casesV2AllUser, owner: CASES_APP_ID }, + { user: casesV3AllUser, owner: CASES_APP_ID }, + ]) { + it(`User ${user.username} with role(s) ${user.roles.join()} can reopen a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'closed' as CaseStatuses, + version: caseInfo.version, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + const updatedCase = await getCase({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'open' as CaseStatuses, + version: updatedCase.version, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner, userWithFullPerms } of [ + { + user: casesV2NoCreateCommentWithReopenUser, + owner: CASES_APP_ID, + userWithFullPerms: casesV3AllUser, + }, + { user: casesV3NoAssigneeUser, owner: CASES_APP_ID, userWithFullPerms: casesV3AllUser }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} can reopen a case, if it's closed`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'closed' as CaseStatuses, + version: caseInfo.version, + expectedHttpCode: 200, + auth: { user: userWithFullPerms, space: null }, + }); + + const updatedCase = await getCase({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'open' as CaseStatuses, + version: updatedCase.version, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner, userWithFullPerms } of [ + { + user: casesV2NoReopenWithCreateCommentUser, + owner: CASES_APP_ID, + userWithFullPerms: casesV3AllUser, + }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} CANNOT reopen a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'closed' as CaseStatuses, + version: caseInfo.version, + expectedHttpCode: 200, + auth: { user: userWithFullPerms, space: null }, + }); + + const updatedCase = await getCase({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'open' as CaseStatuses, + version: updatedCase.version, + expectedHttpCode: 403, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner } of [ + { user: casesAllUser, owner: CASES_APP_ID }, + { user: casesV2AllUser, owner: CASES_APP_ID }, + { user: casesV2NoReopenWithCreateCommentUser, owner: CASES_APP_ID }, + { user: casesV3AllUser, owner: CASES_APP_ID }, + { user: casesV3NoAssigneeUser, owner: CASES_APP_ID }, + ]) { + it(`User ${user.username} with role(s) ${user.roles.join()} can add comments`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const comment: UserCommentAttachmentPayload = { + comment: 'test', + owner, + type: AttachmentType.user, + }; + await createComment({ + params: comment, + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner, userWithFullPerms } of [ + { user: casesV3NoAssigneeUser, owner: CASES_APP_ID, userWithFullPerms: casesV3AllUser }, + { + user: casesV2NoCreateCommentWithReopenUser, + owner: CASES_APP_ID, + userWithFullPerms: casesV3AllUser, + }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} CANNOT change assignee`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const [{ uid: assigneeId }] = await suggestUserProfiles({ + supertest: supertestWithoutAuth, + req: { name: userWithFullPerms.username, owners: [owner], size: 1 }, + auth: { user: userWithFullPerms, space: null }, + }); + await updateCaseAssignee({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + assigneeId, + expectedHttpCode: 403, + auth: { user, space: null }, + version: caseInfo.version, + }); + }); + } + + for (const { user, owner } of [ + { user: casesV3ReadAndAssignUser, owner: CASES_APP_ID }, + { user: casesAllUser, owner: CASES_APP_ID }, + { user: casesV2AllUser, owner: CASES_APP_ID }, + + { user: casesV3AllUser, owner: CASES_APP_ID }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} CAN change assignee`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const [{ uid: assigneeId }] = await suggestUserProfiles({ + supertest: supertestWithoutAuth, + req: { name: user.username, owners: [owner], size: 1 }, + auth: { user, space: null }, + }); + await updateCaseAssignee({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + assigneeId, + expectedHttpCode: 200, + version: caseInfo.version, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner } of [ + { user: casesV2NoCreateCommentWithReopenUser, owner: CASES_APP_ID }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} CANNOT add comments`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const comment: UserCommentAttachmentPayload = { + comment: 'test', + owner, + type: AttachmentType.user, + }; + await createComment({ + params: comment, + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 403, + auth: { user, space: null }, + }); + }); + } + }); +}; diff --git a/x-pack/solutions/observability/test/api_integration/apis/cases/bulk_get_user_profiles.ts b/x-pack/solutions/observability/test/api_integration/apis/cases/bulk_get_user_profiles.ts new file mode 100644 index 0000000000000..138a47ce04004 --- /dev/null +++ b/x-pack/solutions/observability/test/api_integration/apis/cases/bulk_get_user_profiles.ts @@ -0,0 +1,52 @@ +/* + * 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 expect from '@kbn/expect'; +import { observabilityFeatureId as OBSERVABILITY_APP_ID } from '@kbn/observability-plugin/common'; + +import { deleteAllCaseItems } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api'; +import { + bulkGetUserProfiles, + suggestUserProfiles, +} from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api/user_profiles'; +import { obsCasesAllUser } from '@kbn/test-suites-xpack-platform/api_integration/apis/cases/common/users'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext): void => { + describe('bulk_get_user_profiles', () => { + const es = getService('es'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + afterEach(async () => { + await deleteAllCaseItems(es); + }); + + for (const { user, owner } of [{ user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }]) { + it(`User ${ + user.username + } with roles(s) ${user.roles.join()} can bulk get valid user profiles`, async () => { + const suggestedProfiles = await suggestUserProfiles({ + supertest: supertestWithoutAuth, + req: { name: user.username, owners: [owner], size: 1 }, + auth: { user, space: null }, + }); + + const profiles = await bulkGetUserProfiles({ + supertest: supertestWithoutAuth, + req: { + uids: suggestedProfiles.map((suggestedProfile) => suggestedProfile.uid), + dataPath: 'avatar', + }, + auth: { user, space: null }, + }); + + expect(profiles.length).to.be(1); + expect(profiles[0].user.username).to.eql(user.username); + }); + } + }); +}; diff --git a/x-pack/solutions/observability/test/api_integration/apis/cases/config.ts b/x-pack/solutions/observability/test/api_integration/apis/cases/config.ts new file mode 100644 index 0000000000000..73613f45a7692 --- /dev/null +++ b/x-pack/solutions/observability/test/api_integration/apis/cases/config.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseIntegrationTestsConfig = await readConfigFile(require.resolve('../../config.ts')); + + return { + ...baseIntegrationTestsConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/x-pack/test/api_integration/apis/cases/index.ts b/x-pack/solutions/observability/test/api_integration/apis/cases/index.ts similarity index 83% rename from x-pack/test/api_integration/apis/cases/index.ts rename to x-pack/solutions/observability/test/api_integration/apis/cases/index.ts index 33b4933dbf67c..bd4daadfc4d6a 100644 --- a/x-pack/test/api_integration/apis/cases/index.ts +++ b/x-pack/solutions/observability/test/api_integration/apis/cases/index.ts @@ -11,8 +11,13 @@ import { } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/authentication'; import { loginUsers } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api/user_profiles'; -import { casesAllUser, obsCasesAllUser, secAllUser, users } from './common/users'; -import { roles } from './common/roles'; +import { + casesAllUser, + obsCasesAllUser, + secAllUser, + users, +} from '@kbn/test-suites-xpack-platform/api_integration/apis/cases/common/users'; +import { roles } from '@kbn/test-suites-xpack-platform/api_integration/apis/cases/common/roles'; import type { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile, getService }: FtrProviderContext) { @@ -34,6 +39,5 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) { loadTestFile(require.resolve('./privileges')); loadTestFile(require.resolve('./suggest_user_profiles')); loadTestFile(require.resolve('./bulk_get_user_profiles')); - loadTestFile(require.resolve('./files')); }); } diff --git a/x-pack/solutions/observability/test/api_integration/apis/cases/privileges.ts b/x-pack/solutions/observability/test/api_integration/apis/cases/privileges.ts new file mode 100644 index 0000000000000..c9d98253503d7 --- /dev/null +++ b/x-pack/solutions/observability/test/api_integration/apis/cases/privileges.ts @@ -0,0 +1,350 @@ +/* + * 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 expect from '@kbn/expect'; +import { AttachmentType } from '@kbn/cases-plugin/common'; +import type { + CaseStatuses, + UserCommentAttachmentPayload, +} from '@kbn/cases-plugin/common/types/domain'; +import { observabilityFeatureId as OBSERVABILITY_APP_ID } from '@kbn/observability-plugin/common'; + +import { + createCase, + deleteAllCaseItems, + deleteCases, + getCase, + createComment, + updateCaseStatus, + updateCaseAssignee, +} from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api'; +import { getPostCaseRequest } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/mock'; +import { suggestUserProfiles } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api/user_profiles'; +import { + obsCasesAllUser, + obsCasesV2AllUser, + obsCasesV3AllUser, + obsCasesNoDeleteUser, + obsCasesOnlyDeleteUser, + obsCasesV2NoReopenWithCreateCommentUser, + obsCasesV2NoCreateCommentWithReopenUser, +} from '@kbn/test-suites-xpack-platform/api_integration/apis/cases/common/users'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext): void => { + describe('feature privilege', () => { + const es = getService('es'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const supertest = getService('supertest'); + + afterEach(async () => { + await deleteAllCaseItems(es); + }); + + for (const { user, owner } of [ + { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesNoDeleteUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, + ]) { + it(`User ${user.username} with role(s) ${user.roles.join()} can create a case`, async () => { + await createCase(supertest, getPostCaseRequest({ owner }), 200, { + user, + space: null, + }); + }); + } + + for (const { user, owner } of [ + { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesNoDeleteUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, + ]) { + it(`User ${user.username} with role(s) ${user.roles.join()} can get a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const retrievedCase = await getCase({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + expect(caseInfo.owner).to.eql(retrievedCase.owner); + }); + } + + for (const { user, owner } of [{ user: obsCasesOnlyDeleteUser, owner: OBSERVABILITY_APP_ID }]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} cannot create a case`, async () => { + await createCase(supertestWithoutAuth, getPostCaseRequest({ owner }), 403, { + user, + space: null, + }); + }); + } + + for (const { user, owner } of [{ user: obsCasesOnlyDeleteUser, owner: OBSERVABILITY_APP_ID }]) { + it(`User ${user.username} with role(s) ${user.roles.join()} cannot get a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + + await getCase({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 403, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner } of [ + { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesOnlyDeleteUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, + ]) { + it(`User ${user.username} with role(s) ${user.roles.join()} can delete a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await deleteCases({ + caseIDs: [caseInfo.id], + supertest: supertestWithoutAuth, + expectedHttpCode: 204, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner } of [{ user: obsCasesNoDeleteUser, owner: OBSERVABILITY_APP_ID }]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} cannot delete a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await deleteCases({ + caseIDs: [caseInfo.id], + supertest: supertestWithoutAuth, + expectedHttpCode: 403, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner } of [ + { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, + ]) { + it(`User ${user.username} with role(s) ${user.roles.join()} can reopen a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'closed' as CaseStatuses, + version: caseInfo.version, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + const updatedCase = await getCase({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'open' as CaseStatuses, + version: updatedCase.version, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner, userWithFullPerms } of [ + { + user: obsCasesV2NoCreateCommentWithReopenUser, + owner: OBSERVABILITY_APP_ID, + userWithFullPerms: obsCasesV3AllUser, + }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} can reopen a case, if it's closed`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'closed' as CaseStatuses, + version: caseInfo.version, + expectedHttpCode: 200, + auth: { user: userWithFullPerms, space: null }, + }); + + const updatedCase = await getCase({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'open' as CaseStatuses, + version: updatedCase.version, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner, userWithFullPerms } of [ + { + user: obsCasesV2NoReopenWithCreateCommentUser, + owner: OBSERVABILITY_APP_ID, + userWithFullPerms: obsCasesV3AllUser, + }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} CANNOT reopen a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'closed' as CaseStatuses, + version: caseInfo.version, + expectedHttpCode: 200, + auth: { user: userWithFullPerms, space: null }, + }); + + const updatedCase = await getCase({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'open' as CaseStatuses, + version: updatedCase.version, + expectedHttpCode: 403, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner } of [ + { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV2NoReopenWithCreateCommentUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, + ]) { + it(`User ${user.username} with role(s) ${user.roles.join()} can add comments`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const comment: UserCommentAttachmentPayload = { + comment: 'test', + owner, + type: AttachmentType.user, + }; + await createComment({ + params: comment, + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 200, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner, userWithFullPerms } of [ + { + user: obsCasesV2NoCreateCommentWithReopenUser, + owner: OBSERVABILITY_APP_ID, + userWithFullPerms: obsCasesV3AllUser, + }, + { + user: obsCasesOnlyDeleteUser, + owner: OBSERVABILITY_APP_ID, + userWithFullPerms: obsCasesAllUser, + }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} CANNOT change assignee`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const [{ uid: assigneeId }] = await suggestUserProfiles({ + supertest: supertestWithoutAuth, + req: { name: userWithFullPerms.username, owners: [owner], size: 1 }, + auth: { user: userWithFullPerms, space: null }, + }); + await updateCaseAssignee({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + assigneeId, + expectedHttpCode: 403, + auth: { user, space: null }, + version: caseInfo.version, + }); + }); + } + + for (const { user, owner } of [ + { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} CAN change assignee`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const [{ uid: assigneeId }] = await suggestUserProfiles({ + supertest: supertestWithoutAuth, + req: { name: user.username, owners: [owner], size: 1 }, + auth: { user, space: null }, + }); + await updateCaseAssignee({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + assigneeId, + expectedHttpCode: 200, + version: caseInfo.version, + auth: { user, space: null }, + }); + }); + } + + for (const { user, owner } of [ + { user: obsCasesV2NoCreateCommentWithReopenUser, owner: OBSERVABILITY_APP_ID }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} CANNOT add comments`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const comment: UserCommentAttachmentPayload = { + comment: 'test', + owner, + type: AttachmentType.user, + }; + await createComment({ + params: comment, + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 403, + auth: { user, space: null }, + }); + }); + } + }); +}; diff --git a/x-pack/solutions/observability/test/api_integration/apis/cases/suggest_user_profiles.ts b/x-pack/solutions/observability/test/api_integration/apis/cases/suggest_user_profiles.ts new file mode 100644 index 0000000000000..c60b026383170 --- /dev/null +++ b/x-pack/solutions/observability/test/api_integration/apis/cases/suggest_user_profiles.ts @@ -0,0 +1,60 @@ +/* + * 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 expect from '@kbn/expect'; +import { observabilityFeatureId as OBSERVABILITY_APP_ID } from '@kbn/observability-plugin/common'; + +import { deleteAllCaseItems } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api'; +import { suggestUserProfiles } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api/user_profiles'; +import { + obsCasesAllUser, + obsCasesOnlyDeleteUser, + obsCasesReadUser, +} from '@kbn/test-suites-xpack-platform/api_integration/apis/cases/common/users'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext): void => { + describe('suggest_user_profiles', () => { + const es = getService('es'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + afterEach(async () => { + await deleteAllCaseItems(es); + }); + + for (const { user, searchTerm, owner } of [ + { user: obsCasesAllUser, searchTerm: obsCasesAllUser.username, owner: OBSERVABILITY_APP_ID }, + { user: obsCasesReadUser, searchTerm: obsCasesAllUser.username, owner: OBSERVABILITY_APP_ID }, + ]) { + it(`User ${ + user.username + } with roles(s) ${user.roles.join()} can retrieve user profile suggestions`, async () => { + const profiles = await suggestUserProfiles({ + supertest: supertestWithoutAuth, + req: { name: searchTerm, owners: [owner], size: 1 }, + auth: { user, space: null }, + }); + + expect(profiles.length).to.be(1); + expect(profiles[0].user.username).to.eql(searchTerm); + }); + } + + for (const { user, owner } of [{ user: obsCasesOnlyDeleteUser, owner: OBSERVABILITY_APP_ID }]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} cannot retrieve user profile suggestions because they lack privileges`, async () => { + await suggestUserProfiles({ + supertest: supertestWithoutAuth, + req: { name: user.username, owners: [owner] }, + auth: { user, space: null }, + expectedHttpCode: 403, + }); + }); + } + }); +}; diff --git a/x-pack/test/api_integration/apis/security/api_keys.ts b/x-pack/solutions/observability/test/api_integration/apis/security/api_keys.ts similarity index 100% rename from x-pack/test/api_integration/apis/security/api_keys.ts rename to x-pack/solutions/observability/test/api_integration/apis/security/api_keys.ts diff --git a/x-pack/test/api_integration/apis/security/config.ts b/x-pack/solutions/observability/test/api_integration/apis/security/config.ts similarity index 100% rename from x-pack/test/api_integration/apis/security/config.ts rename to x-pack/solutions/observability/test/api_integration/apis/security/config.ts diff --git a/x-pack/test/api_integration/apis/security/index.ts b/x-pack/solutions/observability/test/api_integration/apis/security/index.ts similarity index 100% rename from x-pack/test/api_integration/apis/security/index.ts rename to x-pack/solutions/observability/test/api_integration/apis/security/index.ts diff --git a/x-pack/solutions/observability/test/api_integration/services/index.ts b/x-pack/solutions/observability/test/api_integration/services/index.ts index 38558929b24ee..bad31631c647d 100644 --- a/x-pack/solutions/observability/test/api_integration/services/index.ts +++ b/x-pack/solutions/observability/test/api_integration/services/index.ts @@ -7,8 +7,10 @@ import { services as platformServices } from '@kbn/test-suites-xpack-platform/api_integration/services'; import { InfraLogViewsServiceProvider } from './infra_log_views'; +import { SloApiProvider } from './slo'; export const services = { ...platformServices, infraLogViews: InfraLogViewsServiceProvider, + sloApi: SloApiProvider, }; diff --git a/x-pack/solutions/observability/test/api_integration/services/slo.ts b/x-pack/solutions/observability/test/api_integration/services/slo.ts new file mode 100644 index 0000000000000..177d431e46ccb --- /dev/null +++ b/x-pack/solutions/observability/test/api_integration/services/slo.ts @@ -0,0 +1,153 @@ +/* + * 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 { SUMMARY_DESTINATION_INDEX_NAME } from '@kbn/slo-plugin/common/constants'; +import { TOTAL_INDEX_PRIVILEGE_SET_EDITOR } from '@kbn/slo-plugin/server/services/get_diagnosis'; +import { + CreateSLOInput, + fetchHistoricalSummaryParamsSchema, + FetchHistoricalSummaryResponse, + FindSLODefinitionsResponse, +} from '@kbn/slo-schema'; +import * as t from 'io-ts'; +import type { Client } from '@elastic/elasticsearch'; +import type { + AggregationsAggregate, + SearchResponse, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import pRetry from 'p-retry'; +import { FtrProviderContext } from '../ftr_provider_context'; + +async function waitForIndexToBeEmpty({ + esClient, + indexName, +}: { + esClient: Client; + indexName: string; +}): Promise>> { + return pRetry( + async () => { + const response = await esClient.search({ index: indexName, rest_total_hits_as_int: true }); + // @ts-expect-error upgrade typescript v5.1.6 + if (response.hits.total != null && response.hits.total > 0) { + throw new Error(`Found ${response.hits.total} docs.`); + } + return response; + }, + { retries: 10 } + ); +} + +type FetchHistoricalSummaryParams = t.OutputOf< + typeof fetchHistoricalSummaryParamsSchema.props.body +>; + +export function SloApiProvider({ getService }: FtrProviderContext) { + const supertest = getService('supertestWithoutAuth'); + const esClient = getService('es'); + const security = getService('security'); + + return { + async createUser() { + const username = 'slo_editor'; + const roleName = 'slo_editor'; + try { + await security.user.delete(username); + await security.role.delete(roleName); + } catch (error) { + const status = error.response.status; + if (status !== 404) { + throw error; + } + } + const password = 'changeme'; + + await security.role.create(roleName, { + elasticsearch: { + indices: [ + { + names: ['.slo-observability.*'], + privileges: TOTAL_INDEX_PRIVILEGE_SET_EDITOR, + }, + ], + }, + }); + + await security.user.create(username, { + password, + roles: [roleName, 'editor'], + }); + }, + async create(params: CreateSLOInput) { + const slo = await supertest + .post('/api/observability/slos') + .set('kbn-xsrf', 'true') + .auth('slo_editor', 'changeme') + .send(params) + .expect(200); + + return slo; + }, + async reset(id: string) { + const response = supertest + .post(`/api/observability/slos/${id}/_reset`) + .auth('slo_editor', 'changeme') + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + return response; + }, + async getDefinitions({ search }: { search?: string } = {}) { + const url = `/api/observability/slos/_definitions${search ? `?search=${search}` : ''}`; + const response = await supertest + .get(url) + .set('kbn-xsrf', 'true') + .auth('slo_editor', 'changeme') + .send() + .expect(200); + + return response; + }, + async delete(id: string) { + await supertest + .delete(`/api/observability/slos/${id}`) + .set('kbn-xsrf', 'true') + .auth('slo_editor', 'changeme') + .send() + .expect(204); + }, + async deleteAllSLOs() { + const response = await supertest + .get(`/api/observability/slos/_definitions`) + .set('kbn-xsrf', 'true') + .auth('slo_editor', 'changeme') + .send() + .expect(200); + for (const { id } of (response.body as FindSLODefinitionsResponse).results) { + await supertest + .delete(`/api/observability/slos/${id}`) + .set('kbn-xsrf', 'true') + .auth('slo_editor', 'changeme') + .send() + .expect(204); + } + await waitForIndexToBeEmpty({ esClient, indexName: SUMMARY_DESTINATION_INDEX_NAME }); + }, + async fetchHistoricalSummary( + params: FetchHistoricalSummaryParams + ): Promise { + const { body } = await supertest + .post(`/internal/observability/slos/_historical_summary`) + .set('kbn-xsrf', 'foo') + .auth('slo_editor', 'changeme') + .set('elastic-api-version', '1') + .send(params); + + return body; + }, + }; +} diff --git a/x-pack/test/functional/apps/slo/embeddables/config.ts b/x-pack/solutions/observability/test/functional/apps/slo/embeddables/config.ts similarity index 95% rename from x-pack/test/functional/apps/slo/embeddables/config.ts rename to x-pack/solutions/observability/test/functional/apps/slo/embeddables/config.ts index f7fe54a56831d..6bf77b884411e 100644 --- a/x-pack/test/functional/apps/slo/embeddables/config.ts +++ b/x-pack/solutions/observability/test/functional/apps/slo/embeddables/config.ts @@ -8,7 +8,7 @@ import { FtrConfigProviderContext } from '@kbn/test'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { - const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.ts')); return { ...functionalConfig.getAll(), diff --git a/x-pack/test/functional/apps/slo/embeddables/overview_embeddable.ts b/x-pack/solutions/observability/test/functional/apps/slo/embeddables/overview_embeddable.ts similarity index 83% rename from x-pack/test/functional/apps/slo/embeddables/overview_embeddable.ts rename to x-pack/solutions/observability/test/functional/apps/slo/embeddables/overview_embeddable.ts index adf2339323fe2..7e85528843ef7 100644 --- a/x-pack/test/functional/apps/slo/embeddables/overview_embeddable.ts +++ b/x-pack/solutions/observability/test/functional/apps/slo/embeddables/overview_embeddable.ts @@ -6,35 +6,41 @@ */ import { cleanup } from '@kbn/infra-forge'; -import { loadTestData } from '../../../../api_integration/apis/slos/helper/load_test_data'; -import { SloEsClient } from '../../../../api_integration/apis/slos/helper/es'; -import { sloData } from '../../../../api_integration/apis/slos/fixtures/create_slo'; +import { loadTestData } from '../../../services/slo/helper/load_test_data'; +import { sloData } from '../../../services/slo/fixtures/create_slo'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'dashboard']); const esClient = getService('es'); - const sloEsClient = new SloEsClient(esClient); const logger = getService('log'); - const slo = getService('slo'); + const sloApi = getService('sloApi'); const sloUi = getService('sloUi'); const dashboardAddPanel = getService('dashboardAddPanel'); describe('OverviewEmbeddable', function () { before(async () => { await loadTestData(getService); - await slo.createUser(); - await slo.deleteAllSLOs(); - await slo.create(sloData); + await sloApi.createUser(); + await sloApi.deleteAllSLOs(); + await sloApi.create(sloData); await PageObjects.dashboard.navigateToApp(); await PageObjects.dashboard.clickNewDashboard(); await PageObjects.dashboard.switchToEditMode(); }); after(async () => { - await slo.deleteAllSLOs(); + await sloApi.deleteAllSLOs(); await cleanup({ esClient, logger }); - await sloEsClient.deleteTestSourceData(); + try { + await esClient.deleteByQuery({ + index: 'kbn-data-forge-fake_hosts*', + query: { term: { 'system.network.name': 'eth1' } }, + }); + } catch (e) { + // eslint-disable-next-line no-console + console.warn('SLO api integration test data not found'); + } }); describe('Single SLO', function () { diff --git a/x-pack/solutions/observability/test/functional/config.base.ts b/x-pack/solutions/observability/test/functional/config.base.ts new file mode 100644 index 0000000000000..175f7ab4dab18 --- /dev/null +++ b/x-pack/solutions/observability/test/functional/config.base.ts @@ -0,0 +1,38 @@ +/* + * 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 { ScoutTestRunConfigCategory } from '@kbn/scout-info'; +import { FtrConfigProviderContext } from '@kbn/test'; +import { services } from './services'; +import { pageObjects } from './page_objects'; + +export async function getApiIntegrationConfig({ readConfigFile }: FtrConfigProviderContext) { + const xPackPlatformApiIntegrationTestsConfig = await readConfigFile( + require.resolve('@kbn/test-suites-xpack-platform/functional/config.base') + ); + + return { + services, + pageObjects, + testConfigCategory: ScoutTestRunConfigCategory.UI_TEST, + servers: xPackPlatformApiIntegrationTestsConfig.get('servers'), + security: xPackPlatformApiIntegrationTestsConfig.get('security'), + junit: { + reportName: 'X-Pack Observability Functional UI Tests', + }, + kbnTestServer: { + ...xPackPlatformApiIntegrationTestsConfig.get('kbnTestServer'), + serverArgs: [...xPackPlatformApiIntegrationTestsConfig.get('kbnTestServer.serverArgs')], + }, + esTestCluster: { + ...xPackPlatformApiIntegrationTestsConfig.get('esTestCluster'), + serverArgs: [...xPackPlatformApiIntegrationTestsConfig.get('esTestCluster.serverArgs')], + }, + }; +} + +export default getApiIntegrationConfig; diff --git a/x-pack/solutions/observability/test/functional/ftr_provider_context.d.ts b/x-pack/solutions/observability/test/functional/ftr_provider_context.d.ts new file mode 100644 index 0000000000000..6092c6668a3dc --- /dev/null +++ b/x-pack/solutions/observability/test/functional/ftr_provider_context.d.ts @@ -0,0 +1,13 @@ +/* + * 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 { GenericFtrProviderContext } from '@kbn/test'; + +import { services } from './services'; +import { pageObjects } from './page_objects'; + +export type FtrProviderContext = GenericFtrProviderContext; diff --git a/x-pack/solutions/observability/test/functional/page_objects/index.ts b/x-pack/solutions/observability/test/functional/page_objects/index.ts new file mode 100644 index 0000000000000..0165c27b2400e --- /dev/null +++ b/x-pack/solutions/observability/test/functional/page_objects/index.ts @@ -0,0 +1,12 @@ +/* + * 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 platformPageObjects } from '@kbn/test-suites-xpack-platform/functional/page_objects'; + +export const pageObjects = { + ...platformPageObjects, +}; diff --git a/x-pack/solutions/observability/test/functional/services/index.ts b/x-pack/solutions/observability/test/functional/services/index.ts new file mode 100644 index 0000000000000..46003e76fd96e --- /dev/null +++ b/x-pack/solutions/observability/test/functional/services/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 { services as platformServices } from '@kbn/test-suites-xpack-platform/functional/services'; +import { services as obltApiServices } from '../../api_integration/services'; +import { SloUiServiceProvider } from './slo'; + +export const services = { + ...platformServices, + ...obltApiServices, + sloUi: SloUiServiceProvider, +}; diff --git a/x-pack/test/functional/services/slo/common.ts b/x-pack/solutions/observability/test/functional/services/slo/common.ts similarity index 98% rename from x-pack/test/functional/services/slo/common.ts rename to x-pack/solutions/observability/test/functional/services/slo/common.ts index c18ad0eeec9fd..a4986581c0df4 100644 --- a/x-pack/test/functional/services/slo/common.ts +++ b/x-pack/solutions/observability/test/functional/services/slo/common.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { sloData } from '../../../api_integration/apis/slos/fixtures/create_slo'; +import { sloData } from './fixtures/create_slo'; const OVERVIEW_MODE_SELECTOR = 'sloOverviewModeSelector'; const SLO_CONFIRM_BUTTON = 'sloConfirmButton'; diff --git a/x-pack/test/api_integration/apis/slos/fixtures/create_slo.ts b/x-pack/solutions/observability/test/functional/services/slo/fixtures/create_slo.ts similarity index 100% rename from x-pack/test/api_integration/apis/slos/fixtures/create_slo.ts rename to x-pack/solutions/observability/test/functional/services/slo/fixtures/create_slo.ts diff --git a/x-pack/test/api_integration/apis/slos/helper/load_test_data.ts b/x-pack/solutions/observability/test/functional/services/slo/helper/load_test_data.ts similarity index 100% rename from x-pack/test/api_integration/apis/slos/helper/load_test_data.ts rename to x-pack/solutions/observability/test/functional/services/slo/helper/load_test_data.ts diff --git a/x-pack/test/api_integration/apis/slos/helper/wait_for_index_state.ts b/x-pack/solutions/observability/test/functional/services/slo/helper/wait_for_index_state.ts similarity index 100% rename from x-pack/test/api_integration/apis/slos/helper/wait_for_index_state.ts rename to x-pack/solutions/observability/test/functional/services/slo/helper/wait_for_index_state.ts diff --git a/x-pack/test/functional/services/slo/index.ts b/x-pack/solutions/observability/test/functional/services/slo/index.ts similarity index 100% rename from x-pack/test/functional/services/slo/index.ts rename to x-pack/solutions/observability/test/functional/services/slo/index.ts diff --git a/x-pack/solutions/observability/test/tsconfig.json b/x-pack/solutions/observability/test/tsconfig.json index b304820aefd4a..9a038c7e6eb71 100644 --- a/x-pack/solutions/observability/test/tsconfig.json +++ b/x-pack/solutions/observability/test/tsconfig.json @@ -78,5 +78,7 @@ "@kbn/es-errors", "@kbn/content-packs-schema", "@kbn/server-route-repository-utils", + "@kbn/cases-plugin", + "@kbn/infra-forge", ] } diff --git a/x-pack/solutions/security/test/api_integration/apis/cases/bulk_get_user_profiles.ts b/x-pack/solutions/security/test/api_integration/apis/cases/bulk_get_user_profiles.ts new file mode 100644 index 0000000000000..047bb8198838d --- /dev/null +++ b/x-pack/solutions/security/test/api_integration/apis/cases/bulk_get_user_profiles.ts @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { APP_ID as SECURITY_SOLUTION_APP_ID } from '@kbn/security-solution-plugin/common/constants'; +import { deleteAllCaseItems } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api'; +import { + bulkGetUserProfiles, + suggestUserProfiles, +} from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api/user_profiles'; +import { secAllUser } from '@kbn/test-suites-xpack-platform/api_integration/apis/cases/common/users'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext): void => { + describe('bulk_get_user_profiles', () => { + const es = getService('es'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + afterEach(async () => { + await deleteAllCaseItems(es); + }); + + for (const { user, owner } of [{ user: secAllUser, owner: SECURITY_SOLUTION_APP_ID }]) { + it(`User ${ + user.username + } with roles(s) ${user.roles.join()} can bulk get valid user profiles`, async () => { + const suggestedProfiles = await suggestUserProfiles({ + supertest: supertestWithoutAuth, + req: { name: user.username, owners: [owner], size: 1 }, + auth: { user, space: null }, + }); + + const profiles = await bulkGetUserProfiles({ + supertest: supertestWithoutAuth, + req: { + uids: suggestedProfiles.map((suggestedProfile) => suggestedProfile.uid), + dataPath: 'avatar', + }, + auth: { user, space: null }, + }); + + expect(profiles.length).to.be(1); + expect(profiles[0].user.username).to.eql(user.username); + }); + } + }); +}; diff --git a/x-pack/solutions/security/test/api_integration/apis/cases/config.ts b/x-pack/solutions/security/test/api_integration/apis/cases/config.ts new file mode 100644 index 0000000000000..73613f45a7692 --- /dev/null +++ b/x-pack/solutions/security/test/api_integration/apis/cases/config.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseIntegrationTestsConfig = await readConfigFile(require.resolve('../../config.ts')); + + return { + ...baseIntegrationTestsConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/x-pack/solutions/security/test/api_integration/apis/cases/index.ts b/x-pack/solutions/security/test/api_integration/apis/cases/index.ts new file mode 100644 index 0000000000000..bd4daadfc4d6a --- /dev/null +++ b/x-pack/solutions/security/test/api_integration/apis/cases/index.ts @@ -0,0 +1,43 @@ +/* + * 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 { + createUsersAndRoles, + deleteUsersAndRoles, +} from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/authentication'; + +import { loginUsers } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api/user_profiles'; +import { + casesAllUser, + obsCasesAllUser, + secAllUser, + users, +} from '@kbn/test-suites-xpack-platform/api_integration/apis/cases/common/users'; +import { roles } from '@kbn/test-suites-xpack-platform/api_integration/apis/cases/common/roles'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile, getService }: FtrProviderContext) { + describe('cases', function () { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + before(async () => { + await createUsersAndRoles(getService, users, roles); + await loginUsers({ + supertest: supertestWithoutAuth, + users: [casesAllUser, secAllUser, obsCasesAllUser], + }); + }); + + after(async () => { + await deleteUsersAndRoles(getService, users, roles); + }); + + loadTestFile(require.resolve('./privileges')); + loadTestFile(require.resolve('./suggest_user_profiles')); + loadTestFile(require.resolve('./bulk_get_user_profiles')); + }); +} diff --git a/x-pack/test/api_integration/apis/cases/privileges.ts b/x-pack/solutions/security/test/api_integration/apis/cases/privileges.ts similarity index 70% rename from x-pack/test/api_integration/apis/cases/privileges.ts rename to x-pack/solutions/security/test/api_integration/apis/cases/privileges.ts index 4662bf7443a2d..579c4dc112962 100644 --- a/x-pack/test/api_integration/apis/cases/privileges.ts +++ b/x-pack/solutions/security/test/api_integration/apis/cases/privileges.ts @@ -6,15 +6,12 @@ */ import expect from '@kbn/expect'; -import { APP_ID as CASES_APP_ID } from '@kbn/cases-plugin/common/constants'; import { AttachmentType } from '@kbn/cases-plugin/common'; import type { CaseStatuses, UserCommentAttachmentPayload, } from '@kbn/cases-plugin/common/types/domain'; import { APP_ID as SECURITY_SOLUTION_APP_ID } from '@kbn/security-solution-plugin/common/constants'; -import { observabilityFeatureId as OBSERVABILITY_APP_ID } from '@kbn/observability-plugin/common'; - import { createCase, deleteAllCaseItems, @@ -27,18 +24,6 @@ import { import { getPostCaseRequest } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/mock'; import { suggestUserProfiles } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api/user_profiles'; import { - casesAllUser, - casesV2AllUser, - casesV3AllUser, - casesV3NoAssigneeUser, - casesV3ReadAndAssignUser, - casesNoDeleteUser, - casesOnlyDeleteUser, - obsCasesAllUser, - obsCasesV2AllUser, - obsCasesV3AllUser, - obsCasesNoDeleteUser, - obsCasesOnlyDeleteUser, secAllCasesNoDeleteUser, secAllCasesNoneUser, secAllCasesOnlyDeleteUser, @@ -50,13 +35,9 @@ import { secReadCasesNoneUser, secReadCasesReadUser, secReadUser, - casesV2NoReopenWithCreateCommentUser, - casesV2NoCreateCommentWithReopenUser, - obsCasesV2NoReopenWithCreateCommentUser, - obsCasesV2NoCreateCommentWithReopenUser, secCasesV2NoReopenWithCreateCommentUser, secCasesV2NoCreateCommentWithReopenUser, -} from './common/users'; +} from '@kbn/test-suites-xpack-platform/api_integration/apis/cases/common/users'; import type { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getService }: FtrProviderContext): void => { @@ -73,16 +54,7 @@ export default ({ getService }: FtrProviderContext): void => { { user: secAllUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secCasesV2AllUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secReadCasesAllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesAllUser, owner: CASES_APP_ID }, - { user: casesV2AllUser, owner: CASES_APP_ID }, - { user: casesNoDeleteUser, owner: CASES_APP_ID }, - { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesNoDeleteUser, owner: OBSERVABILITY_APP_ID }, { user: secCasesV3AllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesV3AllUser, owner: CASES_APP_ID }, - { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, - { user: casesV3NoAssigneeUser, owner: CASES_APP_ID }, ]) { it(`User ${user.username} with role(s) ${user.roles.join()} can create a case`, async () => { await createCase(supertest, getPostCaseRequest({ owner }), 200, { @@ -97,16 +69,7 @@ export default ({ getService }: FtrProviderContext): void => { { user: secReadCasesAllUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secReadCasesReadUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secReadUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesAllUser, owner: CASES_APP_ID }, - { user: casesV2AllUser, owner: CASES_APP_ID }, - { user: casesNoDeleteUser, owner: CASES_APP_ID }, - { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesNoDeleteUser, owner: OBSERVABILITY_APP_ID }, { user: secCasesV3AllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesV3AllUser, owner: CASES_APP_ID }, - { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, - { user: casesV3NoAssigneeUser, owner: CASES_APP_ID }, ]) { it(`User ${user.username} with role(s) ${user.roles.join()} can get a case`, async () => { const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); @@ -127,9 +90,6 @@ export default ({ getService }: FtrProviderContext): void => { { user: secReadCasesReadUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secReadUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secReadCasesNoneUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesOnlyDeleteUser, owner: CASES_APP_ID }, - { user: obsCasesOnlyDeleteUser, owner: OBSERVABILITY_APP_ID }, - { user: casesV3NoAssigneeUser, owner: CASES_APP_ID }, ]) { it(`User ${ user.username @@ -145,8 +105,6 @@ export default ({ getService }: FtrProviderContext): void => { { user: secAllCasesNoneUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secReadCasesNoneUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secAllCasesOnlyDeleteUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesOnlyDeleteUser, owner: CASES_APP_ID }, - { user: obsCasesOnlyDeleteUser, owner: OBSERVABILITY_APP_ID }, ]) { it(`User ${user.username} with role(s) ${user.roles.join()} cannot get a case`, async () => { const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); @@ -164,16 +122,7 @@ export default ({ getService }: FtrProviderContext): void => { { user: secAllUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secCasesV2AllUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secAllCasesOnlyDeleteUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesAllUser, owner: CASES_APP_ID }, - { user: casesV2AllUser, owner: CASES_APP_ID }, - { user: casesOnlyDeleteUser, owner: CASES_APP_ID }, - { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesOnlyDeleteUser, owner: OBSERVABILITY_APP_ID }, { user: secCasesV3AllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesV3AllUser, owner: CASES_APP_ID }, - { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, - { user: casesV3NoAssigneeUser, owner: CASES_APP_ID }, ]) { it(`User ${user.username} with role(s) ${user.roles.join()} can delete a case`, async () => { const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); @@ -189,8 +138,6 @@ export default ({ getService }: FtrProviderContext): void => { for (const { user, owner } of [ { user: secAllCasesReadUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secAllCasesNoDeleteUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesNoDeleteUser, owner: CASES_APP_ID }, - { user: obsCasesNoDeleteUser, owner: OBSERVABILITY_APP_ID }, ]) { it(`User ${ user.username @@ -208,13 +155,7 @@ export default ({ getService }: FtrProviderContext): void => { for (const { user, owner } of [ { user: secAllUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secCasesV2AllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, - { user: casesAllUser, owner: CASES_APP_ID }, - { user: casesV2AllUser, owner: CASES_APP_ID }, { user: secCasesV3AllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesV3AllUser, owner: CASES_APP_ID }, - { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, ]) { it(`User ${user.username} with role(s) ${user.roles.join()} can reopen a case`, async () => { const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); @@ -246,22 +187,11 @@ export default ({ getService }: FtrProviderContext): void => { } for (const { user, owner, userWithFullPerms } of [ - { - user: casesV2NoCreateCommentWithReopenUser, - owner: CASES_APP_ID, - userWithFullPerms: casesV3AllUser, - }, - { - user: obsCasesV2NoCreateCommentWithReopenUser, - owner: OBSERVABILITY_APP_ID, - userWithFullPerms: obsCasesV3AllUser, - }, { user: secCasesV2NoCreateCommentWithReopenUser, owner: SECURITY_SOLUTION_APP_ID, userWithFullPerms: secCasesV3AllUser, }, - { user: casesV3NoAssigneeUser, owner: CASES_APP_ID, userWithFullPerms: casesV3AllUser }, ]) { it(`User ${ user.username @@ -295,16 +225,6 @@ export default ({ getService }: FtrProviderContext): void => { } for (const { user, owner, userWithFullPerms } of [ - { - user: casesV2NoReopenWithCreateCommentUser, - owner: CASES_APP_ID, - userWithFullPerms: casesV3AllUser, - }, - { - user: obsCasesV2NoReopenWithCreateCommentUser, - owner: OBSERVABILITY_APP_ID, - userWithFullPerms: obsCasesV3AllUser, - }, { user: secCasesV2NoReopenWithCreateCommentUser, owner: SECURITY_SOLUTION_APP_ID, @@ -345,17 +265,9 @@ export default ({ getService }: FtrProviderContext): void => { for (const { user, owner } of [ { user: secAllUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secCasesV2AllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, - { user: casesAllUser, owner: CASES_APP_ID }, - { user: casesV2AllUser, owner: CASES_APP_ID }, - { user: casesV2NoReopenWithCreateCommentUser, owner: CASES_APP_ID }, - { user: obsCasesV2NoReopenWithCreateCommentUser, owner: OBSERVABILITY_APP_ID }, + { user: secCasesV2NoReopenWithCreateCommentUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secCasesV3AllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesV3AllUser, owner: CASES_APP_ID }, - { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, - { user: casesV3NoAssigneeUser, owner: CASES_APP_ID }, ]) { it(`User ${user.username} with role(s) ${user.roles.join()} can add comments`, async () => { const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); @@ -375,29 +287,12 @@ export default ({ getService }: FtrProviderContext): void => { } for (const { user, owner, userWithFullPerms } of [ - { user: casesV3NoAssigneeUser, owner: CASES_APP_ID, userWithFullPerms: casesV3AllUser }, - { - user: casesV2NoCreateCommentWithReopenUser, - owner: CASES_APP_ID, - userWithFullPerms: casesV3AllUser, - }, - { - user: obsCasesV2NoCreateCommentWithReopenUser, - owner: OBSERVABILITY_APP_ID, - userWithFullPerms: obsCasesV3AllUser, - }, { user: secCasesV2NoCreateCommentWithReopenUser, owner: SECURITY_SOLUTION_APP_ID, userWithFullPerms: secCasesV3AllUser, }, { user: secReadUser, owner: SECURITY_SOLUTION_APP_ID, userWithFullPerms: secAllUser }, - { user: casesOnlyDeleteUser, owner: CASES_APP_ID, userWithFullPerms: casesAllUser }, - { - user: obsCasesOnlyDeleteUser, - owner: OBSERVABILITY_APP_ID, - userWithFullPerms: obsCasesAllUser, - }, ]) { it(`User ${ user.username @@ -420,19 +315,11 @@ export default ({ getService }: FtrProviderContext): void => { } for (const { user, owner } of [ - { user: casesV3ReadAndAssignUser, owner: CASES_APP_ID }, { user: secAllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesAllUser, owner: CASES_APP_ID }, - { user: casesV2AllUser, owner: CASES_APP_ID }, + { user: secCasesV2AllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, { user: secCasesV2AllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: obsCasesAllUser, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, { user: secCasesV3AllUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesV3AllUser, owner: CASES_APP_ID }, - { user: obsCasesV3AllUser, owner: OBSERVABILITY_APP_ID }, ]) { it(`User ${ user.username @@ -455,8 +342,6 @@ export default ({ getService }: FtrProviderContext): void => { } for (const { user, owner } of [ - { user: casesV2NoCreateCommentWithReopenUser, owner: CASES_APP_ID }, - { user: obsCasesV2NoCreateCommentWithReopenUser, owner: OBSERVABILITY_APP_ID }, { user: secCasesV2NoCreateCommentWithReopenUser, owner: SECURITY_SOLUTION_APP_ID }, ]) { it(`User ${ diff --git a/x-pack/test/api_integration/apis/cases/suggest_user_profiles.ts b/x-pack/solutions/security/test/api_integration/apis/cases/suggest_user_profiles.ts similarity index 64% rename from x-pack/test/api_integration/apis/cases/suggest_user_profiles.ts rename to x-pack/solutions/security/test/api_integration/apis/cases/suggest_user_profiles.ts index 37507623aa98b..e5ae00fe9a25c 100644 --- a/x-pack/test/api_integration/apis/cases/suggest_user_profiles.ts +++ b/x-pack/solutions/security/test/api_integration/apis/cases/suggest_user_profiles.ts @@ -6,24 +6,15 @@ */ import expect from '@kbn/expect'; -import { APP_ID as CASES_APP_ID, MAX_SUGGESTED_PROFILES } from '@kbn/cases-plugin/common/constants'; import { APP_ID as SECURITY_SOLUTION_APP_ID } from '@kbn/security-solution-plugin/common/constants'; -import { observabilityFeatureId as OBSERVABILITY_APP_ID } from '@kbn/observability-plugin/common'; - import { deleteAllCaseItems } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api'; import { suggestUserProfiles } from '@kbn/test-suites-xpack-platform/cases_api_integration/common/lib/api/user_profiles'; -import type { FtrProviderContext } from '../../ftr_provider_context'; import { - casesAllUser, - casesOnlyDeleteUser, - casesReadUser, - obsCasesAllUser, - obsCasesOnlyDeleteUser, - obsCasesReadUser, secAllCasesNoneUser, secAllCasesReadUser, secAllUser, -} from './common/users'; +} from '@kbn/test-suites-xpack-platform/api_integration/apis/cases/common/users'; +import type { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getService }: FtrProviderContext): void => { describe('suggest_user_profiles', () => { @@ -41,10 +32,6 @@ export default ({ getService }: FtrProviderContext): void => { searchTerm: secAllUser.username, owner: SECURITY_SOLUTION_APP_ID, }, - { user: casesAllUser, searchTerm: casesAllUser.username, owner: CASES_APP_ID }, - { user: casesReadUser, searchTerm: casesAllUser.username, owner: CASES_APP_ID }, - { user: obsCasesAllUser, searchTerm: obsCasesAllUser.username, owner: OBSERVABILITY_APP_ID }, - { user: obsCasesReadUser, searchTerm: obsCasesAllUser.username, owner: OBSERVABILITY_APP_ID }, ]) { it(`User ${ user.username @@ -62,8 +49,6 @@ export default ({ getService }: FtrProviderContext): void => { for (const { user, owner } of [ { user: secAllCasesNoneUser, owner: SECURITY_SOLUTION_APP_ID }, - { user: casesOnlyDeleteUser, owner: CASES_APP_ID }, - { user: obsCasesOnlyDeleteUser, owner: OBSERVABILITY_APP_ID }, ]) { it(`User ${ user.username @@ -76,20 +61,5 @@ export default ({ getService }: FtrProviderContext): void => { }); }); } - - describe('errors', () => { - it('400s when size parameter is not valid', async () => { - await suggestUserProfiles({ - supertest: supertestWithoutAuth, - req: { - name: casesAllUser.username, - owners: [CASES_APP_ID], - size: MAX_SUGGESTED_PROFILES + 1, - }, - auth: { user: casesAllUser, space: null }, - expectedHttpCode: 400, - }); - }); - }); }); }; diff --git a/x-pack/test/api_integration/services/slo.ts b/x-pack/test/api_integration/services/slo.ts index 9244ad7ee00d7..177d431e46ccb 100644 --- a/x-pack/test/api_integration/services/slo.ts +++ b/x-pack/test/api_integration/services/slo.ts @@ -13,9 +13,34 @@ import { FindSLODefinitionsResponse, } from '@kbn/slo-schema'; import * as t from 'io-ts'; -import { waitForIndexToBeEmpty } from '../apis/slos/helper/wait_for_index_state'; +import type { Client } from '@elastic/elasticsearch'; +import type { + AggregationsAggregate, + SearchResponse, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import pRetry from 'p-retry'; import { FtrProviderContext } from '../ftr_provider_context'; +async function waitForIndexToBeEmpty({ + esClient, + indexName, +}: { + esClient: Client; + indexName: string; +}): Promise>> { + return pRetry( + async () => { + const response = await esClient.search({ index: indexName, rest_total_hits_as_int: true }); + // @ts-expect-error upgrade typescript v5.1.6 + if (response.hits.total != null && response.hits.total > 0) { + throw new Error(`Found ${response.hits.total} docs.`); + } + return response; + }, + { retries: 10 } + ); +} + type FetchHistoricalSummaryParams = t.OutputOf< typeof fetchHistoricalSummaryParamsSchema.props.body >; diff --git a/x-pack/test/functional/services/index.ts b/x-pack/test/functional/services/index.ts index 6e7f8225d4edb..213d266bc34de 100644 --- a/x-pack/test/functional/services/index.ts +++ b/x-pack/test/functional/services/index.ts @@ -67,7 +67,6 @@ import { InfraSourceConfigurationFormProvider } from './infra_source_configurati import { LogsUiProvider } from './logs_ui'; import { ObservabilityProvider } from './observability'; import { DataStreamProvider } from './data_stream'; -import { SloUiServiceProvider } from './slo'; // define the name and providers for services that should be // available to your tests. If you don't specify anything here // only the built-in services will be available @@ -130,5 +129,4 @@ export const services = { dataStreams: DataStreamProvider, slo: kibanaXPackApiIntegrationServices.slo, dataViewApi: kibanaXPackApiIntegrationServices.dataViewApi, - sloUi: SloUiServiceProvider, }; diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 0416bf00d50c2..c6faa1f8c9cf9 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -48,7 +48,6 @@ "@kbn/transform-plugin", "@kbn/upgrade-assistant-plugin", "@kbn/remote-clusters-plugin", - "@kbn/synthetics-plugin", "@kbn/global-search-test-plugin", "@kbn/test", "@kbn/repo-info", @@ -82,7 +81,6 @@ "@kbn/stdio-dev-helpers", "@kbn/security-api-integration-helpers", "@kbn/discover-plugin", - "@kbn/shared-ux-file-types", "@kbn/guided-onboarding-plugin", "@kbn/field-formats-plugin", "@kbn/ml-anomaly-utils", @@ -105,7 +103,6 @@ "@kbn/slo-schema", "@kbn/typed-react-router-config", "@kbn/ftr-common-functional-ui-services", - "@kbn/infra-forge", "@kbn/slo-plugin", "@kbn/observability-ai-assistant-app-plugin", "@kbn/search-types",