diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index ddcfffafc7c79..09b2feced215b 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -343,9 +343,7 @@ enabled: - x-pack/test/security_functional/expired_session.config.ts - x-pack/test/session_view/basic/config.ts - x-pack/test/spaces_api_integration/security_and_spaces/config_basic.ts - - x-pack/test/spaces_api_integration/security_and_spaces/copy_to_space_config_basic.ts - x-pack/test/spaces_api_integration/security_and_spaces/config_trial.ts - - x-pack/test/spaces_api_integration/security_and_spaces/copy_to_space_config_trial.ts - x-pack/test/spaces_api_integration/spaces_only/config.ts - x-pack/test/task_manager_claimer_update_by_query/config.ts - x-pack/test/ui_capabilities/security_and_spaces/config.ts diff --git a/.buildkite/ftr_security_serverless_configs.yml b/.buildkite/ftr_security_serverless_configs.yml index eca2fc6bdf0a6..7337addf34ac9 100644 --- a/.buildkite/ftr_security_serverless_configs.yml +++ b/.buildkite/ftr_security_serverless_configs.yml @@ -126,3 +126,5 @@ enabled: - x-pack/test/security_solution_endpoint/configs/serverless.integrations.config.ts # serverless config files that run deployment-agnostic tests - x-pack/test/api_integration/deployment_agnostic/configs/serverless/security.serverless.config.ts + - x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/serverless.config.ts + - x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/serverless.copy_to_space.config.ts diff --git a/.buildkite/ftr_security_stateful_configs.yml b/.buildkite/ftr_security_stateful_configs.yml index d9953cfe1e727..5ccc1911c992b 100644 --- a/.buildkite/ftr_security_stateful_configs.yml +++ b/.buildkite/ftr_security_stateful_configs.yml @@ -106,3 +106,8 @@ enabled: - x-pack/test/automatic_import_api_integration/apis/config_basic.ts - x-pack/test/automatic_import_api_integration/apis/config_graphs.ts - x-pack/test/security_solution_api_integration/test_suites/asset_inventory/entity_store/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/config.ts + - x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.config_basic.ts + - x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.config_trial.ts + - x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.copy_to_space.config_trial.ts + - x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.copy_to_space.config_basic.ts diff --git a/packages/kbn-es/src/stateful_resources/roles.yml b/packages/kbn-es/src/stateful_resources/roles.yml index 49ae1fafad958..2bf66f99859d3 100644 --- a/packages/kbn-es/src/stateful_resources/roles.yml +++ b/packages/kbn-es/src/stateful_resources/roles.yml @@ -128,3 +128,4 @@ system_indices_superuser: privileges: ['*'] resources: ['*'] run_as: ['*'] + diff --git a/src/dev/eslint/types.eslint.config.template.cjs b/src/dev/eslint/types.eslint.config.template.cjs index ef7572d5626b2..4ad2391055f5d 100644 --- a/src/dev/eslint/types.eslint.config.template.cjs +++ b/src/dev/eslint/types.eslint.config.template.cjs @@ -34,5 +34,11 @@ module.exports = { '@typescript-eslint/no-floating-promises': 'error', }, }, + { + files: ['*spaces_api_integration/common/services/basic_auth_supertest.ts'], + rules: { + '@typescript-eslint/no-floating-promises': 'off', + }, + }, ], }; diff --git a/x-pack/test/spaces_api_integration/common/config.ts b/x-pack/test/spaces_api_integration/common/config.ts index 466b34b65ce84..324a3607e3513 100644 --- a/x-pack/test/spaces_api_integration/common/config.ts +++ b/x-pack/test/spaces_api_integration/common/config.ts @@ -10,6 +10,8 @@ import path from 'path'; import { REPO_ROOT } from '@kbn/repo-info'; import type { FtrConfigProviderContext } from '@kbn/test'; +import { services } from './services'; + interface CreateTestConfigOptions { license: string; disabledPlugins?: string[]; @@ -45,6 +47,8 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) kibanaServer: config.kibana.functional.get('services.kibanaServer'), spaces: config.xpack.api.get('services.spaces'), usageAPI: config.xpack.api.get('services.usageAPI'), + roleScopedSupertest: services.roleScopedSupertest, + samlAuth: () => {}, }, junit: { reportName: 'X-Pack Spaces API Integration Tests -- ' + name, diff --git a/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json index fcf6043a30012..546ed5401b244 100644 --- a/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json +++ b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json @@ -68,11 +68,11 @@ { "type": "_doc", "value": { - "id": "isolatedtype:my_isolated_object", + "id": "url:my_isolated_object", "index": ".kibana", "source": { "namespace": "space_2", - "type": "isolatedtype", + "type": "url", "updated_at": "2017-09-21T18:49:16.270Z" }, "type": "_doc" @@ -82,11 +82,11 @@ { "type": "_doc", "value": { - "id": "isolatedtype:my_isolated_object", + "id": "url:my_isolated_object", "index": ".kibana", "source": { "namespace": "space_1", - "type": "isolatedtype", + "type": "url", "updated_at": "2017-09-21T18:49:16.270Z" }, "type": "_doc" @@ -96,10 +96,10 @@ { "type": "_doc", "value": { - "id": "isolatedtype:my_isolated_object", + "id": "url:my_isolated_object", "index": ".kibana", "source": { - "type": "isolatedtype", + "type": "url", "updated_at": "2017-09-21T18:49:16.270Z" }, "type": "_doc" @@ -411,16 +411,16 @@ { "type": "doc", "value": { - "id": "sharedtype:default_only", - "index": ".kibana", + "id": "index-pattern:default_only", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in one space" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["default"], "references": [ - { "type": "sharedtype", "id": "each_space", "name": "refname" } + { "type": "index-pattern", "id": "each_space", "name": "refname" } ], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -431,7 +431,7 @@ { "type": "doc", "value": { - "id": "legacy-url-alias:default:sharedtype:space_1_only", + "id": "legacy-url-alias:default:index-pattern:space_1_only", "index": ".kibana", "source": { "type": "legacy-url-alias", @@ -439,7 +439,7 @@ "legacy-url-alias": { "sourceId": "space_1_only", "targetNamespace": "default", - "targetType": "sharedtype", + "targetType": "index-pattern", "targetId": "default_only" }, "coreMigrationVersion": "8.8.0", @@ -451,16 +451,16 @@ { "type": "doc", "value": { - "id": "sharedtype:space_1_only", - "index": ".kibana", + "id": "index-pattern:space_1_only", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in one space" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["space_1"], "references": [ - { "type": "sharedtype", "id": "each_space", "name": "refname" } + { "type": "index-pattern", "id": "each_space", "name": "refname" } ], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -471,14 +471,14 @@ { "type": "doc", "value": { - "id": "sharedtype:space_1_only_matching_origin", - "index": ".kibana", + "id": "index-pattern:space_1_only_matching_origin", + "index": ".kibana_analytics", "source": { "originId": "space_1_only", - "sharedtype": { + "index-pattern": { "title": "This object only exists to test the second assertion for spacesWithMatchingOrigins in get_shareable_references" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["other_space"], "references": [], "updated_at": "2017-09-21T18:59:16.270Z" @@ -490,16 +490,16 @@ { "type": "doc", "value": { - "id": "sharedtype:space_2_only", - "index": ".kibana", + "id": "index-pattern:space_2_only", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in one space" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["space_2"], "references": [ - { "type": "sharedtype", "id": "each_space", "name": "refname" } + { "type": "index-pattern", "id": "each_space", "name": "refname" } ], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -510,14 +510,14 @@ { "type": "doc", "value": { - "id": "sharedtype:space_2_only_matching_origin", - "index": ".kibana", + "id": "index-pattern:space_2_only_matching_origin", + "index": ".kibana_analytics", "source": { "originId": "space_2_only", - "sharedtype": { + "index-pattern": { "title": "This object only exists to test the third assertion for spacesWithMatchingOrigins in get_shareable_references" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["*"], "references": [], "updated_at": "2017-09-21T18:59:16.270Z" @@ -529,7 +529,7 @@ { "type": "doc", "value": { - "id": "legacy-url-alias:space_2:sharedtype:space_1_only", + "id": "legacy-url-alias:space_2:index-pattern:space_1_only", "index": ".kibana", "source": { "type": "legacy-url-alias", @@ -537,7 +537,7 @@ "legacy-url-alias": { "sourceId": "space_1_only", "targetNamespace": "space_2", - "targetType": "sharedtype", + "targetType": "index-pattern", "targetId": "space_2_only" }, "coreMigrationVersion": "8.8.0", @@ -549,7 +549,7 @@ { "type": "doc", "value": { - "id": "legacy-url-alias:other_space:sharedtype:default_only", + "id": "legacy-url-alias:other_space:index-pattern:default_only", "index": ".kibana", "source": { "type": "legacy-url-alias", @@ -557,7 +557,7 @@ "legacy-url-alias": { "sourceId": "default_only", "targetNamespace": "other_space", - "targetType": "sharedtype", + "targetType": "index-pattern", "targetId": "other_id", "disabled": true } @@ -568,13 +568,13 @@ { "type": "doc", "value": { - "id": "sharedtype:default_and_space_1", - "index": ".kibana", + "id": "index-pattern:default_and_space_1", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in the default and space_1 spaces" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["default", "space_1"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -585,13 +585,13 @@ { "type": "doc", "value": { - "id": "sharedtype:default_and_space_2", - "index": ".kibana", + "id": "index-pattern:default_and_space_2", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in the default and space_2 spaces" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["default", "space_2"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -602,13 +602,13 @@ { "type": "doc", "value": { - "id": "sharedtype:space_1_and_space_2", - "index": ".kibana", + "id": "index-pattern:space_1_and_space_2", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in the space_1 and space_2 spaces" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["space_1", "space_2"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -619,19 +619,19 @@ { "type": "doc", "value": { - "id": "sharedtype:each_space", - "index": ".kibana", + "id": "index-pattern:each_space", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in the default, space_1, and space_2 spaces" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["default", "space_1", "space_2"], "references": [ - { "type": "sharedtype", "id": "default_only", "name": "refname" }, - { "type": "sharedtype", "id": "space_1_only", "name": "refname" }, - { "type": "sharedtype", "id": "space_2_only", "name": "refname" }, - { "type": "sharedtype", "id": "all_spaces", "name": "refname" } + { "type": "index-pattern", "id": "default_only", "name": "refname" }, + { "type": "index-pattern", "id": "space_1_only", "name": "refname" }, + { "type": "index-pattern", "id": "space_2_only", "name": "refname" }, + { "type": "index-pattern", "id": "all_spaces", "name": "refname" } ], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -642,13 +642,13 @@ { "type": "doc", "value": { - "id": "sharedtype:all_spaces", - "index": ".kibana", + "id": "index-pattern:all_spaces", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in all spaces" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["*"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -659,13 +659,13 @@ { "type": "doc", "value": { - "id": "sharedtype:alias_delete_inclusive", - "index": ".kibana", + "id": "index-pattern:alias_delete_inclusive", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "This is used to test that when an object is unshared from a space, inbound aliases for just those spaces are removed" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["default", "space_1", "space_2"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -676,7 +676,7 @@ { "type": "doc", "value": { - "id": "legacy-url-alias:default:sharedtype:doesnt-matter", + "id": "legacy-url-alias:default:index-pattern:doesnt-matter", "index": ".kibana", "source": { "type": "legacy-url-alias", @@ -684,7 +684,7 @@ "legacy-url-alias": { "sourceId": "doesnt-matter", "targetNamespace": "default", - "targetType": "sharedtype", + "targetType": "index-pattern", "targetId": "alias_delete_inclusive" } } @@ -694,7 +694,7 @@ { "type": "doc", "value": { - "id": "legacy-url-alias:space_2:sharedtype:doesnt-matter", + "id": "legacy-url-alias:space_2:index-pattern:doesnt-matter", "index": ".kibana", "source": { "type": "legacy-url-alias", @@ -702,7 +702,7 @@ "legacy-url-alias": { "sourceId": "doesnt-matter", "targetNamespace": "space_2", - "targetType": "sharedtype", + "targetType": "index-pattern", "targetId": "alias_delete_inclusive" } } @@ -712,13 +712,13 @@ { "type": "doc", "value": { - "id": "sharedtype:alias_delete_exclusive", - "index": ".kibana", + "id": "index-pattern:alias_delete_exclusive", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "This is used to test that when an object is unshared from all space, inbound aliases for all spaces are removed" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["*"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -729,7 +729,7 @@ { "type": "doc", "value": { - "id": "legacy-url-alias:other_space:sharedtype:doesnt-matter", + "id": "legacy-url-alias:other_space:index-pattern:doesnt-matter", "index": ".kibana", "source": { "type": "legacy-url-alias", @@ -737,7 +737,7 @@ "legacy-url-alias": { "sourceId": "doesnt-matter", "targetNamespace": "other_space", - "targetType": "sharedtype", + "targetType": "index-pattern", "targetId": "alias_delete_exclusive" } } @@ -747,14 +747,14 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_1a_default", - "index": ".kibana", + "id": "index-pattern:conflict_1a_default", + "index": ".kibana_analytics", "source": { "originId": "conflict_1a", - "sharedtype": { + "index-pattern": { "title": "This is used to test an inexact match conflict for an originId -> originId match" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["default"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -765,14 +765,14 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_1a_space_1", - "index": ".kibana", + "id": "index-pattern:conflict_1a_space_1", + "index": ".kibana_analytics", "source": { "originId": "conflict_1a", - "sharedtype": { + "index-pattern": { "title": "This is used to test an inexact match conflict for an originId -> originId match" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["space_1"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -783,14 +783,14 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_1a_space_2", - "index": ".kibana", + "id": "index-pattern:conflict_1a_space_2", + "index": ".kibana_analytics", "source": { "originId": "conflict_1a", - "sharedtype": { + "index-pattern": { "title": "This is used to test an inexact match conflict for an originId -> originId match" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["space_2"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -801,14 +801,14 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_1b_default", - "index": ".kibana", + "id": "index-pattern:conflict_1b_default", + "index": ".kibana_analytics", "source": { "originId": "conflict_1b_space_2", - "sharedtype": { + "index-pattern": { "title": "This is used to test an inexact match conflict for an originId -> id match" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["default"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -819,14 +819,14 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_1b_space_1", - "index": ".kibana", + "id": "index-pattern:conflict_1b_space_1", + "index": ".kibana_analytics", "source": { "originId": "conflict_1b_space_2", - "sharedtype": { + "index-pattern": { "title": "This is used to test an inexact match conflict for an originId -> id match" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["space_1"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -837,13 +837,13 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_1b_space_2", - "index": ".kibana", + "id": "index-pattern:conflict_1b_space_2", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "This is used to test an inexact match conflict for an originId -> id match" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["space_2"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -854,13 +854,13 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_1c_default_and_space_1", - "index": ".kibana", + "id": "index-pattern:conflict_1c_default_and_space_1", + "index": ".kibana_analytics", "source": { - "sharedtype": { + "index-pattern": { "title": "This is used to test an inexact match conflict for an id -> originId match" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["default", "space_1"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -871,14 +871,14 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_1c_space_2", - "index": ".kibana", + "id": "index-pattern:conflict_1c_space_2", + "index": ".kibana_analytics", "source": { "originId": "conflict_1c_default_and_space_1", - "sharedtype": { + "index-pattern": { "title": "This is used to test an inexact match conflict for an id -> originId match" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["space_2"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -889,14 +889,14 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_2_default", - "index": ".kibana", + "id": "index-pattern:conflict_2_default", + "index": ".kibana_analytics", "source": { "originId": "conflict_2", - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in one space" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["default"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -907,14 +907,14 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_2_space_1", - "index": ".kibana", + "id": "index-pattern:conflict_2_space_1", + "index": ".kibana_analytics", "source": { "originId": "conflict_2", - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in one space" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["space_1"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -925,14 +925,14 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_2_space_2", - "index": ".kibana", + "id": "index-pattern:conflict_2_space_2", + "index": ".kibana_analytics", "source": { "originId": "conflict_2", - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in one space" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["space_2"], "updated_at": "2017-09-21T18:59:16.270Z" }, @@ -943,14 +943,14 @@ { "type": "doc", "value": { - "id": "sharedtype:conflict_2_all", - "index": ".kibana", + "id": "index-pattern:conflict_2_all", + "index": ".kibana_analytics", "source": { "originId": "conflict_2", - "sharedtype": { + "index-pattern": { "title": "A shared saved-object in all spaces" }, - "type": "sharedtype", + "type": "index-pattern", "namespaces": ["default", "space_1", "space_2"], "updated_at": "2017-09-21T18:59:16.270Z" }, diff --git a/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/default_space.json b/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/default_space.json index 9179a846066f1..1a6d80802bd23 100644 --- a/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/default_space.json +++ b/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/default_space.json @@ -139,7 +139,7 @@ "id": "conflict_2_default", "originId": "conflict_2", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUxMCwxXQ==" } @@ -151,7 +151,7 @@ "id": "conflict_2_all", "originId": "conflict_2", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUxMSwxXQ==" } @@ -163,7 +163,7 @@ "id": "conflict_1b_default", "originId": "conflict_1b_space_2", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUwMywxXQ==" } @@ -175,7 +175,7 @@ "id": "conflict_1a_default", "originId": "conflict_1a", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUwMCwxXQ==" } @@ -186,7 +186,7 @@ }, "id": "my_isolated_object", "references": [], - "type": "isolatedtype", + "type": "url", "updated_at": "2017-09-21T18:49:16.270Z", "version": "WzQ4NywxXQ==" } @@ -197,7 +197,7 @@ }, "id": "all_spaces", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ5NywxXQ==" } @@ -211,10 +211,10 @@ { "id": "each_space", "name": "refname", - "type": "sharedtype" + "type": "event-annotation-group" } ], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ4OCwxXQ==" } @@ -228,25 +228,25 @@ { "id": "default_only", "name": "refname", - "type": "sharedtype" + "type": "event-annotation-group" }, { "id": "space_1_only", "name": "refname", - "type": "sharedtype" + "type": "event-annotation-group" }, { "id": "space_2_only", "name": "refname", - "type": "sharedtype" + "type": "event-annotation-group" }, { "id": "all_spaces", "name": "refname", - "type": "sharedtype" + "type": "event-annotation-group" } ], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ5NiwxXQ==" } @@ -257,7 +257,7 @@ }, "id": "conflict_1c_default_and_space_1", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUwNiwxXQ==" } @@ -268,7 +268,7 @@ }, "id": "default_and_space_1", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ5MywxXQ==" } @@ -279,7 +279,7 @@ }, "id": "default_and_space_2", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ5NCwxXQ==" } @@ -291,7 +291,7 @@ "id": "space_2_only_matching_origin", "originId": "space_2_only", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ5MiwxXQ==" } @@ -302,7 +302,7 @@ }, "id": "alias_delete_inclusive", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ5OCwxXQ==" } @@ -313,7 +313,7 @@ }, "id": "alias_delete_exclusive", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ5OSwxXQ==" } @@ -324,7 +324,7 @@ }, "id": "space_1_and_space_2", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ5NSwxXQ==" } diff --git a/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/space_1.json b/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/space_1.json index d037b9d1bd24c..96b2b519a5da3 100644 --- a/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/space_1.json +++ b/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/space_1.json @@ -139,7 +139,7 @@ "id": "conflict_2_space_1", "originId": "conflict_2", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUxMCwxXQ==" } @@ -151,7 +151,7 @@ "id": "conflict_1b_space_1", "originId": "conflict_1b_space_2", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUwNCwxXQ==" } @@ -163,7 +163,7 @@ "id": "conflict_1a_space_1", "originId": "conflict_1a", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUwMSwxXQ==" } @@ -177,10 +177,10 @@ { "id": "each_space", "name": "refname", - "type": "sharedtype" + "type": "event-annotation-group" } ], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ4OSwxXQ==" } @@ -191,7 +191,7 @@ }, "id": "my_isolated_object", "references": [], - "type": "isolatedtype", + "type": "url", "updated_at": "2017-09-21T18:49:16.270Z", "version": "WzQ4NywxXQ==" } diff --git a/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/space_2.json b/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/space_2.json index c68269eb1b335..65d66e305d1c3 100644 --- a/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/space_2.json +++ b/x-pack/test/spaces_api_integration/common/fixtures/kbn_archiver/space_2.json @@ -5,7 +5,7 @@ "id": "conflict_2_space_2", "originId": "conflict_2", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUxMCwxXQ==" } @@ -17,7 +17,7 @@ "id": "conflict_1c_space_2", "originId": "conflict_1c_default_and_space_1", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUwNywxXQ==" } @@ -28,7 +28,7 @@ }, "id": "conflict_1b_space_2", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUwNSwxXQ==" } @@ -40,7 +40,7 @@ "id": "conflict_1a_space_2", "originId": "conflict_1a", "references": [], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzUwMiwxXQ==" } @@ -54,10 +54,10 @@ { "id": "each_space", "name": "refname", - "type": "sharedtype" + "type": "event-annotation-group" } ], - "type": "sharedtype", + "type": "event-annotation-group", "updated_at": "2017-09-21T18:59:16.270Z", "version": "WzQ5MSwxXQ==" } @@ -68,7 +68,7 @@ }, "id": "my_isolated_object", "references": [], - "type": "isolatedtype", + "type": "url", "updated_at": "2017-09-21T18:49:16.270Z", "version": "WzQ4NywxXQ==" } diff --git a/x-pack/test/spaces_api_integration/common/lib/authentication.ts b/x-pack/test/spaces_api_integration/common/lib/authentication.ts index cbd261008dacb..cacc3881ade3f 100644 --- a/x-pack/test/spaces_api_integration/common/lib/authentication.ts +++ b/x-pack/test/spaces_api_integration/common/lib/authentication.ts @@ -9,97 +9,333 @@ export const AUTHENTICATION = { NOT_A_KIBANA_USER: { username: 'not_a_kibana_user', password: 'password', + role: 'no_access', }, SUPERUSER: { username: 'elastic', password: 'changeme', + role: 'system_indices_superuser', }, KIBANA_LEGACY_USER: { username: 'a_kibana_legacy_user', password: 'password', + role: 'kibana_legacy_user', }, KIBANA_DUAL_PRIVILEGES_USER: { username: 'a_kibana_dual_privileges_user', password: 'password', + role: 'kibana_dual_privileges_user', }, KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER: { username: 'a_kibana_dual_privileges_dashboard_only_user', password: 'password', + role: 'kibana_dual_privileges_dashboard_only_user', }, KIBANA_RBAC_USER: { username: 'a_kibana_rbac_user', password: 'password', + role: 'kibana_rbac_user', }, KIBANA_RBAC_DASHBOARD_ONLY_USER: { username: 'a_kibana_rbac_dashboard_only_user', password: 'password', + role: 'kibana_rbac_dashboard_only_user', }, KIBANA_RBAC_DEFAULT_SPACE_ALL_USER: { username: 'a_kibana_rbac_default_space_all_user', password: 'password', + role: 'kibana_rbac_default_space_all_user', }, KIBANA_RBAC_DEFAULT_SPACE_READ_USER: { username: 'a_kibana_rbac_default_space_read_user', password: 'password', + role: 'kibana_rbac_default_space_read_user', }, KIBANA_RBAC_SPACE_1_ALL_USER: { username: 'a_kibana_rbac_space_1_all_user', password: 'password', + role: 'kibana_rbac_space_1_all_user', }, KIBANA_RBAC_SPACE_1_READ_USER: { username: 'a_kibana_rbac_space_1_read_user', password: 'password', + role: 'kibana_rbac_space_1_read_user', }, KIBANA_RBAC_SPACE_2_ALL_USER: { username: 'a_kibana_rbac_space_2_all_user', password: 'password', + role: 'kibana_rbac_space_2_all_user', }, KIBANA_RBAC_SPACE_2_READ_USER: { username: 'a_kibana_rbac_space_2_read_user', password: 'password', + role: 'kibana_rbac_space_2_read_user', }, KIBANA_RBAC_SPACE_1_2_ALL_USER: { username: 'a_kibana_rbac_space_1_2_all_user', password: 'password', + role: 'kibana_rbac_space_1_2_all_user', }, KIBANA_RBAC_SPACE_1_2_READ_USER: { username: 'a_kibana_rbac_space_1_2_read_user', password: 'password', + role: 'kibana_rbac_space_1_2_read_user', }, KIBANA_RBAC_SPACE_3_ALL_USER: { username: 'a_kibana_rbac_space_3_all_user', password: 'password', + role: 'kibana_rbac_space_3_all_user', }, KIBANA_RBAC_SPACE_3_READ_USER: { username: 'a_kibana_rbac_space_3_read_user', password: 'password', + role: 'kibana_rbac_space_3_read_user', }, KIBANA_RBAC_DEFAULT_SPACE_SAVED_OBJECTS_ALL_USER: { username: 'a_kibana_rbac_default_space_saved_objects_all_user', password: 'password', + role: 'kibana_rbac_default_space_saved_objects_all_user', }, KIBANA_RBAC_DEFAULT_SPACE_SAVED_OBJECTS_READ_USER: { username: 'a_kibana_rbac_default_space_saved_objects_read_user', password: 'password', + role: 'kibana_rbac_default_space_saved_objects_read_user', }, KIBANA_RBAC_SPACE_1_SAVED_OBJECTS_ALL_USER: { username: 'a_kibana_rbac_space_1_saved_objects_all_user', password: 'password', + role: 'kibana_rbac_space_1_saved_objects_all_user', }, KIBANA_RBAC_SPACE_1_SAVED_OBJECTS_READ_USER: { username: 'a_kibana_rbac_space_1_saved_objects_read_user', password: 'password', + role: 'kibana_rbac_space_1_saved_objects_read_user', }, MACHINE_LEARING_ADMIN: { username: 'a_machine_learning_admin', password: 'password', + role: 'machine_learning_admin', }, MACHINE_LEARNING_USER: { username: 'a_machine_learning_user', password: 'password', + role: 'machine_learning_user', }, MONITORING_USER: { username: 'a_monitoring_user', password: 'password', + role: 'monitoring_user', }, }; + +export const ROLES = { + kibana_legacy_user: { + elasticsearch: { + indices: [ + { + names: ['.kibana*'], + privileges: ['manage', 'read', 'index', 'delete'], + }, + ], + }, + kibana: [], + }, + kibana_dual_privileges_user: { + elasticsearch: { + indices: [ + { + names: ['.kibana*'], + privileges: ['manage', 'read', 'index', 'delete'], + }, + ], + }, + kibana: [ + { + base: ['all'], + spaces: ['*'], + }, + ], + }, + kibana_dual_privileges_dashboard_only_user: { + elasticsearch: { + indices: [ + { + names: ['.kibana*'], + privileges: ['read', 'view_index_metadata'], + }, + ], + }, + kibana: [ + { + base: ['read'], + spaces: ['*'], + }, + ], + }, + kibana_rbac_user: { + kibana: [ + { + base: ['all'], + spaces: ['*'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_dashboard_only_user: { + kibana: [ + { + base: ['read'], + spaces: ['*'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_default_space_all_user: { + kibana: [ + { + base: ['all'], + spaces: ['default'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_default_space_read_user: { + kibana: [ + { + base: ['read'], + spaces: ['default'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_space_1_all_user: { + kibana: [ + { + base: ['all'], + spaces: ['space_1'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_space_1_read_user: { + kibana: [ + { + base: ['read'], + spaces: ['space_1'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_space_2_all_user: { + kibana: [ + { + base: ['all'], + spaces: ['space_2'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_space_2_read_user: { + kibana: [ + { + base: ['read'], + spaces: ['space_2'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_space_1_2_all_user: { + kibana: [ + { + base: ['all'], + spaces: ['space_1', 'space_2'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_space_1_2_read_user: { + kibana: [ + { + base: ['read'], + spaces: ['space_1', 'space_2'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_space_3_all_user: { + kibana: [ + { + base: ['all'], + spaces: ['space_3'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_space_3_read_user: { + kibana: [ + { + base: ['read'], + spaces: ['space_3'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_default_space_saved_objects_all_user: { + kibana: [ + { + base: [], + feature: { + savedObjectsManagement: ['all'], + }, + spaces: ['default'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_default_space_saved_objects_read_user: { + kibana: [ + { + base: [], + feature: { + savedObjectsManagement: ['read'], + }, + spaces: ['default'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_space_1_saved_objects_all_user: { + kibana: [ + { + base: [], + feature: { + savedObjectsManagement: ['all'], + }, + spaces: ['space_1'], + }, + ], + elasticsearch: {}, + }, + kibana_rbac_space_1_saved_objects_read_user: { + kibana: [ + { + base: [], + feature: { + savedObjectsManagement: ['read'], + }, + spaces: ['space_1'], + }, + ], + elasticsearch: {}, + }, + no_access: { + kibana: [], + elasticsearch: {}, + }, +}; + +export const isBuiltInRole = (role: string) => + ['admin', 'viewer', 'system_indices_superuser'].includes(role); + +export const getRoleDefinitionForUser = (user: { role: string }) => + ROLES[user.role as keyof typeof ROLES]; diff --git a/x-pack/test/spaces_api_integration/common/lib/space_test_utils.ts b/x-pack/test/spaces_api_integration/common/lib/space_test_utils.ts index 3c30208933550..70a597141f1c2 100644 --- a/x-pack/test/spaces_api_integration/common/lib/space_test_utils.ts +++ b/x-pack/test/spaces_api_integration/common/lib/space_test_utils.ts @@ -42,6 +42,7 @@ export function getTestScenariosForSpace(spaceId: string) { export function getAggregatedSpaceData(es: Client, objectTypes: string[]) { return es.search({ index: ALL_SAVED_OBJECT_INDICES, + request_cache: false, body: { size: 0, runtime_mappings: { diff --git a/x-pack/test/spaces_api_integration/common/lib/types.ts b/x-pack/test/spaces_api_integration/common/lib/types.ts index 34a96c3d6daad..1a372d136c36f 100644 --- a/x-pack/test/spaces_api_integration/common/lib/types.ts +++ b/x-pack/test/spaces_api_integration/common/lib/types.ts @@ -10,4 +10,5 @@ export type DescribeFn = (text: string, fn: () => void) => void; export interface TestDefinitionAuthentication { username?: string; password?: string; + role: string; } diff --git a/x-pack/test/spaces_api_integration/common/services.ts b/x-pack/test/spaces_api_integration/common/services.ts index 44ca7ec39c582..0e9428124bc2b 100644 --- a/x-pack/test/spaces_api_integration/common/services.ts +++ b/x-pack/test/spaces_api_integration/common/services.ts @@ -7,8 +7,10 @@ import { services as apiIntegrationServices } from '../../api_integration/services'; import { services as commonServices } from '../../common/services'; +import { RoleScopedSupertestProvider } from '../deployment_agnostic/services/role_scoped_supertest'; export const services = { ...commonServices, usageAPI: apiIntegrationServices.usageAPI, + roleScopedSupertest: RoleScopedSupertestProvider, }; diff --git a/x-pack/test/spaces_api_integration/common/services/basic_auth_supertest.ts b/x-pack/test/spaces_api_integration/common/services/basic_auth_supertest.ts new file mode 100644 index 0000000000000..f3fc944925287 --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/services/basic_auth_supertest.ts @@ -0,0 +1,54 @@ +/* + * 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 { Test } from 'supertest'; + +import type { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services'; + +import type { TestDefinitionAuthentication as User } from '../lib/types'; + +export class SupertestWithBasicAuth { + private readonly supertestWithoutAuth: SupertestWithoutAuthProviderType; + private readonly user: User; + + constructor(supertestWithoutAuth: SupertestWithoutAuthProviderType, user: User) { + this.supertestWithoutAuth = supertestWithoutAuth; + this.user = user; + } + + async destroy() {} + + private request(method: 'post' | 'get' | 'put' | 'delete' | 'patch', url: string): Test { + const agent = this.supertestWithoutAuth[method](url); + + if (this.user) { + agent.auth(this.user.username!, this.user.password!); + } + + return agent; + } + + post(url: string) { + return this.request('post', url); + } + + get(url: string) { + return this.request('get', url); + } + + put(url: string) { + return this.request('put', url); + } + + delete(url: string) { + return this.request('delete', url); + } + + patch(url: string) { + return this.request('patch', url); + } +} diff --git a/x-pack/test/spaces_api_integration/common/services/test_data_loader.ts b/x-pack/test/spaces_api_integration/common/services/test_data_loader.ts new file mode 100644 index 0000000000000..5d8868edfd113 --- /dev/null +++ b/x-pack/test/spaces_api_integration/common/services/test_data_loader.ts @@ -0,0 +1,223 @@ +/* + * 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 Fs from 'fs/promises'; + +import type { LegacyUrlAlias } from '@kbn/core-saved-objects-base-server-internal'; +import { ALL_SAVED_OBJECT_INDICES } from '@kbn/core-saved-objects-server'; + +import type { FtrProviderContext } from '../ftr_provider_context'; + +export const SPACE_1 = { + id: 'space_1', + name: 'Space 1', + description: 'This is the first test space', + disabledFeatures: [], +}; + +export const SPACE_2 = { + id: 'space_2', + name: 'Space 2', + description: 'This is the second test space', + disabledFeatures: [], +}; + +async function parseLegacyUrlAliases(path: string): Promise { + return (await Fs.readFile(path, 'utf-8')) + .split(/\r?\n\r?\n/) + .filter((line) => !!line) + .map((line) => JSON.parse(line)); +} + +// Objects can only be imported in one space at a time. To have test saved objects +// that are shared in multiple spaces we should import all objects in the "original" +// spaces first and then share them to other spaces as a subsequent operation. +const OBJECTS_TO_SHARE: Array<{ + spacesToAdd?: string[]; + spacesToRemove?: string[]; + objects: Array<{ type: string; id: string }>; +}> = [ + { + spacesToAdd: ['*'], + spacesToRemove: ['default'], + objects: [ + { type: 'event-annotation-group', id: 'all_spaces' }, + { type: 'event-annotation-group', id: 'space_2_only_matching_origin' }, + { type: 'event-annotation-group', id: 'alias_delete_exclusive' }, + ], + }, + { + spacesToRemove: ['default'], + spacesToAdd: [SPACE_1.id, SPACE_2.id], + objects: [{ type: 'event-annotation-group', id: 'space_1_and_space_2' }], + }, + { + spacesToAdd: [SPACE_1.id, SPACE_2.id], + objects: [ + { type: 'event-annotation-group', id: 'each_space' }, + { type: 'event-annotation-group', id: 'conflict_2_all' }, + { type: 'event-annotation-group', id: 'alias_delete_inclusive' }, + ], + }, + { + spacesToAdd: [SPACE_1.id], + objects: [ + { type: 'event-annotation-group', id: 'conflict_1c_default_and_space_1' }, + { type: 'event-annotation-group', id: 'default_and_space_1' }, + ], + }, + { + spacesToAdd: [SPACE_2.id], + objects: [{ type: 'event-annotation-group', id: 'default_and_space_2' }], + }, + { + spacesToAdd: [SPACE_1.id, SPACE_2.id], + objects: [{ type: 'resolvetype', id: 'conflict-newid' }], + }, +]; + +export function getTestDataLoader({ getService }: Pick) { + const spacesService = getService('spaces'); + const kbnServer = getService('kibanaServer'); + const supertest = getService('supertest'); + const log = getService('log'); + const es = getService('es'); + const roleScopedSupertest = getService('roleScopedSupertest'); + const config = getService('config'); + const isServerless = config.get('serverless'); + + return { + createFtrSpaces: async () => { + await Promise.all([await spacesService.create(SPACE_1), await spacesService.create(SPACE_2)]); + }, + + deleteFtrSpaces: async () => { + await Promise.all([spacesService.delete(SPACE_1.id), spacesService.delete(SPACE_2.id)]); + }, + + createFtrSavedObjectsData: async ( + spaceData: Array<{ spaceName: string | null; dataUrl: string }> + ) => { + log.debug('Loading test data for the following spaces: default, space_1 and space_2'); + + await Promise.all( + spaceData.map((spaceDataObj) => { + if (spaceDataObj.spaceName) { + return kbnServer.importExport.load(spaceDataObj.dataUrl, { + space: spaceDataObj.spaceName, + }); + } else { + return kbnServer.importExport.load(spaceDataObj.dataUrl); + } + }) + ); + + // Adjust spaces for the imported saved objects. + for (const { objects, spacesToAdd = [], spacesToRemove = [] } of OBJECTS_TO_SHARE) { + log.debug( + `Updating spaces for the following objects (add: [${spacesToAdd.join( + ', ' + )}], remove: [${spacesToRemove.join(', ')}]): ${objects + .map(({ type, id }) => `${type}:${id}`) + .join(', ')}` + ); + + // _update_objects_spaces route is internal in serverless and public in stateful + const supertestWithScope = isServerless + ? await roleScopedSupertest.getSupertestWithRoleScope( + { role: 'admin' }, + { + withCommonHeaders: true, + useCookieHeader: false, + withInternalHeaders: true, + } + ) + : supertest; + await supertestWithScope + .post('/api/spaces/_update_objects_spaces') + .set('kbn-xsrf', 'xxx') + .send({ objects, spacesToAdd, spacesToRemove }) + .expect(200); + } + }, + + createLegacyUrlAliases: async ( + spaceData: Array<{ spaceName: string | null; dataUrl: string; disabled?: boolean }> + ) => { + await Promise.all( + spaceData.map(async (data) => { + const spaceString = data.spaceName ?? 'default'; + + const aliases = await parseLegacyUrlAliases(data.dataUrl); + log.info('creating', aliases.length, 'legacy URL aliases', { + space: spaceString, + }); + + await Promise.all( + aliases.map(async (alias) => { + await es.create({ + id: `legacy-url-alias:${spaceString}:${alias.targetType}:${alias.sourceId}`, + index: '.kibana', + refresh: 'wait_for', + document: { + type: 'legacy-url-alias', + updated_at: '2017-09-21T18:51:23.794Z', + 'legacy-url-alias': { + ...alias, + targetNamespace: spaceString, + ...(data.disabled && { disabled: data.disabled }), + }, + }, + }); + }) + ); + }) + ); + }, + + deleteFtrSavedObjectsData: async () => { + const allSpacesIds = [ + ...(await spacesService.getAll()).map((space: { id: string }) => space.id), + 'non_existent_space', + ]; + log.debug(`Removing data from the following spaces: ${allSpacesIds.join(', ')}`); + await Promise.all( + allSpacesIds.flatMap((spaceId) => [ + kbnServer.savedObjects.cleanStandardList({ space: spaceId }), + kbnServer.savedObjects.clean({ + space: spaceId, + types: ['event-annotation-group', 'url'], + }), + ]) + ); + }, + + deleteAllSavedObjectsFromKibanaIndex: async () => { + await es.deleteByQuery({ + index: ALL_SAVED_OBJECT_INDICES, + wait_for_completion: true, + body: { + // @ts-expect-error + conflicts: 'proceed', + query: { + bool: { + must_not: [ + { + term: { + type: { + value: 'space', + }, + }, + }, + ], + }, + }, + }, + }); + }, + }; +} diff --git a/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts b/x-pack/test/spaces_api_integration/common/suites/copy_to_space.agnostic.ts similarity index 95% rename from x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts rename to x-pack/test/spaces_api_integration/common/suites/copy_to_space.agnostic.ts index 68e1ea401cbf3..3d6496ed556a9 100644 --- a/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts +++ b/x-pack/test/spaces_api_integration/common/suites/copy_to_space.agnostic.ts @@ -5,7 +5,6 @@ * 2.0. */ import type * as estypes from '@elastic/elasticsearch/lib/api/types'; -import type { SuperTest } from 'supertest'; import type { SavedObjectsImportAmbiguousConflictError, @@ -15,10 +14,13 @@ import expect from '@kbn/expect'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common/constants'; import type { CopyResponse } from '@kbn/spaces-plugin/server/lib/copy_to_spaces'; -import { getTestDataLoader, SPACE_1, SPACE_2 } from '../../../common/lib/test_data_loader'; -import type { FtrProviderContext } from '../ftr_provider_context'; +import type { + DeploymentAgnosticFtrProviderContext, + SupertestWithRoleScopeType, +} from '../../deployment_agnostic/ftr_provider_context'; import { getAggregatedSpaceData, getUrlPrefix } from '../lib/space_test_utils'; import type { DescribeFn, TestDefinitionAuthentication } from '../lib/types'; +import { getTestDataLoader, SPACE_1, SPACE_2 } from '../services/test_data_loader'; type TestResponse = Record; @@ -99,12 +101,10 @@ const getDestinationWithConflicts = (originSpaceId?: string) => interface Aggs extends estypes.AggregationsMultiBucketAggregateBase { buckets: SpaceBucket[]; } -export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { +export function copyToSpaceTestSuiteFactory(context: DeploymentAgnosticFtrProviderContext) { const testDataLoader = getTestDataLoader(context); - const supertestWithoutAuth = context.getService( - 'supertestWithoutAuth' - ) as unknown as SuperTest; const es = context.getService('es'); + const roleScopedSupertest = context.getService('roleScopedSupertest'); const collectSpaceContents = async () => { const response = await getAggregatedSpaceData(es, [ @@ -513,7 +513,7 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { // the status code of the HTTP response differs depending on the error type // a 403 error actually comes back as an HTTP 200 response const statusCode = outcome === 'noAccess' ? 403 : 200; - const type = 'sharedtype'; + const type = 'event-annotation-group'; const noConflictId = `${spaceId}_only`; const exactMatchId = 'each_space'; const inexactMatchIdA = `conflict_1a_${spaceId}`; @@ -528,7 +528,11 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { success: false, successCount: 0, errors: [ - { statusCode: 403, error: 'Forbidden', message: `Unable to bulk_create sharedtype` }, + { + statusCode: 403, + error: 'Forbidden', + message: `Unable to bulk_create event-annotation-group`, + }, ], }, }); @@ -540,7 +544,7 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { expect(successCount).to.eql(1); const destinationId = successResults![0].destinationId; expect(destinationId).to.match(UUID_PATTERN); - const meta = { title, icon: 'beaker' }; + const meta = { title, icon: 'flag' }; const managed = false; // default added By `create` expect(successResults).to.eql([{ type, id: sourceId, meta, destinationId, managed }]); expect(errors).to.be(undefined); @@ -578,6 +582,7 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { // 'unauthorizedRead'), the copy attempt will proceed because they are not aware that the object already exists in the // destination space. In that case, they will encounter a 403 error. const { success, successCount, successResults, errors } = getResult(response); + const title = 'A shared saved-object in the default, space_1, and space_2 spaces'; if (createNewCopies) { expectNewCopyResponse(response, exactMatchId, title); @@ -606,7 +611,7 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { const { success, successCount, successResults, errors } = getResult(response); const title = 'This is used to test an inexact match conflict for an originId -> originId match'; - const meta = { title, icon: 'beaker' }; + const meta = { title, icon: 'flag' }; const destinationId = 'conflict_1a_space_2'; if (createNewCopies) { expectNewCopyResponse(response, inexactMatchIdA, title); @@ -654,7 +659,7 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { const { success, successCount, successResults, errors } = getResult(response); const title = 'This is used to test an inexact match conflict for an originId -> id match'; - const meta = { title, icon: 'beaker' }; + const meta = { title, icon: 'flag' }; const destinationId = 'conflict_1b_space_2'; if (createNewCopies) { expectNewCopyResponse(response, inexactMatchIdB, title); @@ -702,7 +707,7 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { const { success, successCount, successResults, errors } = getResult(response); const title = 'This is used to test an inexact match conflict for an id -> originId match'; - const meta = { title, icon: 'beaker' }; + const meta = { title, icon: 'flag' }; const destinationId = 'conflict_1c_space_2'; if (createNewCopies) { expectNewCopyResponse(response, inexactMatchIdC, title); @@ -778,7 +783,7 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { error: { type: 'ambiguous_conflict', destinations }, type, id: ambiguousConflictId, - meta: { title, icon: 'beaker' }, + meta: { title, icon: 'flag' }, }, ]); } @@ -797,24 +802,26 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { (describeFn: DescribeFn) => ( description: string, - { user = {}, spaceId = DEFAULT_SPACE_ID, tests }: CopyToSpaceTestDefinition + { user, spaceId = DEFAULT_SPACE_ID, tests }: CopyToSpaceTestDefinition ) => { describeFn(description, () => { + let supertest: SupertestWithRoleScopeType; before(async () => { // test data only allows for the following spaces as the copy origin expect(['default', 'space_1']).to.contain(spaceId); - await testDataLoader.createFtrSpaces(); + supertest = await roleScopedSupertest.getSupertestWithRoleScope(user!); }); after(async () => { await testDataLoader.deleteFtrSpaces(); + await supertest.destroy(); }); describe('single-namespace types', () => { - beforeEach(async () => { - await testDataLoader.createFtrSavedObjectsData(SPACE_DATA_TO_LOAD); - }); + beforeEach( + async () => await testDataLoader.createFtrSavedObjectsData(SPACE_DATA_TO_LOAD) + ); afterEach(async () => await testDataLoader.deleteFtrSavedObjectsData()); @@ -825,9 +832,8 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { await assertSpaceCounts(destination, INITIAL_COUNTS[destination]); - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_copy_saved_objects`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], spaces: [destination], @@ -844,9 +850,8 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { await assertSpaceCounts(destination, INITIAL_COUNTS[destination]); - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_copy_saved_objects`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], spaces: [destination], @@ -863,9 +868,8 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { await assertSpaceCounts(destination, INITIAL_COUNTS[destination]); - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_copy_saved_objects`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], spaces: [destination], @@ -882,9 +886,8 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { await assertSpaceCounts(destination, INITIAL_COUNTS[destination]); - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_copy_saved_objects`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], spaces: [destination], @@ -900,9 +903,8 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { const conflictDestination = getDestinationWithConflicts(spaceId); const noConflictDestination = getDestinationWithoutConflicts(); - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_copy_saved_objects`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], spaces: [conflictDestination, noConflictDestination], @@ -933,9 +935,8 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { }); it(`should return ${tests.nonExistentSpace.statusCode} when copying to non-existent space`, async () => { - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_copy_saved_objects`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], spaces: ['non_existent_space'], @@ -952,7 +953,7 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { [false, false], [false, true], // createNewCopies enabled [true, false], // overwrite enabled - // we don't specify tese cases with both overwrite and createNewCopies enabled, since overwrite won't matter in that scenario + // we don't specify test cases with both overwrite and createNewCopies enabled, since overwrite won't matter in that scenario ].forEach(([overwrite, createNewCopies]) => { const spaces = ['space_2']; const includeReferences = false; @@ -963,9 +964,8 @@ export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) { const testCases = tests.multiNamespaceTestCases(overwrite, createNewCopies); testCases.forEach(({ testTitle, objects, statusCode, response }) => { it(`should return ${statusCode} when ${testTitle}`, async () => { - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_copy_saved_objects`) - .auth(user.username, user.password) .send({ objects, spaces, includeReferences, createNewCopies, overwrite }) .expect(statusCode) .then(response); diff --git a/x-pack/test/spaces_api_integration/common/suites/create.ts b/x-pack/test/spaces_api_integration/common/suites/create.agnostic.ts similarity index 85% rename from x-pack/test/spaces_api_integration/common/suites/create.ts rename to x-pack/test/spaces_api_integration/common/suites/create.agnostic.ts index 5599d065eb93c..cc5caf361fd9b 100644 --- a/x-pack/test/spaces_api_integration/common/suites/create.ts +++ b/x-pack/test/spaces_api_integration/common/suites/create.agnostic.ts @@ -5,10 +5,12 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - import expect from '@kbn/expect'; +import type { + DeploymentAgnosticFtrProviderContext, + SupertestWithRoleScopeType, +} from '../../deployment_agnostic/ftr_provider_context'; import { getTestScenariosForSpace } from '../lib/space_test_utils'; import type { DescribeFn, TestDefinitionAuthentication } from '../lib/types'; @@ -30,7 +32,13 @@ interface CreateTestDefinition { tests: CreateTests; } -export function createTestSuiteFactory(esArchiver: any, supertest: SuperTest) { +export function createTestSuiteFactory({ getService }: DeploymentAgnosticFtrProviderContext) { + const esArchiver = getService('esArchiver'); + const roleScopedSupertest = getService('roleScopedSupertest'); + const config = getService('config'); + const isServerless = config.get('serverless'); + const noop = () => undefined; + const expectConflictResponse = (resp: { [key: string]: any }) => { expect(resp.body).to.only.have.keys(['error', 'message', 'statusCode']); expect(resp.body.error).to.equal('Conflict'); @@ -101,8 +109,18 @@ export function createTestSuiteFactory(esArchiver: any, supertest: SuperTest - (description: string, { user = {}, spaceId, tests }: CreateTestDefinition) => { + (description: string, { user, spaceId, tests }: CreateTestDefinition) => { describeFn(description, () => { + let supertest: SupertestWithRoleScopeType; + + before(async () => { + supertest = await roleScopedSupertest.getSupertestWithRoleScope(user!); + }); + + after(async () => { + await supertest.destroy(); + }); + beforeEach(() => esArchiver.load( 'x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces' @@ -118,7 +136,6 @@ export function createTestSuiteFactory(esArchiver: any, supertest: SuperTest { return supertest .post(`${urlPrefix}/api/spaces/space`) - .auth(user.username, user.password) .send({ name: 'marketing', id: 'marketing', @@ -134,7 +151,6 @@ export function createTestSuiteFactory(esArchiver: any, supertest: SuperTest { return supertest .post(`${urlPrefix}/api/spaces/space`) - .auth(user.username, user.password) .send({ name: 'space_1', id: 'space_1', @@ -151,7 +167,6 @@ export function createTestSuiteFactory(esArchiver: any, supertest: SuperTest { return supertest .post(`${urlPrefix}/api/spaces/space`) - .auth(user.username, user.password) .send({ name: 'reserved space', id: 'reserved', @@ -167,9 +182,10 @@ export function createTestSuiteFactory(esArchiver: any, supertest: SuperTest { it(`should return ${tests.solutionSpecified.statusCode}`, async () => { + const statusCode = isServerless ? 400 : tests.solutionSpecified.statusCode; + return supertest .post(`${urlPrefix}/api/spaces/space`) - .auth(user.username, user.password) .send({ name: 'space with solution', id: 'solution', @@ -178,8 +194,8 @@ export function createTestSuiteFactory(esArchiver: any, supertest: SuperTest) { +export function deleteTestSuiteFactory({ getService }: DeploymentAgnosticFtrProviderContext) { + const esArchiver = getService('esArchiver'); + const es = getService('es'); + const roleScopedSupertest = getService('roleScopedSupertest'); + const retry = getService('retry'); + const createExpectResult = (expectedResult: any) => (resp: { [key: string]: any }) => { expect(resp.body).to.eql(expectedResult); }; @@ -40,6 +46,23 @@ export function deleteTestSuiteFactory(es: Client, esArchiver: any, supertest: S const expectEmptyResult = async (resp: { [key: string]: any }) => { expect(resp.body).to.eql(''); + await retry.waitForWithTimeout('space_2 to be deleted', 5000, async () => { + const response = await getAggregatedSpaceData(es, [ + 'visualization', + 'dashboard', + 'space', + 'index-pattern', + 'legacy-url-alias', + ]); + + // @ts-expect-error @elastic/elasticsearch doesn't defined `count.buckets`. + const buckets = response.aggregations?.count.buckets; + + const isSpace2Found = buckets?.some((bucket: any) => bucket.key === 'space_2'); + + return !isSpace2Found; + }); + // Query ES to ensure that we deleted everything we expected, and nothing we didn't // Grouping first by namespace, then by saved object type const response = await getAggregatedSpaceData(es, [ @@ -64,40 +87,86 @@ export function deleteTestSuiteFactory(es: Client, esArchiver: any, supertest: S const expectedBuckets = [ { key: 'default', - doc_count: 10, + doc_count: 20, countByType: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ - { key: 'space', doc_count: 3 }, // since space objects are namespace-agnostic, they appear in the "default" agg bucket - { key: 'visualization', doc_count: 3 }, - { key: 'legacy-url-alias', doc_count: 2 }, // aliases (1) - { key: 'dashboard', doc_count: 1 }, - { key: 'index-pattern', doc_count: 1 }, + { + key: 'index-pattern', + doc_count: 11, + }, + { + key: 'space', + doc_count: 3, + }, + { + key: 'visualization', + doc_count: 3, + }, + { + key: 'legacy-url-alias', + doc_count: 2, + }, + { + key: 'dashboard', + doc_count: 1, + }, ], }, }, { - doc_count: 5, key: 'space_1', + doc_count: 10, countByType: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ - { key: 'visualization', doc_count: 3 }, - { key: 'dashboard', doc_count: 1 }, - { key: 'index-pattern', doc_count: 1 }, - // no legacy url alias objects exist in space_1 + { + key: 'index-pattern', + doc_count: 6, + }, + { + key: 'visualization', + doc_count: 3, + }, + { + key: 'dashboard', + doc_count: 1, + }, + ], + }, + }, + { + key: '*', + doc_count: 3, + countByType: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'index-pattern', + doc_count: 3, + }, ], }, }, { - doc_count: 2, key: 'other_space', + doc_count: 3, countByType: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, - buckets: [{ key: 'legacy-url-alias', doc_count: 2 }], // aliases (3) + buckets: [ + { + key: 'legacy-url-alias', + doc_count: 2, + }, + { + key: 'index-pattern', + doc_count: 1, + }, + ], }, }, ]; @@ -110,11 +179,11 @@ export function deleteTestSuiteFactory(es: Client, esArchiver: any, supertest: S const multiNamespaceResponse = await es.search>({ index: ALL_SAVED_OBJECT_INDICES, size: 100, - body: { query: { terms: { type: ['sharedtype'] } } }, + body: { query: { terms: { type: ['index-pattern'] } } }, }); const docs = multiNamespaceResponse.hits.hits; - // Just 19 results, since spaces_2_only, conflict_1a_space_2, conflict_1b_space_2, conflict_1c_space_2, and conflict_2_space_2 got deleted. - expect(docs).length(19); + // Just 21 results, since spaces_2_only, conflict_1a_space_2, conflict_1b_space_2, conflict_1c_space_2, and conflict_2_space_2 got deleted. + expect(docs).length(21); docs.forEach((doc) => () => { const containsSpace2 = doc?._source?.namespaces.includes('space_2'); expect(containsSpace2).to.eql(false); @@ -149,8 +218,17 @@ export function deleteTestSuiteFactory(es: Client, esArchiver: any, supertest: S const makeDeleteTest = (describeFn: DescribeFn) => - (description: string, { user = {}, spaceId, tests }: DeleteTestDefinition) => { + (description: string, { user, spaceId, tests }: DeleteTestDefinition) => { describeFn(description, () => { + let supertest: SupertestWithRoleScopeType; + + before(async () => { + supertest = await roleScopedSupertest.getSupertestWithRoleScope(user!); + }); + after(async () => { + await supertest.destroy(); + }); + beforeEach(async () => { await esArchiver.load( 'x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces' @@ -166,7 +244,6 @@ export function deleteTestSuiteFactory(es: Client, esArchiver: any, supertest: S it(`should return ${tests.exists.statusCode} ${scenario}`, async () => { return supertest .delete(`${urlPrefix}/api/spaces/space/space_2`) - .auth(user.username, user.password) .expect(tests.exists.statusCode) .then(tests.exists.response); }); @@ -175,7 +252,6 @@ export function deleteTestSuiteFactory(es: Client, esArchiver: any, supertest: S it(`should return ${tests.reservedSpace.statusCode} ${scenario}`, async () => { return supertest .delete(`${urlPrefix}/api/spaces/space/default`) - .auth(user.username, user.password) .expect(tests.reservedSpace.statusCode) .then(tests.reservedSpace.response); }); @@ -185,7 +261,6 @@ export function deleteTestSuiteFactory(es: Client, esArchiver: any, supertest: S it(`should return ${tests.doesntExist.statusCode} ${scenario}`, async () => { return supertest .delete(`${urlPrefix}/api/spaces/space/space_7`) - .auth(user.username, user.password) .expect(tests.doesntExist.statusCode) .then(tests.doesntExist.response); }); diff --git a/x-pack/test/spaces_api_integration/common/suites/disable_legacy_url_aliases.ts b/x-pack/test/spaces_api_integration/common/suites/disable_legacy_url_aliases.ts index a00729e7eca8c..10cb486ac2633 100644 --- a/x-pack/test/spaces_api_integration/common/suites/disable_legacy_url_aliases.ts +++ b/x-pack/test/spaces_api_integration/common/suites/disable_legacy_url_aliases.ts @@ -38,7 +38,7 @@ interface RawLegacyUrlAlias { [LEGACY_URL_ALIAS_TYPE]: LegacyUrlAlias; } -export const TEST_CASE_TARGET_TYPE = 'sharedtype'; +export const TEST_CASE_TARGET_TYPE = 'index-pattern'; export const TEST_CASE_SOURCE_ID = 'space_1_only'; // two aliases exist for space_1_only: one in the default spacd=e, and one in space_2 const createRequest = ({ targetSpace, targetType, sourceId }: DisableLegacyUrlAliasesTestCase) => ({ aliases: [{ targetSpace, targetType, sourceId }], diff --git a/x-pack/test/spaces_api_integration/common/suites/get.ts b/x-pack/test/spaces_api_integration/common/suites/get.agnostic.ts similarity index 66% rename from x-pack/test/spaces_api_integration/common/suites/get.ts rename to x-pack/test/spaces_api_integration/common/suites/get.agnostic.ts index 3c3a81d171f7b..9c7a8e6b53152 100644 --- a/x-pack/test/spaces_api_integration/common/suites/get.ts +++ b/x-pack/test/spaces_api_integration/common/suites/get.agnostic.ts @@ -5,10 +5,12 @@ * 2.0. */ -import type { SuperAgent } from 'superagent'; - import expect from '@kbn/expect'; +import type { + DeploymentAgnosticFtrProviderContext, + SupertestWithRoleScopeType, +} from '../../deployment_agnostic/ftr_provider_context'; import { getTestScenariosForSpace } from '../lib/space_test_utils'; import type { DescribeFn, TestDefinitionAuthentication } from '../lib/types'; @@ -30,7 +32,11 @@ interface GetTestDefinition { const nonExistantSpaceId = 'not-a-space'; -export function getTestSuiteFactory(esArchiver: any, supertest: SuperAgent) { +export function getTestSuiteFactory(context: DeploymentAgnosticFtrProviderContext) { + const esArchiver = context.getService('esArchiver'); + const config = context.getService('config'); + const isServerless = config.get('serverless'); + const createExpectEmptyResult = () => (resp: { [key: string]: any }) => { expect(resp.body).to.eql(''); }; @@ -77,26 +83,29 @@ export function getTestSuiteFactory(esArchiver: any, supertest: SuperAgent) id: 'space_3', name: 'Space 3', description: 'This is the third test space', - solution: 'es', - disabledFeatures: [ - // Disabled features are automatically added to the space when a solution is set - 'apm', - 'infrastructure', - 'inventory', - 'logs', - 'observabilityCases', - 'observabilityCasesV2', - 'securitySolutionAssistant', - 'securitySolutionAttackDiscovery', - 'securitySolutionCases', - 'securitySolutionCasesV2', - 'securitySolutionNotes', - 'securitySolutionTimeline', - 'siem', - 'siemV2', - 'slo', - 'uptime', - ], + disabledFeatures: [], + ...(!isServerless && { + solution: 'es', + disabledFeatures: [ + // Disabled features are automatically added to the space when a solution is set + 'apm', + 'infrastructure', + 'inventory', + 'logs', + 'observabilityCases', + 'observabilityCasesV2', + 'securitySolutionAssistant', + 'securitySolutionAttackDiscovery', + 'securitySolutionCases', + 'securitySolutionCasesV2', + 'securitySolutionNotes', + 'securitySolutionTimeline', + 'siem', + 'siemV2', + 'slo', + 'uptime', + ], + }), }, ]; @@ -104,7 +113,7 @@ export function getTestSuiteFactory(esArchiver: any, supertest: SuperAgent) const expectedSpace = allSpaces.find((space) => space.id === spaceId); if (expectedSpace) { - expectedSpace.disabledFeatures.sort(); + expectedSpace.disabledFeatures?.sort(); } expect({ ...resp.body, disabledFeatures }).to.eql(expectedSpace); @@ -112,24 +121,28 @@ export function getTestSuiteFactory(esArchiver: any, supertest: SuperAgent) const makeGetTest = (describeFn: DescribeFn) => - (description: string, { user = {}, currentSpaceId, spaceId, tests }: GetTestDefinition) => { + (description: string, { user, currentSpaceId, spaceId, tests }: GetTestDefinition) => { describeFn(description, () => { - before(() => - esArchiver.load( + const roleScopedSupertest = context.getService('roleScopedSupertest'); + let supertest: SupertestWithRoleScopeType; + + before(async () => { + supertest = await roleScopedSupertest.getSupertestWithRoleScope(user!); + await esArchiver.load( 'x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces' - ) - ); - after(() => - esArchiver.unload( + ); + }); + after(async () => { + await supertest.destroy(); + await esArchiver.unload( 'x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces' - ) - ); + ); + }); getTestScenariosForSpace(currentSpaceId).forEach(({ urlPrefix, scenario }) => { it(`should return ${tests.default.statusCode} ${scenario}`, async () => { return supertest .get(`${urlPrefix}/api/spaces/space/${spaceId}`) - .auth(user.username, user.password) .expect(tests.default.statusCode) .then(tests.default.response); }); diff --git a/x-pack/test/spaces_api_integration/common/suites/get_all.ts b/x-pack/test/spaces_api_integration/common/suites/get_all.agnostic.ts similarity index 69% rename from x-pack/test/spaces_api_integration/common/suites/get_all.ts rename to x-pack/test/spaces_api_integration/common/suites/get_all.agnostic.ts index 9f4abd8001f6d..4976f739f3765 100644 --- a/x-pack/test/spaces_api_integration/common/suites/get_all.ts +++ b/x-pack/test/spaces_api_integration/common/suites/get_all.agnostic.ts @@ -5,10 +5,12 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - import expect from '@kbn/expect'; +import type { + DeploymentAgnosticFtrProviderContext, + SupertestWithRoleScopeType, +} from '../../deployment_agnostic/ftr_provider_context'; import { getTestScenariosForSpace } from '../lib/space_test_utils'; import type { DescribeFn, TestDefinitionAuthentication } from '../lib/types'; @@ -53,8 +55,8 @@ const ALL_SPACE_RESULTS: Space[] = [ name: 'Default', color: '#00bfb3', description: 'This is your default space!', - _reserved: true, disabledFeatures: [], + _reserved: true, }, { id: 'space_1', @@ -72,7 +74,6 @@ const ALL_SPACE_RESULTS: Space[] = [ id: 'space_3', name: 'Space 3', description: 'This is the third test space', - solution: 'es', disabledFeatures: [ // Disabled features are automatically added to the space when a solution is set 'apm', @@ -92,31 +93,61 @@ const ALL_SPACE_RESULTS: Space[] = [ 'slo', 'uptime', ], + solution: 'es', }, ]; -const sortDisabledFeatures = (space: Space) => { - return { - ...space, - disabledFeatures: [...space.disabledFeatures].sort(), +export function getAllTestSuiteFactory(context: DeploymentAgnosticFtrProviderContext) { + const esArchiver = context.getService('esArchiver'); + const config = context.getService('config'); + const isServerless = config.get('serverless'); + + const maybeNormalizeSpace = (space: Space) => { + if (isServerless && space.solution) { + const { id, name, description } = space; + + return { id, name, description, disabledFeatures: [] }; + } + return space; }; -}; -export function getAllTestSuiteFactory(esArchiver: any, supertest: SuperTest) { const createExpectResults = (...spaceIds: string[]) => (resp: { [key: string]: any }) => { - const expectedBody = ALL_SPACE_RESULTS.filter((entry) => spaceIds.includes(entry.id)); - expect(resp.body.map(sortDisabledFeatures)).to.eql(expectedBody.map(sortDisabledFeatures)); + const expectedBody = ALL_SPACE_RESULTS.filter((entry) => spaceIds.includes(entry.id)).map( + maybeNormalizeSpace + ); + + for (const space of resp.body) { + const expectedSpace = expectedBody.find((x) => x.id === space.id); + expect(space.name).to.eql(expectedSpace?.name); + expect(space.description).to.eql(expectedSpace?.description); + expect(space.color).to.eql(expectedSpace?.color); + expect(space.solution).to.eql(expectedSpace?.solution); + expect(space.disabledFeatures.sort()).to.eql(expectedSpace?.disabledFeatures.sort()); + } }; const createExpectAllPurposesResults = (authorizedPurposes: AuthorizedPurposes, ...spaceIds: string[]) => (resp: { [key: string]: any }) => { const expectedBody = ALL_SPACE_RESULTS.filter((entry) => spaceIds.includes(entry.id)).map( - (x) => ({ ...x, authorizedPurposes }) + (entry) => { + const space = maybeNormalizeSpace(entry); + + return { ...space, authorizedPurposes }; + } ); - expect(resp.body.map(sortDisabledFeatures)).to.eql(expectedBody.map(sortDisabledFeatures)); + + for (const space of resp.body) { + const expectedSpace = expectedBody.find((x) => x.id === space.id); + expect(space.name).to.eql(expectedSpace?.name); + expect(space.description).to.eql(expectedSpace?.description); + expect(space.color).to.eql(expectedSpace?.color); + expect(space.solution).to.eql(expectedSpace?.solution); + expect(space.disabledFeatures.sort()).to.eql(expectedSpace?.disabledFeatures.sort()); + expect(space.authorizedPurposes).to.eql(expectedSpace?.authorizedPurposes); + } }; const expectEmptyResult = (resp: { [key: string]: any }) => { @@ -133,25 +164,29 @@ export function getAllTestSuiteFactory(esArchiver: any, supertest: SuperTest - (description: string, { user = {}, spaceId, tests }: GetAllTestDefinition) => { + (description: string, { user, spaceId, tests }: GetAllTestDefinition) => { describeFn(description, () => { - before(() => - esArchiver.load( + const roleScopedSupertest = context.getService('roleScopedSupertest'); + let supertest: SupertestWithRoleScopeType; + before(async () => { + supertest = await roleScopedSupertest.getSupertestWithRoleScope(user!); + await esArchiver.load( 'x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces' - ) - ); - after(() => - esArchiver.unload( + ); + }); + after(async () => { + await esArchiver.unload( 'x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces' - ) - ); + ); + + await supertest.destroy(); + }); getTestScenariosForSpace(spaceId).forEach(({ scenario, urlPrefix }) => { describe('undefined purpose', () => { it(`should return ${tests.exists.statusCode} ${scenario}`, async () => { return supertest .get(`${urlPrefix}/api/spaces/space`) - .auth(user.username, user.password) .expect(tests.exists.statusCode) .then(tests.exists.response); }); @@ -162,7 +197,6 @@ export function getAllTestSuiteFactory(esArchiver: any, supertest: SuperTest = deepFreeze({ - SHAREABLE_TYPE: { type: 'sharedtype', id: CASES.EACH_SPACE.id }, // contains references to four other objects - SHAREABLE_TYPE_DOES_NOT_EXIST: { type: 'sharedtype', id: 'does-not-exist' }, - NON_SHAREABLE_TYPE: { type: 'isolatedtype', id: 'my_isolated_object' }, // one of these exists in each space + SHAREABLE_TYPE: { type: 'index-pattern', id: CASES.EACH_SPACE.id }, // contains references to four other objects + SHAREABLE_TYPE_DOES_NOT_EXIST: { type: 'index-pattern', id: 'does-not-exist' }, + NON_SHAREABLE_TYPE: { type: 'url', id: 'my_isolated_object' }, // one of these exists in each space }); // Expected results for each space are defined here since they are used in multiple test suites export const EXPECTED_RESULTS: Record = { @@ -54,7 +54,7 @@ export const EXPECTED_RESULTS: Record ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, spaces: [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID], // No matching origins because there are no copies of the object in another space (we no longer consider a raw ID match to be an origin match) - inboundReferences: [{ type: 'sharedtype', id: CASES.DEFAULT_ONLY.id, name: 'refname' }], // only reflects inbound reference that exist in the default space + inboundReferences: [{ type: 'index-pattern', id: CASES.DEFAULT_ONLY.id, name: 'refname' }], // only reflects inbound reference that exist in the default space }, { ...TEST_CASE_OBJECTS.SHAREABLE_TYPE_DOES_NOT_EXIST, @@ -64,28 +64,28 @@ export const EXPECTED_RESULTS: Record }, { ...TEST_CASE_OBJECTS.NON_SHAREABLE_TYPE, spaces: [], inboundReferences: [] }, // not missing, but has an empty spaces array because it is not a shareable type { - type: 'sharedtype', + type: 'index-pattern', id: CASES.DEFAULT_ONLY.id, spaces: [DEFAULT_SPACE_ID], // No matching origins because there are no copies of the object in another space (we no longer consider a raw ID match to be an origin match) inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }], }, { - type: 'sharedtype', + type: 'index-pattern', id: CASES.SPACE_1_ONLY.id, spaces: [], inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }], isMissing: true, // doesn't exist in the default space }, { - type: 'sharedtype', + type: 'index-pattern', id: CASES.SPACE_2_ONLY.id, spaces: [], inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }], isMissing: true, // doesn't exist in the default space }, { - type: 'sharedtype', + type: 'index-pattern', id: CASES.ALL_SPACES.id, spaces: ['*'], // No matching origins because there are no copies of the object in another space (we no longer consider a raw ID match to be an origin match) @@ -97,7 +97,7 @@ export const EXPECTED_RESULTS: Record ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, spaces: [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID], // No matching origins because there are no copies of the object in another space (we no longer consider a raw ID match to be an origin match) - inboundReferences: [{ type: 'sharedtype', id: CASES.SPACE_1_ONLY.id, name: 'refname' }], // only reflects inbound reference that exist in space 1 + inboundReferences: [{ type: 'index-pattern', id: CASES.SPACE_1_ONLY.id, name: 'refname' }], // only reflects inbound reference that exist in space 1 }, { ...TEST_CASE_OBJECTS.SHAREABLE_TYPE_DOES_NOT_EXIST, @@ -107,14 +107,14 @@ export const EXPECTED_RESULTS: Record }, { ...TEST_CASE_OBJECTS.NON_SHAREABLE_TYPE, spaces: [], inboundReferences: [] }, // not missing, but has an empty spaces array because it is not a shareable type { - type: 'sharedtype', + type: 'index-pattern', id: CASES.DEFAULT_ONLY.id, spaces: [], inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }], isMissing: true, // doesn't exist in space 1 }, { - type: 'sharedtype', + type: 'index-pattern', id: CASES.SPACE_1_ONLY.id, spaces: [SPACE_1_ID], spacesWithMatchingAliases: [DEFAULT_SPACE_ID, SPACE_2_ID], // aliases with a matching targetType and sourceId exist in two other spaces @@ -122,14 +122,14 @@ export const EXPECTED_RESULTS: Record inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }], }, { - type: 'sharedtype', + type: 'index-pattern', id: CASES.SPACE_2_ONLY.id, spaces: [], inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }], isMissing: true, // doesn't exist in space 1 }, { - type: 'sharedtype', + type: 'index-pattern', id: CASES.ALL_SPACES.id, spaces: ['*'], // No matching origins because there are no copies of the object in another space (we no longer consider a raw ID match to be an origin match) @@ -141,7 +141,7 @@ export const EXPECTED_RESULTS: Record ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, spaces: [DEFAULT_SPACE_ID, SPACE_1_ID, SPACE_2_ID], // No matching origins because there are no copies of the object in another space (we no longer consider a raw ID match to be an origin match) - inboundReferences: [{ type: 'sharedtype', id: CASES.SPACE_2_ONLY.id, name: 'refname' }], // only reflects inbound reference that exist in space 2 + inboundReferences: [{ type: 'index-pattern', id: CASES.SPACE_2_ONLY.id, name: 'refname' }], // only reflects inbound reference that exist in space 2 }, { ...TEST_CASE_OBJECTS.SHAREABLE_TYPE_DOES_NOT_EXIST, @@ -151,28 +151,28 @@ export const EXPECTED_RESULTS: Record }, { ...TEST_CASE_OBJECTS.NON_SHAREABLE_TYPE, spaces: [], inboundReferences: [] }, // not missing, but has an empty spaces array because it is not a shareable type { - type: 'sharedtype', + type: 'index-pattern', id: CASES.DEFAULT_ONLY.id, spaces: [], inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }], isMissing: true, // doesn't exist in space 2 }, { - type: 'sharedtype', + type: 'index-pattern', id: CASES.SPACE_1_ONLY.id, spaces: [], inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }], isMissing: true, // doesn't exist in space 2 }, { - type: 'sharedtype', + type: 'index-pattern', id: CASES.SPACE_2_ONLY.id, spaces: [SPACE_2_ID], spacesWithMatchingOrigins: ['*'], // The third test assertion for spacesWithMatchingOrigins is an object that has a matching origin in all spaces (this takes precedence, causing SPACE_2_ID to be omitted) inboundReferences: [{ ...TEST_CASE_OBJECTS.SHAREABLE_TYPE, name: 'refname' }], }, { - type: 'sharedtype', + type: 'index-pattern', id: CASES.ALL_SPACES.id, spaces: ['*'], // No matching origins because there are no copies of the object in another space (we no longer consider a raw ID match to be an origin match) diff --git a/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts b/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.agnostic.ts similarity index 93% rename from x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts rename to x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.agnostic.ts index 845d41d1431b9..2edbcaddcfae3 100644 --- a/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts +++ b/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.agnostic.ts @@ -5,17 +5,18 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - import type { SavedObject } from '@kbn/core/server'; import expect from '@kbn/expect'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common/constants'; import type { CopyResponse } from '@kbn/spaces-plugin/server/lib/copy_to_spaces'; -import { getTestDataLoader, SPACE_1, SPACE_2 } from '../../../common/lib/test_data_loader'; -import type { FtrProviderContext } from '../ftr_provider_context'; +import type { + DeploymentAgnosticFtrProviderContext, + SupertestWithRoleScopeType, +} from '../../deployment_agnostic/ftr_provider_context'; import { getUrlPrefix } from '../lib/space_test_utils'; import type { DescribeFn, TestDefinitionAuthentication } from '../lib/types'; +import { getTestDataLoader, SPACE_1, SPACE_2 } from '../services/test_data_loader'; type TestResponse = Record; @@ -69,20 +70,37 @@ const getDestinationSpace = (originSpaceId?: string) => { return DEFAULT_SPACE_ID; }; -export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { +export function resolveCopyToSpaceConflictsSuite(context: DeploymentAgnosticFtrProviderContext) { const testDataLoader = getTestDataLoader(context); + const roleScopedSupertest = context.getService('roleScopedSupertest'); const supertestWithAuth = context.getService('supertest'); - const supertestWithoutAuth = context.getService( - 'supertestWithoutAuth' - ) as unknown as SuperTest; + const config = context.getService('config'); + const license = config.get('esTestCluster.license'); + const isServerless = config.get('serverless'); + + const getSupertestWithAuth = async () => + license === 'basic' && !isServerless + ? supertestWithAuth + : await roleScopedSupertest.getSupertestWithRoleScope( + { role: 'admin' }, + { + withCommonHeaders: true, + useCookieHeader: false, + withInternalHeaders: true, + } + ); const getVisualizationAtSpace = async (spaceId: string): Promise> => { - return supertestWithAuth + const supertest = await getSupertestWithAuth(); + + return supertest .get(`${getUrlPrefix(spaceId)}/api/saved_objects/visualization/cts_vis_3_${spaceId}`) .then((response: any) => response.body); }; const getDashboardAtSpace = async (spaceId: string): Promise> => { - return supertestWithAuth + const supertest = await getSupertestWithAuth(); + + return supertest .get(`${getUrlPrefix(spaceId)}/api/saved_objects/dashboard/cts_dashboard_${spaceId}`) .then((response: any) => response.body); }; @@ -209,6 +227,7 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { }); const [dashboard, visualization] = await getObjectsAtSpace(destination); + expect(dashboard.attributes.title).to.eql( `This is the ${destination} test space CTS dashboard` ); @@ -342,7 +361,7 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { // the status code of the HTTP response differs depending on the error type // a 403 error actually comes back as an HTTP 200 response const statusCode = outcome === 'noAccess' ? 403 : 200; - const type = 'sharedtype'; + const type = 'event-annotation-group'; const exactMatchId = 'each_space'; const inexactMatchIdA = `conflict_1a_${spaceId}`; const inexactMatchIdB = `conflict_1b_${spaceId}`; @@ -359,7 +378,11 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { success: false, successCount: 0, errors: [ - { statusCode: 403, error: 'Forbidden', message: `Unable to bulk_create sharedtype` }, + { + statusCode: 403, + error: 'Forbidden', + message: `Unable to bulk_create event-annotation-group`, + }, ], }, }); @@ -387,7 +410,7 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { return 'A shared saved-object in one space'; } })(); - const meta = { title, icon: 'beaker' }; + const meta = { title, icon: 'flag' }; expect(successResults).to.eql([ { type, @@ -509,14 +532,20 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { (describeFn: DescribeFn) => ( description: string, - { user = {}, spaceId = DEFAULT_SPACE_ID, tests }: ResolveCopyToSpaceTestDefinition + { user, spaceId = DEFAULT_SPACE_ID, tests }: ResolveCopyToSpaceTestDefinition ) => { describeFn(description, () => { - before(() => { + let supertest: SupertestWithRoleScopeType; + before(async () => { + supertest = await roleScopedSupertest.getSupertestWithRoleScope(user!); // test data only allows for the following spaces as the copy origin expect(['default', 'space_1']).to.contain(spaceId); }); + after(async () => { + await supertest.destroy(); + }); + describe('single-namespace types', () => { beforeEach( async () => await testDataLoader.createFtrSavedObjectsData(SPACE_DATA_TO_LOAD) @@ -530,9 +559,8 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { it(`should return ${tests.withReferencesNotOverwriting.statusCode} when not overwriting, with references`, async () => { const destination = getDestinationSpace(spaceId); - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_resolve_copy_saved_objects_errors`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], includeReferences: true, @@ -559,9 +587,8 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { it(`should return ${tests.withReferencesOverwriting.statusCode} when overwriting, with references`, async () => { const destination = getDestinationSpace(spaceId); - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_resolve_copy_saved_objects_errors`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], includeReferences: true, @@ -588,9 +615,8 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { it(`should return ${tests.withoutReferencesOverwriting.statusCode} when overwriting, without references`, async () => { const destination = getDestinationSpace(spaceId); - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_resolve_copy_saved_objects_errors`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], includeReferences: false, @@ -612,9 +638,8 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { it(`should return ${tests.withoutReferencesNotOverwriting.statusCode} when not overwriting, without references`, async () => { const destination = getDestinationSpace(spaceId); - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_resolve_copy_saved_objects_errors`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], includeReferences: false, @@ -636,9 +661,8 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { it(`should return ${tests.nonExistentSpace.statusCode} when resolving within a non-existent space`, async () => { const destination = NON_EXISTENT_SPACE_ID; - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_resolve_copy_saved_objects_errors`) - .auth(user.username, user.password) .send({ objects: [dashboardObject], includeReferences: false, @@ -669,9 +693,8 @@ export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) { const testCases = tests.multiNamespaceTestCases(); testCases.forEach(({ testTitle, objects, retries, statusCode, response }) => { it(`should return ${statusCode} when ${testTitle}`, async () => { - return supertestWithoutAuth + return supertest .post(`${getUrlPrefix(spaceId)}/api/spaces/_resolve_copy_saved_objects_errors`) - .auth(user.username, user.password) .send({ objects, includeReferences, createNewCopies, retries }) .expect(statusCode) .then(response); diff --git a/x-pack/test/spaces_api_integration/common/suites/update.ts b/x-pack/test/spaces_api_integration/common/suites/update.agnostic.ts similarity index 79% rename from x-pack/test/spaces_api_integration/common/suites/update.ts rename to x-pack/test/spaces_api_integration/common/suites/update.agnostic.ts index 62226bf4dbb8d..b3e1972912f23 100644 --- a/x-pack/test/spaces_api_integration/common/suites/update.ts +++ b/x-pack/test/spaces_api_integration/common/suites/update.agnostic.ts @@ -4,11 +4,19 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import type { SuperTest } from 'supertest'; +/* + * 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 type { + DeploymentAgnosticFtrProviderContext, + SupertestWithRoleScopeType, +} from '../../deployment_agnostic/ftr_provider_context'; import { getUrlPrefix } from '../lib/space_test_utils'; import type { DescribeFn, TestDefinitionAuthentication } from '../lib/types'; @@ -29,7 +37,10 @@ interface UpdateTestDefinition { tests: UpdateTests; } -export function updateTestSuiteFactory(esArchiver: any, supertest: SuperTest) { +export function updateTestSuiteFactory(context: DeploymentAgnosticFtrProviderContext) { + const esArchiver = context.getService('esArchiver'); + const roleScopedSupertest = context.getService('roleScopedSupertest'); + const expectRbacForbidden = (resp: { [key: string]: any }) => { expect(resp.body).to.eql({ statusCode: 403, @@ -69,24 +80,26 @@ export function updateTestSuiteFactory(esArchiver: any, supertest: SuperTest - (description: string, { user = {}, spaceId, tests }: UpdateTestDefinition) => { + (description: string, { user, spaceId, tests }: UpdateTestDefinition) => { describeFn(description, () => { - before(() => - esArchiver.load( + let supertest: SupertestWithRoleScopeType; + before(async () => { + supertest = await roleScopedSupertest.getSupertestWithRoleScope(user!); + await esArchiver.load( 'x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces' - ) - ); - after(() => - esArchiver.unload( + ); + }); + after(async () => { + await supertest.destroy(); + await esArchiver.unload( 'x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces' - ) - ); + ); + }); describe('space_1', () => { it(`should return ${tests.alreadyExists.statusCode}`, async () => { return supertest .put(`${getUrlPrefix(spaceId)}/api/spaces/space/space_1`) - .auth(user.username, user.password) .send({ name: 'space 1', id: 'space_1', @@ -104,7 +117,6 @@ export function updateTestSuiteFactory(esArchiver: any, supertest: SuperTest { return supertest .put(`${getUrlPrefix(spaceId)}/api/spaces/space/default`) - .auth(user.username, user.password) .send({ name: 'the new default', id: 'default', @@ -122,7 +134,6 @@ export function updateTestSuiteFactory(esArchiver: any, supertest: SuperTest { return supertest .put(`${getUrlPrefix(spaceId)}/api/spaces/space/marketing`) - .auth(user.username, user.password) .send({ name: 'marketing', id: 'marketing', diff --git a/x-pack/test/spaces_api_integration/common/suites/update_objects_spaces.ts b/x-pack/test/spaces_api_integration/common/suites/update_objects_spaces.ts index 05ed64e1e6047..c1f5bf68c5da2 100644 --- a/x-pack/test/spaces_api_integration/common/suites/update_objects_spaces.ts +++ b/x-pack/test/spaces_api_integration/common/suites/update_objects_spaces.ts @@ -45,7 +45,7 @@ export interface UpdateObjectsSpacesTestCase { spacesToRemove: string[]; } -const TYPE = 'sharedtype'; +const TYPE = 'index-pattern'; const createRequest = ({ objects, spacesToAdd, spacesToRemove }: UpdateObjectsSpacesTestCase) => ({ objects: objects.map(({ id }) => ({ type: TYPE, id })), spacesToAdd, diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/ftr_provider_context.d.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/ftr_provider_context.d.ts new file mode 100644 index 0000000000000..c8d0b14c5786f --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/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 type { GenericFtrProviderContext } from '@kbn/test'; + +import type { services } from './services'; + +export type DeploymentAgnosticFtrProviderContext = GenericFtrProviderContext; +export type { SupertestWithRoleScopeType } from './services'; diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/copy_to_space/copy_to_space.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/copy_to_space/copy_to_space.ts similarity index 90% rename from x-pack/test/spaces_api_integration/security_and_spaces/apis/copy_to_space/copy_to_space.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/copy_to_space/copy_to_space.ts index b7e10cb500e80..3e769698d7f55 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/copy_to_space/copy_to_space.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/copy_to_space/copy_to_space.ts @@ -5,13 +5,20 @@ * 2.0. */ -import type { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { AUTHENTICATION } from '../../../common/lib/authentication'; -import { SPACES } from '../../../common/lib/spaces'; -import { copyToSpaceTestSuiteFactory } from '../../../common/suites/copy_to_space'; +import { AUTHENTICATION } from '../../../../common/lib/authentication'; +import { SPACES } from '../../../../common/lib/spaces'; +import { copyToSpaceTestSuiteFactory } from '../../../../common/suites/copy_to_space.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export -export default function copyToSpaceSpacesAndSecuritySuite(context: FtrProviderContext) { +interface User { + username: string; + password: string; + role: string; +} + +export default function copyToSpaceSpacesAndSecuritySuite( + context: DeploymentAgnosticFtrProviderContext +) { const { copyToSpaceTest, expectNoConflictsWithoutReferencesResult, @@ -54,7 +61,7 @@ export default function copyToSpaceSpacesAndSecuritySuite(context: FtrProviderCo }, }, ].forEach(({ spaceId, ...scenario }) => { - const definitionNoAccess = (user: { username: string; password: string }) => ({ + const definitionNoAccess = (user: User) => ({ spaceId, user, tests: { @@ -117,7 +124,7 @@ export default function copyToSpaceSpacesAndSecuritySuite(context: FtrProviderCo response: createExpectUnauthorizedAtSpaceWithoutReferencesResult(spaceId, 'non-existent'), }, }; - const definitionUnauthorizedRead = (user: { username: string; password: string }) => ({ + const definitionUnauthorizedRead = (user: User) => ({ spaceId, user, tests: { @@ -125,7 +132,7 @@ export default function copyToSpaceSpacesAndSecuritySuite(context: FtrProviderCo multiNamespaceTestCases: createMultiNamespaceTestCases(spaceId, 'unauthorizedRead'), }, }); - const definitionUnauthorizedWrite = (user: { username: string; password: string }) => ({ + const definitionUnauthorizedWrite = (user: User) => ({ spaceId, user, tests: { @@ -133,7 +140,7 @@ export default function copyToSpaceSpacesAndSecuritySuite(context: FtrProviderCo multiNamespaceTestCases: createMultiNamespaceTestCases(spaceId, 'unauthorizedWrite'), }, }); - const definitionAuthorized = (user: { username: string; password: string }) => ({ + const definitionAuthorized = (user: User) => ({ spaceId, user, tests: { diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/copy_to_space/index.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/copy_to_space/index.ts new file mode 100644 index 0000000000000..3dab3cfbf708c --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/copy_to_space/index.ts @@ -0,0 +1,29 @@ +/* + * 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 } from '../../../../common/lib/create_users_and_roles'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile, getService }: DeploymentAgnosticFtrProviderContext) { + const config = getService('config'); + const license = config.get('esTestCluster.license'); + const es = getService('es'); + const supertest = getService('supertest'); + const isServerless = config.get('serverless'); + + describe('spaces api with security', function () { + // Should be enabled when custom roles can be provisioned for MKI + // See: https://github.com/elastic/kibana/issues/207361 + this.tags('skipMKI'); + before(async () => { + if (license === 'basic' && !isServerless) { + await createUsersAndRoles(es, supertest); + } + }); + loadTestFile(require.resolve('./copy_to_space')); + }); +} diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/create.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/create.ts similarity index 91% rename from x-pack/test/spaces_api_integration/security_and_spaces/apis/create.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/create.ts index 6e5bc1649cb3f..ea775aa0a50ce 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/create.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/create.ts @@ -5,18 +5,12 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { AUTHENTICATION } from '../../common/lib/authentication'; -import { SPACES } from '../../common/lib/spaces'; -import { createTestSuiteFactory } from '../../common/suites/create'; - -// eslint-disable-next-line import/no-default-export -export default function createSpacesOnlySuite({ getService }: FtrProviderContext) { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); +import { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { createTestSuiteFactory } from '../../../common/suites/create.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; +export default function createSpacesOnlySuite(context: DeploymentAgnosticFtrProviderContext) { const { createTest, expectNewSpaceResult, @@ -24,7 +18,7 @@ export default function createSpacesOnlySuite({ getService }: FtrProviderContext expectConflictResponse, expectRbacForbiddenResponse, expectSolutionSpecifiedResult, - } = createTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest); + } = createTestSuiteFactory(context); describe('create', () => { [ @@ -100,7 +94,6 @@ export default function createSpacesOnlySuite({ getService }: FtrProviderContext }, }, }); - createTest(`rbac user with all globally from the ${scenario.spaceId} space`, { spaceId: scenario.spaceId, user: scenario.users.allGlobally, @@ -169,7 +162,6 @@ export default function createSpacesOnlySuite({ getService }: FtrProviderContext }, }, }); - createTest(`rbac user with read globally from the ${scenario.spaceId} space`, { spaceId: scenario.spaceId, user: scenario.users.readGlobally, diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/delete.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/delete.ts similarity index 89% rename from x-pack/test/spaces_api_integration/security_and_spaces/apis/delete.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/delete.ts index 01fd306a7f558..1c398b08fc311 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/delete.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/delete.ts @@ -5,26 +5,19 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { AUTHENTICATION } from '../../common/lib/authentication'; -import { SPACES } from '../../common/lib/spaces'; -import { deleteTestSuiteFactory } from '../../common/suites/delete'; - -// eslint-disable-next-line import/no-default-export -export default function deleteSpaceTestSuite({ getService }: FtrProviderContext) { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); - const es = getService('es'); +import { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { deleteTestSuiteFactory } from '../../../common/suites/delete.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; +export default function deleteSpaceTestSuite(context: DeploymentAgnosticFtrProviderContext) { const { deleteTest, expectRbacForbidden, expectEmptyResult, expectNotFound, expectReservedSpaceResult, - } = deleteTestSuiteFactory(es, esArchiver, supertestWithoutAuth as unknown as SuperTest); + } = deleteTestSuiteFactory(context); describe('delete', () => { [ diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/get.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/get.ts similarity index 93% rename from x-pack/test/spaces_api_integration/security_and_spaces/apis/get.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/get.ts index cc24ffa0d891a..ca9fac5a99dcf 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/get.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/get.ts @@ -5,25 +5,19 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { AUTHENTICATION } from '../../common/lib/authentication'; -import { SPACES } from '../../common/lib/spaces'; -import { getTestSuiteFactory } from '../../common/suites/get'; - -// eslint-disable-next-line import/no-default-export -export default function getSpaceTestSuite({ getService }: FtrProviderContext) { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); +import { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { getTestSuiteFactory } from '../../../common/suites/get.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; +export default function getSpaceTestSuite(context: DeploymentAgnosticFtrProviderContext) { const { getTest, createExpectResults, createExpectNotFoundResult, createExpectRbacForbidden, nonExistantSpaceId, - } = getTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest); + } = getTestSuiteFactory(context); describe('get', () => { [ diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/get_all.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/get_all.ts new file mode 100644 index 0000000000000..39dcf12e9a696 --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/get_all.ts @@ -0,0 +1,446 @@ +/* + * 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 { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { getAllTestSuiteFactory } from '../../../common/suites/get_all.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; + +export default function getAllSpacesTestSuite(context: DeploymentAgnosticFtrProviderContext) { + const { getAllTest, createExpectResults, createExpectAllPurposesResults, expectRbacForbidden } = + getAllTestSuiteFactory(context); + + const spaces = ['default', 'space_1', 'space_2', 'space_3']; + + // these are used to determine expected results for tests where the `include_authorized_purposes` option is enabled + const authorizedAll = { + any: true, + copySavedObjectsIntoSpace: true, + findSavedObjects: true, + shareSavedObjectsIntoSpace: true, + }; + const authorizedRead = { + any: true, + copySavedObjectsIntoSpace: false, + findSavedObjects: true, + shareSavedObjectsIntoSpace: false, + }; + + describe('get all', () => { + /* eslint-disable @typescript-eslint/naming-convention */ + [ + { + spaceId: SPACES.DEFAULT.spaceId, + users: { + noAccess: AUTHENTICATION.NOT_A_KIBANA_USER, + superuser: AUTHENTICATION.SUPERUSER, + allGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + allAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + readAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER, + allAtDefaultSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + readAtDefaultSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER, + readSavedObjectsAtDefaultSpace: + AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_SAVED_OBJECTS_READ_USER, + allSavedObjectsAtDefaultSpace: + AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_SAVED_OBJECTS_ALL_USER, + readSavedObjectsAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_SAVED_OBJECTS_READ_USER, + allSavedObjectsAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_SAVED_OBJECTS_ALL_USER, + legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + }, + { + spaceId: SPACES.SPACE_1.spaceId, + users: { + noAccess: AUTHENTICATION.NOT_A_KIBANA_USER, + superuser: AUTHENTICATION.SUPERUSER, + allGlobally: AUTHENTICATION.KIBANA_RBAC_USER, + readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, + allAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, + readAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER, + allAtDefaultSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, + readAtDefaultSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER, + readSavedObjectsAtDefaultSpace: + AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_SAVED_OBJECTS_READ_USER, + allSavedObjectsAtDefaultSpace: + AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_SAVED_OBJECTS_ALL_USER, + readSavedObjectsAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_SAVED_OBJECTS_READ_USER, + allSavedObjectsAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_SAVED_OBJECTS_ALL_USER, + legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, + dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, + dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, + }, + }, + /* eslint-enable @typescript-eslint/naming-convention */ + ].forEach((scenario) => { + getAllTest(`user with no access can't access any spaces from ${scenario.spaceId}`, { + spaceId: scenario.spaceId, + user: scenario.users.noAccess, + tests: { + exists: { + statusCode: 403, + response: expectRbacForbidden, + }, + copySavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + shareSavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + includeAuthorizedPurposes: { + statusCode: 403, + response: expectRbacForbidden, + }, + }, + }); + + getAllTest(`superuser can access all spaces from ${scenario.spaceId}`, { + spaceId: scenario.spaceId, + user: scenario.users.superuser, + tests: { + exists: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + copySavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + shareSavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedAll, ...spaces), + }, + }, + }); + + getAllTest(`rbac user with all globally can access all spaces from ${scenario.spaceId}`, { + spaceId: scenario.spaceId, + user: scenario.users.allGlobally, + tests: { + exists: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + copySavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + shareSavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedAll, ...spaces), + }, + }, + }); + + getAllTest(`dual-privileges user can access all spaces from ${scenario.spaceId}`, { + spaceId: scenario.spaceId, + user: scenario.users.dualAll, + tests: { + exists: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + copySavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + shareSavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedAll, ...spaces), + }, + }, + }); + + getAllTest(`legacy user can't access any spaces from ${scenario.spaceId}`, { + spaceId: scenario.spaceId, + user: scenario.users.legacyAll, + tests: { + exists: { + statusCode: 403, + response: expectRbacForbidden, + }, + copySavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + shareSavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + includeAuthorizedPurposes: { + statusCode: 403, + response: expectRbacForbidden, + }, + }, + }); + + getAllTest(`rbac user with read globally can access all spaces from ${scenario.spaceId}`, { + spaceId: scenario.spaceId, + user: scenario.users.readGlobally, + tests: { + exists: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + copySavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + shareSavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedRead, ...spaces), + }, + }, + }); + + getAllTest(`dual-privileges readonly user can access all spaces from ${scenario.spaceId}`, { + spaceId: scenario.spaceId, + user: scenario.users.dualRead, + tests: { + exists: { + statusCode: 200, + response: createExpectResults(...spaces), + }, + copySavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + shareSavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedRead, ...spaces), + }, + }, + }); + + getAllTest(`rbac user with all at space_1 can access space_1 from ${scenario.spaceId}`, { + spaceId: scenario.spaceId, + user: scenario.users.allAtSpace_1, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('space_1'), + }, + copySavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults('space_1'), + }, + shareSavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults('space_1'), + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedAll, 'space_1'), + }, + }, + }); + + getAllTest(`rbac user with read at space_1 can access space_1 from ${scenario.spaceId}`, { + spaceId: scenario.spaceId, + user: scenario.users.readAtSpace_1, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('space_1'), + }, + copySavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + shareSavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedRead, 'space_1'), + }, + }, + }); + + getAllTest( + `rbac user with all at default space can access default from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + user: scenario.users.allAtDefaultSpace, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default'), + }, + copySavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults('default'), + }, + shareSavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults('default'), + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedAll, 'default'), + }, + }, + } + ); + + getAllTest( + `rbac user with read at default space can access default from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + user: scenario.users.readAtDefaultSpace, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default'), + }, + copySavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + shareSavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedRead, 'default'), + }, + }, + } + ); + + getAllTest( + `rbac user with saved objects management all at default space can access default from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + user: scenario.users.allSavedObjectsAtDefaultSpace, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default'), + }, + copySavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults('default'), + }, + shareSavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults('default'), + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedAll, 'default'), + }, + }, + } + ); + + getAllTest( + `rbac user with saved objects management read at default space can access default from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + user: scenario.users.readSavedObjectsAtDefaultSpace, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('default'), + }, + copySavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + shareSavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedRead, 'default'), + }, + }, + } + ); + + getAllTest( + `rbac user with saved objects management all at space_1 space can access space_1 from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + user: scenario.users.allSavedObjectsAtSpace_1, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('space_1'), + }, + copySavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults('space_1'), + }, + shareSavedObjectsPurpose: { + statusCode: 200, + response: createExpectResults('space_1'), + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedAll, 'space_1'), + }, + }, + } + ); + + getAllTest( + `rbac user with saved objects management read at space_1 space can access space_1 from ${scenario.spaceId}`, + { + spaceId: scenario.spaceId, + user: scenario.users.readSavedObjectsAtSpace_1, + tests: { + exists: { + statusCode: 200, + response: createExpectResults('space_1'), + }, + copySavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + shareSavedObjectsPurpose: { + statusCode: 403, + response: expectRbacForbidden, + }, + includeAuthorizedPurposes: { + statusCode: 200, + response: createExpectAllPurposesResults(authorizedRead, 'space_1'), + }, + }, + } + ); + }); + }); +} diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/index.serverless.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/index.serverless.ts new file mode 100644 index 0000000000000..8a5a03dfa8333 --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/index.serverless.ts @@ -0,0 +1,22 @@ +/* + * 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 { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) { + describe('spaces api with security', function () { + // Should be enabled when custom roles can be provisioned for MKI + // See: https://github.com/elastic/kibana/issues/207361 + this.tags('skipMKI'); + loadTestFile(require.resolve('./resolve_copy_to_space_conflicts')); + loadTestFile(require.resolve('./create')); + loadTestFile(require.resolve('./delete')); + loadTestFile(require.resolve('./get_all')); + loadTestFile(require.resolve('./get')); + loadTestFile(require.resolve('./update')); + }); +} diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/index.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/index.ts new file mode 100644 index 0000000000000..392ae720c9330 --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/index.ts @@ -0,0 +1,33 @@ +/* + * 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 } from '../../../common/lib/create_users_and_roles'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile, getService }: DeploymentAgnosticFtrProviderContext) { + const config = getService('config'); + const license = config.get('esTestCluster.license'); + const es = getService('es'); + const supertest = getService('supertest'); + + describe('spaces api with security', function () { + // Should we enabled when custom roles can be provisioned for MKI + // See: https://github.com/elastic/kibana/issues/207361 + this.tags('skipMKI'); + before(async () => { + if (license === 'basic') { + await createUsersAndRoles(es, supertest); + } + }); + loadTestFile(require.resolve('./resolve_copy_to_space_conflicts')); + loadTestFile(require.resolve('./create')); + loadTestFile(require.resolve('./delete')); + loadTestFile(require.resolve('./get_all')); + loadTestFile(require.resolve('./get')); + loadTestFile(require.resolve('./update')); + }); +} diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/resolve_copy_to_space_conflicts.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/resolve_copy_to_space_conflicts.ts similarity index 90% rename from x-pack/test/spaces_api_integration/security_and_spaces/apis/resolve_copy_to_space_conflicts.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/resolve_copy_to_space_conflicts.ts index da5054436dc69..391119e97513a 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/resolve_copy_to_space_conflicts.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/resolve_copy_to_space_conflicts.ts @@ -5,13 +5,20 @@ * 2.0. */ -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { AUTHENTICATION } from '../../common/lib/authentication'; -import { SPACES } from '../../common/lib/spaces'; -import { resolveCopyToSpaceConflictsSuite } from '../../common/suites/resolve_copy_to_space_conflicts'; +import { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { resolveCopyToSpaceConflictsSuite } from '../../../common/suites/resolve_copy_to_space_conflicts.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export -export default function resolveCopyToSpaceConflictsTestSuite(context: FtrProviderContext) { +interface TestUser { + username: string; + password: string; + role: string; +} + +export default function resolveCopyToSpaceConflictsTestSuite( + context: DeploymentAgnosticFtrProviderContext +) { const { resolveCopyToSpaceConflictsTest, createExpectNonOverriddenResponseWithReferences, @@ -54,7 +61,7 @@ export default function resolveCopyToSpaceConflictsTestSuite(context: FtrProvide }, }, ].forEach(({ spaceId, ...scenario }) => { - const definitionNoAccess = (user: { username: string; password: string }) => ({ + const definitionNoAccess = (user: TestUser) => ({ spaceId, user, tests: { @@ -81,7 +88,7 @@ export default function resolveCopyToSpaceConflictsTestSuite(context: FtrProvide multiNamespaceTestCases: createMultiNamespaceTestCases(spaceId, 'noAccess'), }, }); - const definitionUnauthorizedRead = (user: { username: string; password: string }) => ({ + const definitionUnauthorizedRead = (user: TestUser) => ({ spaceId, user, tests: { @@ -111,7 +118,7 @@ export default function resolveCopyToSpaceConflictsTestSuite(context: FtrProvide multiNamespaceTestCases: createMultiNamespaceTestCases(spaceId, 'unauthorizedRead'), }, }); - const definitionUnauthorizedWrite = (user: { username: string; password: string }) => ({ + const definitionUnauthorizedWrite = (user: TestUser) => ({ spaceId, user, tests: { @@ -141,7 +148,7 @@ export default function resolveCopyToSpaceConflictsTestSuite(context: FtrProvide multiNamespaceTestCases: createMultiNamespaceTestCases(spaceId, 'unauthorizedWrite'), }, }); - const definitionAuthorized = (user: { username: string; password: string }) => ({ + const definitionAuthorized = (user: TestUser) => ({ spaceId, user, tests: { diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/update.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/update.ts similarity index 90% rename from x-pack/test/spaces_api_integration/security_and_spaces/apis/update.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/update.ts index 57fd1c5b1a202..0fbfe6763a1a7 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/update.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/apis/update.ts @@ -5,25 +5,19 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { AUTHENTICATION } from '../../common/lib/authentication'; -import { SPACES } from '../../common/lib/spaces'; -import { updateTestSuiteFactory } from '../../common/suites/update'; - -// eslint-disable-next-line import/no-default-export -export default function updateSpaceTestSuite({ getService }: FtrProviderContext) { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); +import { AUTHENTICATION } from '../../../common/lib/authentication'; +import { SPACES } from '../../../common/lib/spaces'; +import { updateTestSuiteFactory } from '../../../common/suites/update.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; +export default function updateSpaceTestSuite(context: DeploymentAgnosticFtrProviderContext) { const { updateTest, expectNotFound, expectAlreadyExistsResult, expectDefaultSpaceResult, expectRbacForbidden, - } = updateTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest); + } = updateTestSuiteFactory(context); describe('update', () => { [ diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/serverless.config.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/serverless.config.ts new file mode 100644 index 0000000000000..e9e47d92c2d45 --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/serverless.config.ts @@ -0,0 +1,19 @@ +/* + * 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 { createServerlessTestConfig } from '../../../api_integration/deployment_agnostic/default_configs/serverless.config.base'; +import { services } from '../services'; + +export default createServerlessTestConfig({ + // @ts-expect-error + services, + serverlessProject: 'security', + testFiles: [require.resolve('./apis/index.serverless')], + junit: { + reportName: 'Serverless Security - Deployment-agnostic API Integration Tests', + }, +}); diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/serverless.copy_to_space.config.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/serverless.copy_to_space.config.ts new file mode 100644 index 0000000000000..fbfe85fb5b9e0 --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/serverless.copy_to_space.config.ts @@ -0,0 +1,20 @@ +/* + * 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 { createServerlessTestConfig } from '../../../api_integration/deployment_agnostic/default_configs/serverless.config.base'; +import { services } from '../services'; + +export default createServerlessTestConfig({ + // @ts-expect-error roleScopedSupertest service accepts a user not just a user role and is different from the one in the common services + services, + serverlessProject: 'security', + testFiles: [require.resolve('./apis/copy_to_space')], + junit: { + reportName: + 'X-Pack Spaces API Deployment Agnostic Integration Tests -- copy_to_space - serverless', + }, +}); diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.config_basic.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.config_basic.ts new file mode 100644 index 0000000000000..f1e1c562bdd61 --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.config_basic.ts @@ -0,0 +1,19 @@ +/* + * 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. + */ +/* + * 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 { createTestConfig } from '../../common/config'; + +export default createTestConfig('security_and_spaces - basic license', { + license: 'basic', + testFiles: [require.resolve('./apis')], +}); diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.config_trial.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.config_trial.ts new file mode 100644 index 0000000000000..d2ed6598dade0 --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.config_trial.ts @@ -0,0 +1,19 @@ +/* + * 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 { createStatefulTestConfig } from '../../../api_integration/deployment_agnostic/default_configs/stateful.config.base'; +import { services } from '../services'; + +export default createStatefulTestConfig({ + // @ts-expect-error roleScopedSupertest service accepts a user not just a user role and is different from the one in the common services + services, + testFiles: [require.resolve('./apis')], + junit: { + reportName: + 'X-Pack Spaces API Deployment Agnostic Integration Tests -- security_and_spaces - trial license', + }, +}); diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/copy_to_space_config_basic.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.copy_to_space.config_basic.ts similarity index 67% rename from x-pack/test/spaces_api_integration/security_and_spaces/copy_to_space_config_basic.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.copy_to_space.config_basic.ts index 609d747fa8861..c6dbb5f0eabbf 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/copy_to_space_config_basic.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.copy_to_space.config_basic.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { createTestConfig } from '../common/config'; +import { createTestConfig } from '../../common/config'; -// eslint-disable-next-line import/no-default-export -export default createTestConfig('security_and_spaces', { +export default createTestConfig('copy_to_space - basic license', { license: 'basic', testFiles: [require.resolve('./apis/copy_to_space')], }); diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.copy_to_space.config_trial.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.copy_to_space.config_trial.ts new file mode 100644 index 0000000000000..ac80beaea2372 --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/security_and_spaces/stateful.copy_to_space.config_trial.ts @@ -0,0 +1,19 @@ +/* + * 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 { createStatefulTestConfig } from '../../../api_integration/deployment_agnostic/default_configs/stateful.config.base'; +import { services } from '../services'; + +export default createStatefulTestConfig({ + // @ts-expect-error roleScopedSupertest service accepts a user not just a user role and is different from the one in the common services + services, + testFiles: [require.resolve('./apis/copy_to_space')], + junit: { + reportName: + 'X-Pack Spaces API Deployment Agnostic Integration Tests -- copy_to_space - trial license', + }, +}); diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/services/index.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/services/index.ts new file mode 100644 index 0000000000000..656aab1cab731 --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/services/index.ts @@ -0,0 +1,20 @@ +/* + * 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 { RoleScopedSupertestProvider } from './role_scoped_supertest'; +import { services as deploymentAgnosticServices } from '../../../api_integration/deployment_agnostic/services'; +import { services as apiIntegrationServices } from '../../../api_integration/services'; +import { services as commonServices } from '../../../common/services'; + +export type { SupertestWithRoleScopeType } from './role_scoped_supertest'; + +export const services = { + ...commonServices, + ...deploymentAgnosticServices, + usageAPI: apiIntegrationServices.usageAPI, + roleScopedSupertest: RoleScopedSupertestProvider, +}; diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/services/role_scoped_supertest.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/services/role_scoped_supertest.ts new file mode 100644 index 0000000000000..0be90b8497f1f --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/services/role_scoped_supertest.ts @@ -0,0 +1,57 @@ +/* + * 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 { RequestHeadersOptions } from '../../../api_integration/deployment_agnostic/services/role_scoped_supertest'; +import { SupertestWithRoleScope } from '../../../api_integration/deployment_agnostic/services/role_scoped_supertest'; +import { getRoleDefinitionForUser, isBuiltInRole } from '../../common/lib/authentication'; +import type { TestDefinitionAuthentication as User } from '../../common/lib/types'; +import { SupertestWithBasicAuth } from '../../common/services/basic_auth_supertest'; +import type { DeploymentAgnosticFtrProviderContext } from '../ftr_provider_context'; + +export type SupertestWithRoleScopeType = SupertestWithBasicAuth | SupertestWithRoleScope; + +export function RoleScopedSupertestProvider({ getService }: DeploymentAgnosticFtrProviderContext) { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const samlAuth = getService('samlAuth'); + const config = getService('config'); + const license = config.get('esTestCluster.license'); + const isServerless = config.get('serverless'); + + return { + async getSupertestWithRoleScope( + user: User, + options: RequestHeadersOptions = { + useCookieHeader: true, + withCommonHeaders: false, + withInternalHeaders: true, + } + ) { + if (!user || (license === 'basic' && !isServerless)) { + return new SupertestWithBasicAuth(supertestWithoutAuth, user); + } + + const isBuiltIn = isBuiltInRole(user.role); + + if (!isBuiltIn) { + await samlAuth.setCustomRole(getRoleDefinitionForUser(user)); + } + + if (options.useCookieHeader) { + const cookieHeader = await samlAuth.getM2MApiCookieCredentialsWithRoleScope( + isBuiltIn ? user.role : 'customRole' + ); + return new SupertestWithRoleScope(cookieHeader, supertestWithoutAuth, samlAuth, options); + } + + // HTTP requests will be called with API key in header by default + const roleAuthc = await samlAuth.createM2mApiKeyWithRoleScope( + isBuiltIn ? user.role : 'customRole' + ); + return new SupertestWithRoleScope(roleAuthc, supertestWithoutAuth, samlAuth, options); + }, + }; +} diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/copy_to_space.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/copy_to_space.ts similarity index 86% rename from x-pack/test/spaces_api_integration/spaces_only/apis/copy_to_space.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/copy_to_space.ts index 3867d528ef374..a159097800f31 100644 --- a/x-pack/test/spaces_api_integration/spaces_only/apis/copy_to_space.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/copy_to_space.ts @@ -5,11 +5,10 @@ * 2.0. */ -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { copyToSpaceTestSuiteFactory } from '../../common/suites/copy_to_space'; +import { copyToSpaceTestSuiteFactory } from '../../../common/suites/copy_to_space.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export -export default function copyToSpacesOnlySuite(context: FtrProviderContext) { +export default function copyToSpacesOnlySuite(context: DeploymentAgnosticFtrProviderContext) { const { copyToSpaceTest, expectNoConflictsWithoutReferencesResult, diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/create.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/create.ts similarity index 67% rename from x-pack/test/spaces_api_integration/spaces_only/apis/create.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/create.ts index c98754d60eec3..b9b0e67f9796d 100644 --- a/x-pack/test/spaces_api_integration/spaces_only/apis/create.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/create.ts @@ -5,24 +5,18 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { SPACES } from '../../common/lib/spaces'; -import { createTestSuiteFactory } from '../../common/suites/create'; - -// eslint-disable-next-line import/no-default-export -export default function createSpacesOnlySuite({ getService }: FtrProviderContext) { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); +import { SPACES } from '../../../common/lib/spaces'; +import { createTestSuiteFactory } from '../../../common/suites/create.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; +export default function createSpacesOnlySuite(context: DeploymentAgnosticFtrProviderContext) { const { createTest, expectNewSpaceResult, expectConflictResponse, expectReservedSpecifiedResult, expectSolutionSpecifiedResult, - } = createTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest); + } = createTestSuiteFactory(context); describe('create', () => { [ diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/delete.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/delete.ts similarity index 61% rename from x-pack/test/spaces_api_integration/spaces_only/apis/delete.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/delete.ts index da50b9c37f190..7550d856fdbe6 100644 --- a/x-pack/test/spaces_api_integration/spaces_only/apis/delete.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/delete.ts @@ -5,20 +5,13 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { SPACES } from '../../common/lib/spaces'; -import { deleteTestSuiteFactory } from '../../common/suites/delete'; - -// eslint-disable-next-line import/no-default-export -export default function deleteSpaceTestSuite({ getService }: FtrProviderContext) { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); - const es = getService('es'); +import { SPACES } from '../../../common/lib/spaces'; +import { deleteTestSuiteFactory } from '../../../common/suites/delete.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; +export default function deleteSpaceTestSuite(context: DeploymentAgnosticFtrProviderContext) { const { deleteTest, expectEmptyResult, expectReservedSpaceResult, expectNotFound } = - deleteTestSuiteFactory(es, esArchiver, supertestWithoutAuth as unknown as SuperTest); + deleteTestSuiteFactory(context); describe('delete', () => { [ diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/get.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/get.ts similarity index 75% rename from x-pack/test/spaces_api_integration/spaces_only/apis/get.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/get.ts index 5cca880f2a7f4..7f73166b29e9e 100644 --- a/x-pack/test/spaces_api_integration/spaces_only/apis/get.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/get.ts @@ -5,19 +5,13 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { SPACES } from '../../common/lib/spaces'; -import { getTestSuiteFactory } from '../../common/suites/get'; - -// eslint-disable-next-line import/no-default-export -export default function getSpaceTestSuite({ getService }: FtrProviderContext) { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); +import { SPACES } from '../../../common/lib/spaces'; +import { getTestSuiteFactory } from '../../../common/suites/get.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; +export default function getSpaceTestSuite(context: DeploymentAgnosticFtrProviderContext) { const { getTest, createExpectResults, createExpectNotFoundResult, nonExistantSpaceId } = - getTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest); + getTestSuiteFactory(context); describe('get', () => { // valid spaces diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/get_all.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/get_all.ts similarity index 69% rename from x-pack/test/spaces_api_integration/spaces_only/apis/get_all.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/get_all.ts index 4b52f25eecbea..34e3f6c328e3d 100644 --- a/x-pack/test/spaces_api_integration/spaces_only/apis/get_all.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/get_all.ts @@ -5,21 +5,12 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; +import { SPACES } from '../../../common/lib/spaces'; +import { getAllTestSuiteFactory } from '../../../common/suites/get_all.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { SPACES } from '../../common/lib/spaces'; -import { getAllTestSuiteFactory } from '../../common/suites/get_all'; - -// eslint-disable-next-line import/no-default-export -export default function getAllSpacesTestSuite({ getService }: FtrProviderContext) { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); - - const { getAllTest, createExpectResults } = getAllTestSuiteFactory( - esArchiver, - supertestWithoutAuth as unknown as SuperTest - ); +export default function getAllSpacesTestSuite(context: DeploymentAgnosticFtrProviderContext) { + const { getAllTest, createExpectResults } = getAllTestSuiteFactory(context); describe('get all', () => { [ diff --git a/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/index.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/index.ts new file mode 100644 index 0000000000000..06b75d10c1099 --- /dev/null +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/index.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ +/* + * 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 { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; + +export default function spacesOnlyTestSuite({ + loadTestFile, +}: DeploymentAgnosticFtrProviderContext) { + describe('spaces api without security', function () { + this.tags('skipFIPS'); + loadTestFile(require.resolve('./copy_to_space')); + loadTestFile(require.resolve('./resolve_copy_to_space_conflicts')); + loadTestFile(require.resolve('./create')); + loadTestFile(require.resolve('./delete')); + loadTestFile(require.resolve('./get_all')); + loadTestFile(require.resolve('./get')); + loadTestFile(require.resolve('./update')); + }); +} diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/resolve_copy_to_space_conflicts.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/resolve_copy_to_space_conflicts.ts similarity index 84% rename from x-pack/test/spaces_api_integration/spaces_only/apis/resolve_copy_to_space_conflicts.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/resolve_copy_to_space_conflicts.ts index 9fc16ed64abb8..dacdeadf26f6e 100644 --- a/x-pack/test/spaces_api_integration/spaces_only/apis/resolve_copy_to_space_conflicts.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/resolve_copy_to_space_conflicts.ts @@ -5,11 +5,12 @@ * 2.0. */ -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { resolveCopyToSpaceConflictsSuite } from '../../common/suites/resolve_copy_to_space_conflicts'; +import { resolveCopyToSpaceConflictsSuite } from '../../../common/suites/resolve_copy_to_space_conflicts.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export -export default function resolveCopyToSpaceConflictsTestSuite(context: FtrProviderContext) { +export default function resolveCopyToSpaceConflictsTestSuite( + context: DeploymentAgnosticFtrProviderContext +) { const { resolveCopyToSpaceConflictsTest, createExpectNonOverriddenResponseWithReferences, diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/update.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/update.ts similarity index 63% rename from x-pack/test/spaces_api_integration/spaces_only/apis/update.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/update.ts index 4a4055896e546..9ff036f858999 100644 --- a/x-pack/test/spaces_api_integration/spaces_only/apis/update.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/apis/update.ts @@ -5,19 +5,12 @@ * 2.0. */ -import type { SuperTest } from 'supertest'; - -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import { SPACES } from '../../common/lib/spaces'; -import { updateTestSuiteFactory } from '../../common/suites/update'; - -// eslint-disable-next-line import/no-default-export -export default function updateSpaceTestSuite({ getService }: FtrProviderContext) { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); - +import { SPACES } from '../../../common/lib/spaces'; +import { updateTestSuiteFactory } from '../../../common/suites/update.agnostic'; +import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context'; +export default function updateSpaceTestSuite(context: DeploymentAgnosticFtrProviderContext) { const { updateTest, expectAlreadyExistsResult, expectDefaultSpaceResult, expectNotFound } = - updateTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest); + updateTestSuiteFactory(context); describe('update', () => { [ diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/copy_to_space_config_trial.ts b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/config.ts similarity index 52% rename from x-pack/test/spaces_api_integration/security_and_spaces/copy_to_space_config_trial.ts rename to x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/config.ts index da8834134f258..fe25ba69b3512 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/copy_to_space_config_trial.ts +++ b/x-pack/test/spaces_api_integration/deployment_agnostic/spaces_only/config.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { createTestConfig } from '../common/config'; +import { createTestConfig } from '../../common/config'; -// eslint-disable-next-line import/no-default-export -export default createTestConfig('security_and_spaces', { - license: 'trial', - testFiles: [require.resolve('./apis/copy_to_space')], +export default createTestConfig('spaces_only', { + disabledPlugins: ['security'], + license: 'basic', + testFiles: [require.resolve('./apis')], }); diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/copy_to_space/index.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/copy_to_space/index.ts deleted file mode 100644 index 79a6e69cb6f32..0000000000000 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/copy_to_space/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { createUsersAndRoles } from '../../../common/lib/create_users_and_roles'; - -// eslint-disable-next-line import/no-default-export -export default function ({ loadTestFile, getService }: FtrProviderContext) { - const es = getService('es'); - const supertest = getService('supertest'); - - describe('copy to space with security', function () { - before(async () => { - await createUsersAndRoles(es, supertest); - }); - - loadTestFile(require.resolve('./copy_to_space')); // ~ 19m 20s - }); -} diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/get_all.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/get_all.ts index d40413f9457e3..4392eb86e6125 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/get_all.ts +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/get_all.ts @@ -4,59 +4,28 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import type { SuperTest } from 'supertest'; +/* + * 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 { FtrProviderContext } from '../../common/ftr_provider_context'; import { AUTHENTICATION } from '../../common/lib/authentication'; import { SPACES } from '../../common/lib/spaces'; -import { getAllTestSuiteFactory } from '../../common/suites/get_all'; +import { getAllTestSuiteFactory } from '../../common/suites/get_all.agnostic'; // eslint-disable-next-line import/no-default-export -export default function getAllSpacesTestSuite({ getService }: FtrProviderContext) { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); - - const { getAllTest, createExpectResults, createExpectAllPurposesResults, expectRbacForbidden } = - getAllTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest); - - // these are used to determine expected results for tests where the `include_authorized_purposes` option is enabled - const authorizedAll = { - any: true, - copySavedObjectsIntoSpace: true, - findSavedObjects: true, - shareSavedObjectsIntoSpace: true, - }; - const authorizedRead = { - any: true, - copySavedObjectsIntoSpace: false, - findSavedObjects: true, - shareSavedObjectsIntoSpace: false, - }; +export default function getAllSpacesTestSuite(context: FtrProviderContext) { + // @ts-expect-error getAllTestSuiteFactory expects only DeploymentAgnosticFtrProviderContext + const { getAllTest, expectRbacForbidden } = getAllTestSuiteFactory(context); describe('get all', () => { - /* eslint-disable @typescript-eslint/naming-convention */ [ { spaceId: SPACES.DEFAULT.spaceId, users: { - noAccess: AUTHENTICATION.NOT_A_KIBANA_USER, - superuser: AUTHENTICATION.SUPERUSER, - allGlobally: AUTHENTICATION.KIBANA_RBAC_USER, - readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, - allAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, - readAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER, - allAtDefaultSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, - readAtDefaultSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER, - readSavedObjectsAtDefaultSpace: - AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_SAVED_OBJECTS_READ_USER, - allSavedObjectsAtDefaultSpace: - AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_SAVED_OBJECTS_ALL_USER, - readSavedObjectsAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_SAVED_OBJECTS_READ_USER, - allSavedObjectsAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_SAVED_OBJECTS_ALL_USER, - legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, - dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, - dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, machineLearningAdmin: AUTHENTICATION.MACHINE_LEARING_ADMIN, machineLearningUser: AUTHENTICATION.MACHINE_LEARNING_USER, monitoringUser: AUTHENTICATION.MONITORING_USER, @@ -65,423 +34,12 @@ export default function getAllSpacesTestSuite({ getService }: FtrProviderContext { spaceId: SPACES.SPACE_1.spaceId, users: { - noAccess: AUTHENTICATION.NOT_A_KIBANA_USER, - superuser: AUTHENTICATION.SUPERUSER, - allGlobally: AUTHENTICATION.KIBANA_RBAC_USER, - readGlobally: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER, - allAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER, - readAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER, - allAtDefaultSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER, - readAtDefaultSpace: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER, - readSavedObjectsAtDefaultSpace: - AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_SAVED_OBJECTS_READ_USER, - allSavedObjectsAtDefaultSpace: - AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_SAVED_OBJECTS_ALL_USER, - readSavedObjectsAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_SAVED_OBJECTS_READ_USER, - allSavedObjectsAtSpace_1: AUTHENTICATION.KIBANA_RBAC_SPACE_1_SAVED_OBJECTS_ALL_USER, - legacyAll: AUTHENTICATION.KIBANA_LEGACY_USER, - dualAll: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_USER, - dualRead: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER, machineLearningAdmin: AUTHENTICATION.MACHINE_LEARING_ADMIN, machineLearningUser: AUTHENTICATION.MACHINE_LEARNING_USER, monitoringUser: AUTHENTICATION.MONITORING_USER, }, }, - /* eslint-enable @typescript-eslint/naming-convention */ ].forEach((scenario) => { - getAllTest(`user with no access can't access any spaces from ${scenario.spaceId}`, { - spaceId: scenario.spaceId, - user: scenario.users.noAccess, - tests: { - exists: { - statusCode: 403, - response: expectRbacForbidden, - }, - copySavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - shareSavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - includeAuthorizedPurposes: { - statusCode: 403, - response: expectRbacForbidden, - }, - }, - }); - - getAllTest(`superuser can access all spaces from ${scenario.spaceId}`, { - spaceId: scenario.spaceId, - user: scenario.users.superuser, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - copySavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - shareSavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults( - authorizedAll, - 'default', - 'space_1', - 'space_2', - 'space_3' - ), - }, - }, - }); - - getAllTest(`rbac user with all globally can access all spaces from ${scenario.spaceId}`, { - spaceId: scenario.spaceId, - user: scenario.users.allGlobally, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - copySavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - shareSavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults( - authorizedAll, - 'default', - 'space_1', - 'space_2', - 'space_3' - ), - }, - }, - }); - - getAllTest(`dual-privileges user can access all spaces from ${scenario.spaceId}`, { - spaceId: scenario.spaceId, - user: scenario.users.dualAll, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - copySavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - shareSavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults( - authorizedAll, - 'default', - 'space_1', - 'space_2', - 'space_3' - ), - }, - }, - }); - - getAllTest(`legacy user can't access any spaces from ${scenario.spaceId}`, { - spaceId: scenario.spaceId, - user: scenario.users.legacyAll, - tests: { - exists: { - statusCode: 403, - response: expectRbacForbidden, - }, - copySavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - shareSavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - includeAuthorizedPurposes: { - statusCode: 403, - response: expectRbacForbidden, - }, - }, - }); - - getAllTest(`rbac user with read globally can access all spaces from ${scenario.spaceId}`, { - spaceId: scenario.spaceId, - user: scenario.users.readGlobally, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - copySavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - shareSavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults( - authorizedRead, - 'default', - 'space_1', - 'space_2', - 'space_3' - ), - }, - }, - }); - - getAllTest(`dual-privileges readonly user can access all spaces from ${scenario.spaceId}`, { - spaceId: scenario.spaceId, - user: scenario.users.dualRead, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('default', 'space_1', 'space_2', 'space_3'), - }, - copySavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - shareSavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults( - authorizedRead, - 'default', - 'space_1', - 'space_2', - 'space_3' - ), - }, - }, - }); - - getAllTest(`rbac user with all at space_1 can access space_1 from ${scenario.spaceId}`, { - spaceId: scenario.spaceId, - user: scenario.users.allAtSpace_1, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('space_1'), - }, - copySavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('space_1'), - }, - shareSavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('space_1'), - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults(authorizedAll, 'space_1'), - }, - }, - }); - - getAllTest(`rbac user with read at space_1 can access space_1 from ${scenario.spaceId}`, { - spaceId: scenario.spaceId, - user: scenario.users.readAtSpace_1, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('space_1'), - }, - copySavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - shareSavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults(authorizedRead, 'space_1'), - }, - }, - }); - - getAllTest( - `rbac user with all at default space can access default from ${scenario.spaceId}`, - { - spaceId: scenario.spaceId, - user: scenario.users.allAtDefaultSpace, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('default'), - }, - copySavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('default'), - }, - shareSavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('default'), - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults(authorizedAll, 'default'), - }, - }, - } - ); - - getAllTest( - `rbac user with read at default space can access default from ${scenario.spaceId}`, - { - spaceId: scenario.spaceId, - user: scenario.users.readAtDefaultSpace, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('default'), - }, - copySavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - shareSavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults(authorizedRead, 'default'), - }, - }, - } - ); - - getAllTest( - `rbac user with saved objects management all at default space can access default from ${scenario.spaceId}`, - { - spaceId: scenario.spaceId, - user: scenario.users.allSavedObjectsAtDefaultSpace, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('default'), - }, - copySavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('default'), - }, - shareSavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('default'), - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults(authorizedAll, 'default'), - }, - }, - } - ); - - getAllTest( - `rbac user with saved objects management read at default space can access default from ${scenario.spaceId}`, - { - spaceId: scenario.spaceId, - user: scenario.users.readSavedObjectsAtDefaultSpace, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('default'), - }, - copySavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - shareSavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults(authorizedRead, 'default'), - }, - }, - } - ); - - getAllTest( - `rbac user with saved objects management all at space_1 space can access space_1 from ${scenario.spaceId}`, - { - spaceId: scenario.spaceId, - user: scenario.users.allSavedObjectsAtSpace_1, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('space_1'), - }, - copySavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('space_1'), - }, - shareSavedObjectsPurpose: { - statusCode: 200, - response: createExpectResults('space_1'), - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults(authorizedAll, 'space_1'), - }, - }, - } - ); - - getAllTest( - `rbac user with saved objects management read at space_1 space can access space_1 from ${scenario.spaceId}`, - { - spaceId: scenario.spaceId, - user: scenario.users.readSavedObjectsAtSpace_1, - tests: { - exists: { - statusCode: 200, - response: createExpectResults('space_1'), - }, - copySavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - shareSavedObjectsPurpose: { - statusCode: 403, - response: expectRbacForbidden, - }, - includeAuthorizedPurposes: { - statusCode: 200, - response: createExpectAllPurposesResults(authorizedRead, 'space_1'), - }, - }, - } - ); - getAllTest(`machine_learning_admin can't access any spaces from ${scenario.spaceId}`, { spaceId: scenario.spaceId, user: scenario.users.machineLearningAdmin, diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.ts index 756d47308f7fc..197d276564a57 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.ts +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/index.ts @@ -19,13 +19,7 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) { }); // total runtime ~ 17m - loadTestFile(require.resolve('./resolve_copy_to_space_conflicts')); // ~ 10m - loadTestFile(require.resolve('./create')); // ~ 2m - loadTestFile(require.resolve('./delete')); // ~ 1m 20s - loadTestFile(require.resolve('./get_all')); // ~ 50s loadTestFile(require.resolve('./get_shareable_references')); // ~ 30s - loadTestFile(require.resolve('./get')); // ~ 30s - loadTestFile(require.resolve('./update')); // ~ 30s loadTestFile(require.resolve('./update_objects_spaces')); // ~ 1m loadTestFile(require.resolve('./disable_legacy_url_aliases')); // ~ 30s }); diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/config_basic.ts b/x-pack/test/spaces_api_integration/security_and_spaces/config_basic.ts index 902f8baf026a8..aba9bc9a92d08 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/config_basic.ts +++ b/x-pack/test/spaces_api_integration/security_and_spaces/config_basic.ts @@ -8,4 +8,7 @@ import { createTestConfig } from '../common/config'; // eslint-disable-next-line import/no-default-export -export default createTestConfig('security_and_spaces', { license: 'basic' }); +export default createTestConfig('security_and_spaces', { + license: 'basic', + testFiles: [require.resolve('./apis'), require.resolve('./apis/get_all')], +}); diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/config_trial.ts b/x-pack/test/spaces_api_integration/security_and_spaces/config_trial.ts index 0481a6009d722..c988a59d23a22 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/config_trial.ts +++ b/x-pack/test/spaces_api_integration/security_and_spaces/config_trial.ts @@ -8,4 +8,7 @@ import { createTestConfig } from '../common/config'; // eslint-disable-next-line import/no-default-export -export default createTestConfig('security_and_spaces', { license: 'trial' }); +export default createTestConfig('security_and_spaces', { + license: 'trial', + testFiles: [require.resolve('./apis')], +}); diff --git a/x-pack/test/spaces_api_integration/spaces_only/apis/index.ts b/x-pack/test/spaces_api_integration/spaces_only/apis/index.ts index 433ce2c6c444c..a85a84d3f723b 100644 --- a/x-pack/test/spaces_api_integration/spaces_only/apis/index.ts +++ b/x-pack/test/spaces_api_integration/spaces_only/apis/index.ts @@ -11,14 +11,7 @@ import type { FtrProviderContext } from '../../common/ftr_provider_context'; export default function spacesOnlyTestSuite({ loadTestFile }: FtrProviderContext) { describe('spaces api without security', function () { this.tags('skipFIPS'); - loadTestFile(require.resolve('./copy_to_space')); - loadTestFile(require.resolve('./resolve_copy_to_space_conflicts')); - loadTestFile(require.resolve('./create')); - loadTestFile(require.resolve('./delete')); - loadTestFile(require.resolve('./get_all')); loadTestFile(require.resolve('./get_shareable_references')); - loadTestFile(require.resolve('./get')); - loadTestFile(require.resolve('./update')); loadTestFile(require.resolve('./update_objects_spaces')); loadTestFile(require.resolve('./disable_legacy_url_aliases')); });