[Spaces] Moved tests to agnostic setup (#200606)

## Summary

Moved space tests to deployment agnostic setup.


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

__Closes: https://github.com/elastic/kibana/issues/194584__

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Elena Shostak 2025-01-23 15:15:11 +01:00 committed by GitHub
parent 811c539fff
commit ac5366a70e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 1911 additions and 985 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -128,3 +128,4 @@ system_indices_superuser:
privileges: ['*']
resources: ['*']
run_as: ['*']

View file

@ -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',
},
},
],
};

View file

@ -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,

View file

@ -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"
},

View file

@ -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=="
}

View file

@ -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=="
}

View file

@ -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=="
}

View file

@ -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];

View file

@ -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: {

View file

@ -10,4 +10,5 @@ export type DescribeFn = (text: string, fn: () => void) => void;
export interface TestDefinitionAuthentication {
username?: string;
password?: string;
role: string;
}

View file

@ -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,
};

View file

@ -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);
}
}

View file

@ -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<LegacyUrlAlias[]> {
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<FtrProviderContext, 'getService'>) {
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',
},
},
},
],
},
},
},
});
},
};
}

View file

@ -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<string, any>;
@ -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<any>;
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);

View file

@ -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<any>) {
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<any
const makeCreateTest =
(describeFn: DescribeFn) =>
(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<any
it(`should return ${tests.newSpace.statusCode} ${scenario}`, async () => {
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<any
it(`should return ${tests.alreadyExists.statusCode} ${scenario}`, async () => {
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<any
it(`should return ${tests.reservedSpecified.statusCode} and ignore _reserved ${scenario}`, async () => {
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<any
describe('when solution is specified', () => {
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<any
solution: 'es',
disabledFeatures: [],
})
.expect(tests.solutionSpecified.statusCode)
.then(tests.solutionSpecified.response);
.expect(statusCode)
.then(isServerless ? noop : tests.solutionSpecified.response);
});
});
});

View file

@ -5,12 +5,13 @@
* 2.0.
*/
import type { Client } from '@elastic/elasticsearch';
import type { SuperTest } from 'supertest';
import { ALL_SAVED_OBJECT_INDICES } from '@kbn/core-saved-objects-server';
import expect from '@kbn/expect';
import type {
DeploymentAgnosticFtrProviderContext,
SupertestWithRoleScopeType,
} from '../../deployment_agnostic/ftr_provider_context';
import { MULTI_NAMESPACE_SAVED_OBJECT_TEST_CASES as CASES } from '../lib/saved_object_test_cases';
import { getAggregatedSpaceData, getTestScenariosForSpace } from '../lib/space_test_utils';
import type { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
@ -32,7 +33,12 @@ interface DeleteTestDefinition {
tests: DeleteTests;
}
export function deleteTestSuiteFactory(es: Client, esArchiver: any, supertest: SuperTest<any>) {
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: 20,
countByType: {
doc_count_error_upper_bound: 0,
sum_other_doc_count: 0,
buckets: [
{
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,
},
],
},
},
{
key: 'space_1',
doc_count: 10,
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: 6,
},
{
key: 'visualization',
doc_count: 3,
},
{
key: 'dashboard',
doc_count: 1,
},
],
},
},
{
doc_count: 5,
key: 'space_1',
key: '*',
doc_count: 3,
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: 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<Record<string, any>>({
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);
});

View file

@ -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 }],

View file

@ -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<any>) {
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<any>)
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<any>)
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<any>)
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);
});

View file

@ -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<any>) {
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<any
const makeGetAllTest =
(describeFn: DescribeFn) =>
(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<any
return supertest
.get(`${urlPrefix}/api/spaces/space`)
.query({ purpose: 'copySavedObjectsIntoSpace' })
.auth(user.username, user.password)
.expect(tests.copySavedObjectsPurpose.statusCode)
.then(tests.copySavedObjectsPurpose.response);
});
@ -173,7 +207,6 @@ export function getAllTestSuiteFactory(esArchiver: any, supertest: SuperTest<any
return supertest
.get(`${urlPrefix}/api/spaces/space`)
.query({ purpose: 'shareSavedObjectsIntoSpace' })
.auth(user.username, user.password)
.expect(tests.copySavedObjectsPurpose.statusCode)
.then(tests.copySavedObjectsPurpose.response);
});
@ -184,7 +217,6 @@ export function getAllTestSuiteFactory(esArchiver: any, supertest: SuperTest<any
return supertest
.get(`${urlPrefix}/api/spaces/space`)
.query({ include_authorized_purposes: true })
.auth(user.username, user.password)
.expect(tests.includeAuthorizedPurposes.statusCode)
.then(tests.includeAuthorizedPurposes.response);
});

View file

@ -43,9 +43,9 @@ const {
SPACE_2: { spaceId: SPACE_2_ID },
} = SPACES;
export const TEST_CASE_OBJECTS: Record<string, { type: string; id: string }> = 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<string, SavedObjectReferenceWithContext[]> = {
@ -54,7 +54,7 @@ export const EXPECTED_RESULTS: Record<string, SavedObjectReferenceWithContext[]>
...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<string, SavedObjectReferenceWithContext[]>
},
{ ...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<string, SavedObjectReferenceWithContext[]>
...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<string, SavedObjectReferenceWithContext[]>
},
{ ...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<string, SavedObjectReferenceWithContext[]>
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<string, SavedObjectReferenceWithContext[]>
...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<string, SavedObjectReferenceWithContext[]>
},
{ ...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)

View file

@ -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<string, any>;
@ -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<any>;
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<SavedObject<any>> => {
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<SavedObject<any>> => {
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);

View file

@ -4,11 +4,19 @@
* 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 { SuperTest } from 'supertest';
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<any>) {
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<any
const makeUpdateTest =
(describeFn: DescribeFn) =>
(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<any
it(`should return ${tests.defaultSpace.statusCode}`, async () => {
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<any
it(`should return ${tests.newSpace.statusCode}`, async () => {
return supertest
.put(`${getUrlPrefix(spaceId)}/api/spaces/space/marketing`)
.auth(user.username, user.password)
.send({
name: 'marketing',
id: 'marketing',

View file

@ -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,

View file

@ -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<typeof services, {}>;
export type { SupertestWithRoleScopeType } from './services';

View file

@ -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: {

View file

@ -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'));
});
}

View file

@ -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<any>);
} = 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,

View file

@ -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<any>);
} = deleteTestSuiteFactory(context);
describe('delete', () => {
[

View file

@ -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<any>);
} = getTestSuiteFactory(context);
describe('get', () => {
[

View file

@ -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'),
},
},
}
);
});
});
}

View file

@ -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'));
});
}

View file

@ -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'));
});
}

View file

@ -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: {

View file

@ -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<any>);
} = updateTestSuiteFactory(context);
describe('update', () => {
[

View file

@ -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',
},
});

View file

@ -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',
},
});

View file

@ -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')],
});

View file

@ -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',
},
});

View file

@ -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')],
});

View file

@ -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',
},
});

View file

@ -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,
};

View file

@ -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);
},
};
}

View file

@ -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,

View file

@ -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<any>);
} = createTestSuiteFactory(context);
describe('create', () => {
[

View file

@ -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<any>);
deleteTestSuiteFactory(context);
describe('delete', () => {
[

View file

@ -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<any>);
getTestSuiteFactory(context);
describe('get', () => {
// valid spaces

View file

@ -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<any>
);
export default function getAllSpacesTestSuite(context: DeploymentAgnosticFtrProviderContext) {
const { getAllTest, createExpectResults } = getAllTestSuiteFactory(context);
describe('get all', () => {
[

View file

@ -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'));
});
}

View file

@ -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,

View file

@ -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<any>);
updateTestSuiteFactory(context);
describe('update', () => {
[

View file

@ -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')],
});

View file

@ -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
});
}

View file

@ -4,59 +4,28 @@
* 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 { SuperTest } from 'supertest';
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<any>);
// 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,

View file

@ -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
});

View file

@ -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')],
});

View file

@ -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')],
});

View file

@ -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'));
});