From 6c132649c0b20100551eeccf45e46426defb5feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Fri, 20 Sep 2024 12:35:05 +0200 Subject: [PATCH 01/23] Explicitly sets spaces and roles HTTP API endpoints access to public --- .../plugins/security/server/routes/authorization/roles/delete.ts | 1 + x-pack/plugins/security/server/routes/authorization/roles/get.ts | 1 + .../security/server/routes/authorization/roles/get_all.ts | 1 + .../plugins/security/server/routes/authorization/roles/post.ts | 1 + x-pack/plugins/security/server/routes/authorization/roles/put.ts | 1 + x-pack/plugins/spaces/server/routes/api/external/delete.ts | 1 + x-pack/plugins/spaces/server/routes/api/external/get.ts | 1 + x-pack/plugins/spaces/server/routes/api/external/get_all.ts | 1 + x-pack/plugins/spaces/server/routes/api/external/post.ts | 1 + x-pack/plugins/spaces/server/routes/api/external/put.ts | 1 + 10 files changed, 10 insertions(+) diff --git a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts index 8a481c4b60cbf..022e574181425 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts @@ -16,6 +16,7 @@ export function defineDeleteRolesRoutes({ router }: RouteDefinitionParams) { { path: '/api/security/role/{name}', options: { + access: 'public', summary: `Delete a role`, }, validate: { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get.ts b/x-pack/plugins/security/server/routes/authorization/roles/get.ts index 9109d89d956fd..ec2208341dc16 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.ts @@ -22,6 +22,7 @@ export function defineGetRolesRoutes({ { path: '/api/security/role/{name}', options: { + access: 'public', summary: `Get a role`, }, validate: { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts index a7d995f0a2639..ed31aedba7f31 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts @@ -22,6 +22,7 @@ export function defineGetAllRolesRoutes({ { path: '/api/security/role', options: { + access: 'public', summary: `Get all roles`, }, validate: false, diff --git a/x-pack/plugins/security/server/routes/authorization/roles/post.ts b/x-pack/plugins/security/server/routes/authorization/roles/post.ts index 07b9886c4072c..37967d208bf3a 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/post.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/post.ts @@ -43,6 +43,7 @@ export function defineBulkCreateOrUpdateRolesRoutes({ { path: '/api/security/roles', options: { + access: 'public', summary: 'Create or update roles', }, validate: { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.ts index 57271235add36..6175ba6f4d64f 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.ts @@ -24,6 +24,7 @@ export function definePutRolesRoutes({ { path: '/api/security/role/{name}', options: { + access: 'public', summary: `Create or update a role`, }, validate: { diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.ts index 30a6f85d6994b..c39f872b86a00 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/delete.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.ts @@ -21,6 +21,7 @@ export function initDeleteSpacesApi(deps: ExternalRouteDeps) { { path: '/api/spaces/space/{id}', options: { + access: 'public', description: `Delete a space`, }, validate: { diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.ts b/x-pack/plugins/spaces/server/routes/api/external/get.ts index 99bc646994b5c..56592cc531fd4 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get.ts @@ -19,6 +19,7 @@ export function initGetSpaceApi(deps: ExternalRouteDeps) { { path: '/api/spaces/space/{id}', options: { + access: 'public', description: `Get a space`, }, validate: { diff --git a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts index 5b972f6491860..b7b8fc88b85c1 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts @@ -19,6 +19,7 @@ export function initGetAllSpacesApi(deps: ExternalRouteDeps) { { path: '/api/spaces/space', options: { + access: 'public', description: `Get all spaces`, }, validate: { diff --git a/x-pack/plugins/spaces/server/routes/api/external/post.ts b/x-pack/plugins/spaces/server/routes/api/external/post.ts index 31dda1285f06a..8644c0c00e102 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/post.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/post.ts @@ -21,6 +21,7 @@ export function initPostSpacesApi(deps: ExternalRouteDeps) { { path: '/api/spaces/space', options: { + access: 'public', description: `Create a space`, }, validate: { diff --git a/x-pack/plugins/spaces/server/routes/api/external/put.ts b/x-pack/plugins/spaces/server/routes/api/external/put.ts index e1defabee7103..25f0d70d75dc3 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/put.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/put.ts @@ -21,6 +21,7 @@ export function initPutSpacesApi(deps: ExternalRouteDeps) { { path: '/api/spaces/space/{id}', options: { + access: 'public', description: `Update a space`, }, validate: { From a4a640f4f6be926b44f513c52366cb9780761674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Fri, 20 Sep 2024 17:29:00 +0200 Subject: [PATCH 02/23] Updates API integration tests --- .../test_suites/common/management/index.ts | 4 +- .../management/multiple_spaces_enabled.ts | 72 ++--- .../test_suites/common/management/spaces.ts | 256 +++++++++++------- .../common/platform_security/authorization.ts | 89 +++--- .../common/platform_security/index.ts | 26 +- .../roles_routes_feature_flag.ts | 2 +- .../security/common_configs/config.group1.ts | 34 +-- 7 files changed, 274 insertions(+), 209 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts index 7694845a4ed0f..431405df893d2 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts @@ -11,8 +11,8 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('Management', function () { this.tags(['esGate']); - loadTestFile(require.resolve('./rollups')); - loadTestFile(require.resolve('./scripted_fields')); + // loadTestFile(require.resolve('./rollups')); + // loadTestFile(require.resolve('./scripted_fields')); loadTestFile(require.resolve('./spaces')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts index e5c4053b97e73..08882694d9a0f 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts @@ -48,7 +48,7 @@ export default function ({ getService }: FtrProviderContext) { describe('spaces', function () { before(async () => { supertestAdminWithApiKey = await roleScopedSupertest.getSupertestWithRoleScope('admin', { - withInternalHeaders: true, + withCommonHeaders: true, }); supertestAdminWithCookieCredentials = await roleScopedSupertest.getSupertestWithRoleScope( 'admin', @@ -242,42 +242,48 @@ export default function ({ getService }: FtrProviderContext) { }); }); - // These tests just test access to API endpoints + // These tests just test access to API endpoints, in this case + // when accessed without internal headers they will return 400 // They will be included in deployment agnostic testing once spaces // are enabled in production. describe(`Access`, () => { - it('#copyToSpace', async () => { - const { body, status } = await supertestAdminWithApiKey.post( - '/api/spaces/_copy_saved_objects' - ); - svlCommonApi.assertResponseStatusCode(400, status, body); - }); - it('#resolveCopyToSpaceErrors', async () => { - const { body, status } = await supertestAdminWithApiKey.post( - '/api/spaces/_resolve_copy_saved_objects_errors' - ); - svlCommonApi.assertResponseStatusCode(400, status, body); - }); - it('#updateObjectsSpaces', async () => { - const { body, status } = await supertestAdminWithApiKey.post( - '/api/spaces/_update_objects_spaces' - ); - svlCommonApi.assertResponseStatusCode(400, status, body); - }); - it('#getShareableReferences', async () => { - const { body, status } = await supertestAdminWithApiKey - .post('/api/spaces/_get_shareable_references') - .send({ - objects: [{ type: 'a', id: 'a' }], - }); - svlCommonApi.assertResponseStatusCode(200, status, body); + describe(`internal`, () => { + it('#copyToSpace', async () => { + const { body, status } = await supertestAdminWithApiKey.post( + '/api/spaces/_copy_saved_objects' + ); + svlCommonApi.assertResponseStatusCode(400, status, body); + }); + it('#resolveCopyToSpaceErrors', async () => { + const { body, status } = await supertestAdminWithApiKey.post( + '/api/spaces/_resolve_copy_saved_objects_errors' + ); + svlCommonApi.assertResponseStatusCode(400, status, body); + }); + it('#updateObjectsSpaces', async () => { + const { body, status } = await supertestAdminWithApiKey.post( + '/api/spaces/_update_objects_spaces' + ); + svlCommonApi.assertResponseStatusCode(400, status, body); + }); + it('#getShareableReferences', async () => { + const { body, status } = await supertestAdminWithApiKey + .post('/api/spaces/_get_shareable_references') + .send({ + objects: [{ type: 'a', id: 'a' }], + }); + svlCommonApi.assertResponseStatusCode(400, status, body); + }); }); - it('#disableLegacyUrlAliases', async () => { - const { body, status } = await supertestAdminWithApiKey.post( - '/api/spaces/_disable_legacy_url_aliases' - ); - // without a request body we would normally a 400 bad request if the endpoint was registered - svlCommonApi.assertApiNotFound(body, status); + + describe(`disabled`, () => { + it('#disableLegacyUrlAliases', async () => { + const { body, status } = await supertestAdminWithApiKey.post( + '/api/spaces/_disable_legacy_url_aliases' + ); + // without a request body we would normally a 400 bad request if the endpoint was registered + svlCommonApi.assertApiNotFound(body, status); + }); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/management/spaces.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/spaces.ts index 7014dcd6100df..4bde897e714af 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/management/spaces.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/spaces.ts @@ -19,7 +19,9 @@ export default function ({ getService }: FtrProviderContext) { describe('spaces', function () { before(async () => { // admin is the only predefined role that will work for all 3 solutions - supertestAdminWithApiKey = await roleScopedSupertest.getSupertestWithRoleScope('admin'); + supertestAdminWithApiKey = await roleScopedSupertest.getSupertestWithRoleScope('admin', { + withCommonHeaders: true, + }); supertestAdminWithCookieCredentials = await roleScopedSupertest.getSupertestWithRoleScope( 'admin', { @@ -33,93 +35,82 @@ export default function ({ getService }: FtrProviderContext) { }); describe('route access', () => { - it('#delete', async () => { - const { body, status } = await supertestAdminWithApiKey - .delete('/api/spaces/space/default') - .set(samlAuth.getInternalRequestHeader()); - - svlCommonApi.assertResponseStatusCode(400, status, body); - }); - - // Skipped due to change in QA environment for role management and spaces - // TODO: revisit once the change is rolled out to all environments - it.skip('#create', async () => { - const { body, status } = await supertestAdminWithApiKey - .post('/api/spaces/space') - .set(samlAuth.getInternalRequestHeader()) - .send({ + describe('public (CRUD)', () => { + // Skipped due to change in QA environment for role management and spaces + // TODO: revisit once the change is rolled out to all environments + it.skip('#create', async () => { + const { body, status } = await supertestAdminWithApiKey.post('/api/spaces/space').send({ id: 'custom', name: 'Custom', disabledFeatures: [], }); - svlCommonApi.assertResponseStatusCode(400, status, body); - }); + svlCommonApi.assertResponseStatusCode(400, status, body); - it('#update requires internal header', async () => { - const { body, status } = await supertestAdminWithApiKey - .put('/api/spaces/space/default') - .set(samlAuth.getInternalRequestHeader()) - .send({ - id: 'default', - name: 'UPDATED!', - disabledFeatures: [], + // Should fail due to maximum spaces limit, not because of lacking internal header + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: + 'Unable to create Space, this exceeds the maximum number of spaces set by the xpack.spaces.maxSpaces setting', }); + }); - svlCommonApi.assertResponseStatusCode(200, status, body); - }); - - it('#copyToSpace', async () => { - const { body, status } = await supertestAdminWithApiKey - .post('/api/spaces/_copy_saved_objects') - .set(samlAuth.getInternalRequestHeader()); + it('#get', async () => { + const { body, status } = await supertestAdminWithApiKey.get('/api/spaces/space/default'); + // expect success because we're using the internal header + expect(body).toEqual(expect.objectContaining({ id: 'default' })); + expect(status).toBe(200); + }); - svlCommonApi.assertResponseStatusCode(400, status, body); - }); + it('#getAll', async () => { + const { body, status } = await supertestAdminWithApiKey.get('/api/spaces/space'); + // expect success because we're using the internal header + expect(body).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: 'default', + }), + ]) + ); + expect(status).toBe(200); + }); - it('#resolveCopyToSpaceErrors', async () => { - const { body, status } = await supertestAdminWithApiKey - .post('/api/spaces/_resolve_copy_saved_objects_errors') - .set(samlAuth.getInternalRequestHeader()); + it('#update', async () => { + const { body, status } = await supertestAdminWithApiKey + .put('/api/spaces/space/default') + .send({ + id: 'default', + name: 'UPDATED!', + disabledFeatures: [], + }); - svlCommonApi.assertResponseStatusCode(400, status, body); - }); + svlCommonApi.assertResponseStatusCode(200, status, body); + }); - it('#updateObjectsSpaces', async () => { - const { body, status } = await supertestAdminWithApiKey - .post('/api/spaces/_update_objects_spaces') - .set(samlAuth.getInternalRequestHeader()); + it('#delete', async () => { + const { body, status } = await supertestAdminWithApiKey.delete( + '/api/spaces/space/default' + ); - svlCommonApi.assertResponseStatusCode(400, status, body); - }); + svlCommonApi.assertResponseStatusCode(400, status, body); - it('#getShareableReferences', async () => { - const { body, status } = await supertestAdminWithApiKey - .post('/api/spaces/_get_shareable_references') - .set(samlAuth.getInternalRequestHeader()) - .send({ - objects: [{ type: 'a', id: 'a' }], + // 400 with specific reason - cannot delete the default space + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: 'The default space cannot be deleted because it is reserved.', }); - - svlCommonApi.assertResponseStatusCode(200, status, body); - }); - - it('#disableLegacyUrlAliases', async () => { - const { body, status } = await supertestAdminWithApiKey - .post('/api/spaces/_disable_legacy_url_aliases') - .set(samlAuth.getInternalRequestHeader()); - - // without a request body we would normally a 400 bad request if the endpoint was registered - svlCommonApi.assertApiNotFound(body, status); + }); }); describe('internal', () => { - it('#get requires internal header', async () => { + it('#getActiveSpace requires internal header', async () => { let body: any; let status: number; - ({ body, status } = await supertestAdminWithApiKey - .get('/api/spaces/space/default') + ({ body, status } = await supertestAdminWithCookieCredentials + .get('/internal/spaces/_active_space') .set(samlAuth.getCommonRequestHeader())); // expect a rejection because we're not using the internal header expect(body).toEqual({ @@ -131,8 +122,8 @@ export default function ({ getService }: FtrProviderContext) { }); expect(status).toBe(400); - ({ body, status } = await supertestAdminWithApiKey - .get('/api/spaces/space/default') + ({ body, status } = await supertestAdminWithCookieCredentials + .get('/internal/spaces/_active_space') .set(samlAuth.getInternalRequestHeader())); // expect success because we're using the internal header expect(body).toEqual( @@ -143,64 +134,131 @@ export default function ({ getService }: FtrProviderContext) { expect(status).toBe(200); }); - it('#getAll requires internal header', async () => { + it('#copyToSpace requires internal header', async () => { let body: any; let status: number; + ({ body, status } = await supertestAdminWithApiKey.post( + '/api/spaces/_copy_saved_objects' + )); + // expect a rejection because we're not using the internal header + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: expect.stringContaining( + 'method [post] exists but is not available with the current configuration' + ), + }); + ({ body, status } = await supertestAdminWithApiKey - .get('/api/spaces/space') - .set(samlAuth.getCommonRequestHeader())); + .post('/api/spaces/_copy_saved_objects') + .set(samlAuth.getInternalRequestHeader())); + + svlCommonApi.assertResponseStatusCode(400, status, body); + + // expect 400 for missing body + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: '[request body]: expected a plain object value, but found [null] instead.', + }); + }); + + it('#resolveCopyToSpaceErrors requires internal header', async () => { + let body: any; + let status: number; + + ({ body, status } = await supertestAdminWithApiKey.post( + '/api/spaces/_resolve_copy_saved_objects_errors' + )); // expect a rejection because we're not using the internal header expect(body).toEqual({ statusCode: 400, error: 'Bad Request', message: expect.stringContaining( - 'method [get] exists but is not available with the current configuration' + 'method [post] exists but is not available with the current configuration' ), }); - expect(status).toBe(400); ({ body, status } = await supertestAdminWithApiKey - .get('/api/spaces/space') + .post('/api/spaces/_resolve_copy_saved_objects_errors') .set(samlAuth.getInternalRequestHeader())); - // expect success because we're using the internal header - expect(body).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: 'default', - }), - ]) - ); - expect(status).toBe(200); + + svlCommonApi.assertResponseStatusCode(400, status, body); + + // expect 400 for missing body + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: '[request body]: expected a plain object value, but found [null] instead.', + }); }); - it('#getActiveSpace requires internal header', async () => { + it('#updateObjectsSpaces requires internal header', async () => { let body: any; let status: number; - ({ body, status } = await supertestAdminWithCookieCredentials - .get('/internal/spaces/_active_space') - .set(samlAuth.getCommonRequestHeader())); + ({ body, status } = await supertestAdminWithApiKey.post( + '/api/spaces/_update_objects_spaces' + )); // expect a rejection because we're not using the internal header expect(body).toEqual({ statusCode: 400, error: 'Bad Request', message: expect.stringContaining( - 'method [get] exists but is not available with the current configuration' + 'method [post] exists but is not available with the current configuration' ), }); - expect(status).toBe(400); - ({ body, status } = await supertestAdminWithCookieCredentials - .get('/internal/spaces/_active_space') + ({ body, status } = await supertestAdminWithApiKey + .post('/api/spaces/_update_objects_spaces') .set(samlAuth.getInternalRequestHeader())); - // expect success because we're using the internal header - expect(body).toEqual( - expect.objectContaining({ - id: 'default', - }) - ); - expect(status).toBe(200); + + svlCommonApi.assertResponseStatusCode(400, status, body); + + // expect 400 for missing body + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: '[request body]: expected a plain object value, but found [null] instead.', + }); + }); + + it('#getShareableReferences requires internal header', async () => { + let body: any; + let status: number; + + ({ body, status } = await supertestAdminWithApiKey.post( + '/api/spaces/_get_shareable_references' + )); + // expect a rejection because we're not using the internal header + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: expect.stringContaining( + 'method [post] exists but is not available with the current configuration' + ), + }); + + ({ body, status } = await supertestAdminWithApiKey + .post('/api/spaces/_get_shareable_references') + .set(samlAuth.getInternalRequestHeader()) + .send({ + objects: [{ type: 'a', id: 'a' }], + })); + + svlCommonApi.assertResponseStatusCode(200, status, body); + }); + }); + + describe('disabled', () => { + it('#disableLegacyUrlAliases', async () => { + const { body, status } = await supertestAdminWithApiKey + .post('/api/spaces/_disable_legacy_url_aliases') + .set(samlAuth.getInternalRequestHeader()); + + // without a request body we would normally a 400 bad request if the endpoint was registered + svlCommonApi.assertApiNotFound(body, status); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts index 4c77607d7d844..806faefa5cd93 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts @@ -37,65 +37,66 @@ export default function ({ getService }: FtrProviderContext) { 'admin', { useCookieHeader: true, - withInternalHeaders: true, } ); supertestAdminWithApiKey = await roleScopedSupertest.getSupertestWithRoleScope('admin', { - withInternalHeaders: true, + withCommonHeaders: true, }); }); after(async () => { await supertestAdminWithApiKey.destroy(); }); describe('route access', () => { - describe('internal', () => { - describe('disabled', () => { - // Skipped due to change in QA environment for role management and spaces - // TODO: revisit once the change is rolled out to all environments - it.skip('get all privileges', async () => { - const { body, status } = await supertestAdminWithApiKey.get('/api/security/privileges'); - svlCommonApi.assertApiNotFound(body, status); - }); + describe('disabled', () => { + // Skipped due to change in QA environment for role management and spaces + // TODO: revisit once the change is rolled out to all environments + it.skip('get all privileges', async () => { + const { body, status } = await supertestAdminWithApiKey.get('/api/security/privileges'); + svlCommonApi.assertApiNotFound(body, status); + }); - // Skipped due to change in QA environment for role management and spaces - // TODO: revisit once the change is rolled out to all environments - it.skip('get built-in elasticsearch privileges', async () => { - const { body, status } = await supertestAdminWithCookieCredentials.get( - '/internal/security/esPrivileges/builtin' - ); - svlCommonApi.assertApiNotFound(body, status); - }); + // Skipped due to change in QA environment for role management and spaces + // TODO: revisit once the change is rolled out to all environments + it.skip('get built-in elasticsearch privileges', async () => { + const { body, status } = await supertestAdminWithCookieCredentials.get( + '/internal/security/esPrivileges/builtin' + ); + svlCommonApi.assertApiNotFound(body, status); + }); - it('create/update roleAuthc', async () => { - const { body, status } = await supertestAdminWithApiKey.put('/api/security/role/test'); - svlCommonApi.assertApiNotFound(body, status); - }); + // Role CRUD APIs are gated behind the xpack.security.roleManagementEnabled config + // setting. This setting is false by default on serverless. When the custom roles + // feature is enabled, this setting will be true, and the tests from + // roles_routes_feature_flag.ts can be moved here to replace these. + it('create/update roleAuthc', async () => { + const { body, status } = await supertestAdminWithApiKey.put('/api/security/role/test'); + svlCommonApi.assertApiNotFound(body, status); + }); - it('get roleAuthc', async () => { - const { body, status } = await supertestAdminWithApiKey.get( - '/api/security/role/superuser' - ); - svlCommonApi.assertApiNotFound(body, status); - }); + it('get role', async () => { + const { body, status } = await supertestAdminWithApiKey.get( + '/api/security/role/superuser' + ); + svlCommonApi.assertApiNotFound(body, status); + }); - it('get all roles', async () => { - const { body, status } = await supertestAdminWithApiKey.get('/api/security/role'); - svlCommonApi.assertApiNotFound(body, status); - }); + it('get all roles', async () => { + const { body, status } = await supertestAdminWithApiKey.get('/api/security/role'); + svlCommonApi.assertApiNotFound(body, status); + }); - it('delete roleAuthc', async () => { - const { body, status } = await supertestAdminWithApiKey.delete( - '/api/security/role/superuser' - ); - svlCommonApi.assertApiNotFound(body, status); - }); + it('delete roleAuthc', async () => { + const { body, status } = await supertestAdminWithApiKey.delete( + '/api/security/role/superuser' + ); + svlCommonApi.assertApiNotFound(body, status); + }); - it('get shared saved object permissions', async () => { - const { body, status } = await supertestAdminWithCookieCredentials.get( - '/internal/security/_share_saved_object_permissions' - ); - svlCommonApi.assertApiNotFound(body, status); - }); + it('get shared saved object permissions', async () => { + const { body, status } = await supertestAdminWithCookieCredentials.get( + '/internal/security/_share_saved_object_permissions' + ); + svlCommonApi.assertApiNotFound(body, status); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts index e5f3f4a86a923..6d5dd96655bfc 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts @@ -11,19 +11,19 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('serverless common API', function () { this.tags(['esGate']); - loadTestFile(require.resolve('./anonymous')); - loadTestFile(require.resolve('./api_keys')); - loadTestFile(require.resolve('./authentication')); - loadTestFile(require.resolve('./authentication_http')); + // loadTestFile(require.resolve('./anonymous')); + // loadTestFile(require.resolve('./api_keys')); + // loadTestFile(require.resolve('./authentication')); + // loadTestFile(require.resolve('./authentication_http')); loadTestFile(require.resolve('./authorization')); - loadTestFile(require.resolve('./encrypted_saved_objects')); - loadTestFile(require.resolve('./misc')); - loadTestFile(require.resolve('./response_headers')); - loadTestFile(require.resolve('./role_mappings')); - loadTestFile(require.resolve('./sessions')); - loadTestFile(require.resolve('./users')); - loadTestFile(require.resolve('./user_profiles')); - loadTestFile(require.resolve('./views')); - loadTestFile(require.resolve('./feature_check')); + // loadTestFile(require.resolve('./encrypted_saved_objects')); + // loadTestFile(require.resolve('./misc')); + // loadTestFile(require.resolve('./response_headers')); + // loadTestFile(require.resolve('./role_mappings')); + // loadTestFile(require.resolve('./sessions')); + // loadTestFile(require.resolve('./users')); + // loadTestFile(require.resolve('./user_profiles')); + // loadTestFile(require.resolve('./views')); + // loadTestFile(require.resolve('./feature_check')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts index da03ad14047b1..59d8a4564e0e4 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts @@ -41,7 +41,7 @@ export default function ({ getService }: FtrProviderContext) { } ); supertestAdminWithApiKey = await roleScopedSupertest.getSupertestWithRoleScope('admin', { - withInternalHeaders: true, + withCommonHeaders: true, }); }); after(async () => { diff --git a/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts index 406de533a909d..200b716874a18 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts @@ -13,25 +13,25 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { return { ...baseTestConfig.getAll(), testFiles: [ - require.resolve('../../common/alerting'), - require.resolve('../../common/data_view_field_editor'), - require.resolve('../../common/data_views'), - require.resolve('../../common/elasticsearch_api'), - require.resolve('../../common/index_management'), - require.resolve('../../common/kql_telemetry'), + // require.resolve('../../common/alerting'), + // require.resolve('../../common/data_view_field_editor'), + // require.resolve('../../common/data_views'), + // require.resolve('../../common/elasticsearch_api'), + // require.resolve('../../common/index_management'), + // require.resolve('../../common/kql_telemetry'), require.resolve('../../common/management'), require.resolve('../../common/platform_security'), - require.resolve('../../common/scripts_tests'), - require.resolve('../../common/search_oss'), - require.resolve('../../common/search_profiler'), - require.resolve('../../common/search_xpack'), - require.resolve('../../common/core'), - require.resolve('../../common/reporting'), - require.resolve('../../common/grok_debugger'), - require.resolve('../../common/painless_lab'), - require.resolve('../../common/console'), - require.resolve('../../common/saved_objects_management'), - require.resolve('../../common/telemetry'), + // require.resolve('../../common/scripts_tests'), + // require.resolve('../../common/search_oss'), + // require.resolve('../../common/search_profiler'), + // require.resolve('../../common/search_xpack'), + // require.resolve('../../common/core'), + // require.resolve('../../common/reporting'), + // require.resolve('../../common/grok_debugger'), + // require.resolve('../../common/painless_lab'), + // require.resolve('../../common/console'), + // require.resolve('../../common/saved_objects_management'), + // require.resolve('../../common/telemetry'), ], junit: { reportName: 'Serverless Security API Integration Tests - Common Group 1', From 27d69d34afc78099aae9c03240e53c6b3989e010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Mon, 23 Sep 2024 16:56:01 +0200 Subject: [PATCH 03/23] Updates roles api tests --- .../management/multiple_spaces_enabled.ts | 146 ++++++++++++++++-- .../common/platform_security/authorization.ts | 2 +- .../roles_routes_feature_flag.ts | 46 ++++-- 3 files changed, 167 insertions(+), 27 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts index 08882694d9a0f..f90539f0cbfef 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/multiple_spaces_enabled.ts @@ -26,6 +26,8 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const svlCommonApi = getService('svlCommonApi'); const roleScopedSupertest = getService('roleScopedSupertest'); + const samlAuth = getService('samlAuth'); + // CRUD operations to become public APIs: https://github.com/elastic/kibana/issues/192153 let supertestAdminWithApiKey: SupertestWithRoleScopeType; let supertestAdminWithCookieCredentials: SupertestWithRoleScopeType; @@ -248,31 +250,149 @@ export default function ({ getService }: FtrProviderContext) { // are enabled in production. describe(`Access`, () => { describe(`internal`, () => { - it('#copyToSpace', async () => { - const { body, status } = await supertestAdminWithApiKey.post( - '/api/spaces/_copy_saved_objects' + it('#getActiveSpace requires internal header', async () => { + let body: any; + let status: number; + + ({ body, status } = await supertestAdminWithApiKey + .get('/internal/spaces/_active_space') + .set(samlAuth.getCommonRequestHeader())); + // expect a rejection because we're not using the internal header + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: expect.stringContaining( + 'method [get] exists but is not available with the current configuration' + ), + }); + expect(status).toBe(400); + + ({ body, status } = await supertestAdminWithApiKey + .get('/internal/spaces/_active_space') + .set(samlAuth.getInternalRequestHeader())); + // expect success because we're using the internal header + expect(body).toEqual( + expect.objectContaining({ + id: 'default', + }) ); + expect(status).toBe(200); + }); + + it('#copyToSpace requires internal header', async () => { + let body: any; + let status: number; + + ({ body, status } = await supertestAdminWithApiKey.post( + '/api/spaces/_copy_saved_objects' + )); + // expect a rejection because we're not using the internal header + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: expect.stringContaining( + 'method [post] exists but is not available with the current configuration' + ), + }); + + ({ body, status } = await supertestAdminWithApiKey + .post('/api/spaces/_copy_saved_objects') + .set(samlAuth.getInternalRequestHeader())); + svlCommonApi.assertResponseStatusCode(400, status, body); + + // expect 400 for missing body + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: '[request body]: expected a plain object value, but found [null] instead.', + }); }); - it('#resolveCopyToSpaceErrors', async () => { - const { body, status } = await supertestAdminWithApiKey.post( + + it('#resolveCopyToSpaceErrors requires internal header', async () => { + let body: any; + let status: number; + + ({ body, status } = await supertestAdminWithApiKey.post( '/api/spaces/_resolve_copy_saved_objects_errors' - ); + )); + // expect a rejection because we're not using the internal header + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: expect.stringContaining( + 'method [post] exists but is not available with the current configuration' + ), + }); + + ({ body, status } = await supertestAdminWithApiKey + .post('/api/spaces/_resolve_copy_saved_objects_errors') + .set(samlAuth.getInternalRequestHeader())); + svlCommonApi.assertResponseStatusCode(400, status, body); + + // expect 400 for missing body + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: '[request body]: expected a plain object value, but found [null] instead.', + }); }); - it('#updateObjectsSpaces', async () => { - const { body, status } = await supertestAdminWithApiKey.post( + + it('#updateObjectsSpaces requires internal header', async () => { + let body: any; + let status: number; + + ({ body, status } = await supertestAdminWithApiKey.post( '/api/spaces/_update_objects_spaces' - ); + )); + // expect a rejection because we're not using the internal header + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: expect.stringContaining( + 'method [post] exists but is not available with the current configuration' + ), + }); + + ({ body, status } = await supertestAdminWithApiKey + .post('/api/spaces/_update_objects_spaces') + .set(samlAuth.getInternalRequestHeader())); + svlCommonApi.assertResponseStatusCode(400, status, body); + + // expect 400 for missing body + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: '[request body]: expected a plain object value, but found [null] instead.', + }); }); - it('#getShareableReferences', async () => { - const { body, status } = await supertestAdminWithApiKey + + it('#getShareableReferences requires internal header', async () => { + let body: any; + let status: number; + + ({ body, status } = await supertestAdminWithApiKey.post( + '/api/spaces/_get_shareable_references' + )); + // expect a rejection because we're not using the internal header + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: expect.stringContaining( + 'method [post] exists but is not available with the current configuration' + ), + }); + + ({ body, status } = await supertestAdminWithApiKey .post('/api/spaces/_get_shareable_references') + .set(samlAuth.getInternalRequestHeader()) .send({ objects: [{ type: 'a', id: 'a' }], - }); - svlCommonApi.assertResponseStatusCode(400, status, body); + })); + + svlCommonApi.assertResponseStatusCode(200, status, body); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts index 806faefa5cd93..bc01b14848eff 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts @@ -85,7 +85,7 @@ export default function ({ getService }: FtrProviderContext) { svlCommonApi.assertApiNotFound(body, status); }); - it('delete roleAuthc', async () => { + it('delete role', async () => { const { body, status } = await supertestAdminWithApiKey.delete( '/api/security/role/superuser' ); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts index 59d8a4564e0e4..b035d08b62b56 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts @@ -5,7 +5,7 @@ * 2.0. */ -import expect from '@kbn/expect'; +import expect from 'expect'; import type { Role } from '@kbn/security-plugin-types-common'; import { SupertestWithRoleScopeType } from '@kbn/test-suites-xpack/api_integration/deployment_agnostic/services'; import { FtrProviderContext } from '../../../ftr_provider_context'; @@ -26,6 +26,8 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const platformSecurityUtils = getService('platformSecurityUtils'); const roleScopedSupertest = getService('roleScopedSupertest'); + const svlCommonApi = getService('svlCommonApi'); + const samlAuth = getService('samlAuth'); let supertestAdminWithApiKey: SupertestWithRoleScopeType; let supertestAdminWithCookieCredentials: SupertestWithRoleScopeType; const es = getService('es'); @@ -86,7 +88,7 @@ export default function ({ getService }: FtrProviderContext) { .expect(204); const role = await es.security.getRole({ name: 'role_with_privileges' }); - expect(role).to.eql({ + expect(role).toEqual({ role_with_privileges: { cluster: ['manage'], indices: [ @@ -425,7 +427,6 @@ export default function ({ getService }: FtrProviderContext) { .expect(200) .expect((res: { body: Role[] }) => { const roles = res.body; - expect(roles).to.be.an('array'); const success = roles.every((role) => { return ( @@ -440,8 +441,8 @@ export default function ({ getService }: FtrProviderContext) { const expectedRole = roles.find((role) => role.name === 'space_role_to_get'); - expect(success).to.be(true); - expect(expectedRole).to.be.an('object'); + expect(success).toBe(true); + expect(expectedRole).toBeTruthy(); }); }); }); @@ -508,7 +509,7 @@ export default function ({ getService }: FtrProviderContext) { .expect(204); const role = await es.security.getRole({ name: 'role_to_update' }); - expect(role).to.eql({ + expect(role).toEqual({ role_to_update: { cluster: ['manage'], indices: [ @@ -582,9 +583,9 @@ export default function ({ getService }: FtrProviderContext) { const role = await es.security.getRole({ name: 'role_to_update_with_dls_fls' }); - expect(role.role_to_update_with_dls_fls.cluster).to.eql(['manage']); - expect(role.role_to_update_with_dls_fls.indices[0].names).to.eql(['logstash-*']); - expect(role.role_to_update_with_dls_fls.indices[0].query).to.eql( + expect(role.role_to_update_with_dls_fls.cluster).toEqual(['manage']); + expect(role.role_to_update_with_dls_fls.indices[0].names).toEqual(['logstash-*']); + expect(role.role_to_update_with_dls_fls.indices[0].query).toEqual( `{ "match": { "geo.src": "CN" } }` ); }); @@ -652,7 +653,7 @@ export default function ({ getService }: FtrProviderContext) { .expect(400); const role = await es.security.getRole({ name: 'role_to_update' }); - expect(role).to.eql({ + expect(role).toEqual({ role_to_update: { cluster: ['monitor'], indices: [ @@ -753,7 +754,7 @@ export default function ({ getService }: FtrProviderContext) { .expect(400); const role = await es.security.getRole({ name: 'role_to_update' }); - expect(role).to.eql({ + expect(role).toEqual({ role_to_update: { cluster: ['monitor'], indices: [ @@ -855,7 +856,7 @@ export default function ({ getService }: FtrProviderContext) { .expect(400); const role = await es.security.getRole({ name: 'role_to_update' }); - expect(role).to.eql({ + expect(role).toEqual({ role_to_update: { cluster: ['monitor'], indices: [ @@ -924,7 +925,26 @@ export default function ({ getService }: FtrProviderContext) { { name: 'role_to_delete' }, { ignore: [404] } ); - expect(deletedRole).to.eql({}); + expect(deletedRole).toEqual({}); + }); + }); + + describe('Access', () => { + describe('public', () => { + it('reset session page', async () => { + const { status } = await supertestAdminWithCookieCredentials.get( + '/internal/security/reset_session_page.js' + ); + expect(status).toBe(200); + }); + }); + describe('Disabled', () => { + it('get shared saved object permissions', async () => { + const { body, status } = await supertestAdminWithCookieCredentials.get( + '/internal/security/_share_saved_object_permissions' + ); + svlCommonApi.assertApiNotFound(body, status); + }); }); }); }); From ecf8197b77255206cdce0fd4e92e8a84170fed05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Mon, 23 Sep 2024 16:57:33 +0200 Subject: [PATCH 04/23] Uncomments test index files --- .../common/platform_security/index.ts | 26 +++++++------- .../security/common_configs/config.group1.ts | 34 +++++++++---------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts index 6d5dd96655bfc..e5f3f4a86a923 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts @@ -11,19 +11,19 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('serverless common API', function () { this.tags(['esGate']); - // loadTestFile(require.resolve('./anonymous')); - // loadTestFile(require.resolve('./api_keys')); - // loadTestFile(require.resolve('./authentication')); - // loadTestFile(require.resolve('./authentication_http')); + loadTestFile(require.resolve('./anonymous')); + loadTestFile(require.resolve('./api_keys')); + loadTestFile(require.resolve('./authentication')); + loadTestFile(require.resolve('./authentication_http')); loadTestFile(require.resolve('./authorization')); - // loadTestFile(require.resolve('./encrypted_saved_objects')); - // loadTestFile(require.resolve('./misc')); - // loadTestFile(require.resolve('./response_headers')); - // loadTestFile(require.resolve('./role_mappings')); - // loadTestFile(require.resolve('./sessions')); - // loadTestFile(require.resolve('./users')); - // loadTestFile(require.resolve('./user_profiles')); - // loadTestFile(require.resolve('./views')); - // loadTestFile(require.resolve('./feature_check')); + loadTestFile(require.resolve('./encrypted_saved_objects')); + loadTestFile(require.resolve('./misc')); + loadTestFile(require.resolve('./response_headers')); + loadTestFile(require.resolve('./role_mappings')); + loadTestFile(require.resolve('./sessions')); + loadTestFile(require.resolve('./users')); + loadTestFile(require.resolve('./user_profiles')); + loadTestFile(require.resolve('./views')); + loadTestFile(require.resolve('./feature_check')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts index 200b716874a18..406de533a909d 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts @@ -13,25 +13,25 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { return { ...baseTestConfig.getAll(), testFiles: [ - // require.resolve('../../common/alerting'), - // require.resolve('../../common/data_view_field_editor'), - // require.resolve('../../common/data_views'), - // require.resolve('../../common/elasticsearch_api'), - // require.resolve('../../common/index_management'), - // require.resolve('../../common/kql_telemetry'), + require.resolve('../../common/alerting'), + require.resolve('../../common/data_view_field_editor'), + require.resolve('../../common/data_views'), + require.resolve('../../common/elasticsearch_api'), + require.resolve('../../common/index_management'), + require.resolve('../../common/kql_telemetry'), require.resolve('../../common/management'), require.resolve('../../common/platform_security'), - // require.resolve('../../common/scripts_tests'), - // require.resolve('../../common/search_oss'), - // require.resolve('../../common/search_profiler'), - // require.resolve('../../common/search_xpack'), - // require.resolve('../../common/core'), - // require.resolve('../../common/reporting'), - // require.resolve('../../common/grok_debugger'), - // require.resolve('../../common/painless_lab'), - // require.resolve('../../common/console'), - // require.resolve('../../common/saved_objects_management'), - // require.resolve('../../common/telemetry'), + require.resolve('../../common/scripts_tests'), + require.resolve('../../common/search_oss'), + require.resolve('../../common/search_profiler'), + require.resolve('../../common/search_xpack'), + require.resolve('../../common/core'), + require.resolve('../../common/reporting'), + require.resolve('../../common/grok_debugger'), + require.resolve('../../common/painless_lab'), + require.resolve('../../common/console'), + require.resolve('../../common/saved_objects_management'), + require.resolve('../../common/telemetry'), ], junit: { reportName: 'Serverless Security API Integration Tests - Common Group 1', From fbd920f88d2994e12dc7dc8f35045ea8e143e03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Mon, 23 Sep 2024 17:01:31 +0200 Subject: [PATCH 05/23] Uncomments management test index --- .../api_integration/test_suites/common/management/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts index 431405df893d2..7694845a4ed0f 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts @@ -11,8 +11,8 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('Management', function () { this.tags(['esGate']); - // loadTestFile(require.resolve('./rollups')); - // loadTestFile(require.resolve('./scripted_fields')); + loadTestFile(require.resolve('./rollups')); + loadTestFile(require.resolve('./scripted_fields')); loadTestFile(require.resolve('./spaces')); }); } From f9b1e51580147a293006e52b8ba34cf9fa7cb108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Mon, 23 Sep 2024 17:08:05 +0200 Subject: [PATCH 06/23] Removes unused constants --- x-pack/plugins/spaces/server/routes/api/external/delete.ts | 2 +- x-pack/plugins/spaces/server/routes/api/external/get.ts | 2 +- x-pack/plugins/spaces/server/routes/api/external/get_all.ts | 2 +- .../common/platform_security/roles_routes_feature_flag.ts | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.ts index 03edfac626714..c39f872b86a00 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/delete.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.ts @@ -15,7 +15,7 @@ import { wrapError } from '../../../lib/errors'; import { createLicensedRouteHandler } from '../../lib'; export function initDeleteSpacesApi(deps: ExternalRouteDeps) { - const { router, log, getSpacesService, isServerless } = deps; + const { router, log, getSpacesService } = deps; router.delete( { diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.ts b/x-pack/plugins/spaces/server/routes/api/external/get.ts index 8c382423d7601..56592cc531fd4 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get.ts @@ -13,7 +13,7 @@ import { wrapError } from '../../../lib/errors'; import { createLicensedRouteHandler } from '../../lib'; export function initGetSpaceApi(deps: ExternalRouteDeps) { - const { router, getSpacesService, isServerless } = deps; + const { router, getSpacesService } = deps; router.get( { diff --git a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts index 3a78ac0991cfd..b7b8fc88b85c1 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts @@ -13,7 +13,7 @@ import { wrapError } from '../../../lib/errors'; import { createLicensedRouteHandler } from '../../lib'; export function initGetAllSpacesApi(deps: ExternalRouteDeps) { - const { router, log, getSpacesService, isServerless } = deps; + const { router, log, getSpacesService } = deps; router.get( { diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts index b035d08b62b56..7f2237eda4b44 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/roles_routes_feature_flag.ts @@ -27,7 +27,6 @@ export default function ({ getService }: FtrProviderContext) { const platformSecurityUtils = getService('platformSecurityUtils'); const roleScopedSupertest = getService('roleScopedSupertest'); const svlCommonApi = getService('svlCommonApi'); - const samlAuth = getService('samlAuth'); let supertestAdminWithApiKey: SupertestWithRoleScopeType; let supertestAdminWithCookieCredentials: SupertestWithRoleScopeType; const es = getService('es'); From 3d813de55db779b436c0367d898e7a40871cad07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Tue, 24 Sep 2024 18:33:14 +0200 Subject: [PATCH 07/23] Use versioned router for public endpoints --- x-pack/plugins/security/common/constants.ts | 11 ++ .../routes/authorization/roles/delete.test.ts | 8 +- .../routes/authorization/roles/delete.ts | 47 ++--- .../routes/authorization/roles/get.test.ts | 8 +- .../server/routes/authorization/roles/get.ts | 79 +++++---- .../authorization/roles/get_all.test.ts | 8 +- .../routes/authorization/roles/get_all.ts | 77 +++++---- .../routes/authorization/roles/post.test.ts | 9 +- .../server/routes/authorization/roles/post.ts | 163 +++++++++--------- .../routes/authorization/roles/put.test.ts | 17 +- .../server/routes/authorization/roles/put.ts | 130 +++++++------- x-pack/plugins/spaces/common/constants.ts | 9 + x-pack/plugins/spaces/common/index.ts | 1 + .../server/routes/api/external/delete.test.ts | 11 +- .../server/routes/api/external/delete.ts | 71 ++++---- .../server/routes/api/external/get.test.ts | 9 +- .../spaces/server/routes/api/external/get.ts | 58 ++++--- .../routes/api/external/get_all.test.ts | 18 +- .../server/routes/api/external/get_all.ts | 96 ++++++----- .../server/routes/api/external/post.test.ts | 11 +- .../spaces/server/routes/api/external/post.ts | 63 +++---- .../server/routes/api/external/put.test.ts | 10 +- .../spaces/server/routes/api/external/put.ts | 60 ++++--- 23 files changed, 551 insertions(+), 423 deletions(-) diff --git a/x-pack/plugins/security/common/constants.ts b/x-pack/plugins/security/common/constants.ts index 60644c5c6d21a..e875e8cf70c56 100644 --- a/x-pack/plugins/security/common/constants.ts +++ b/x-pack/plugins/security/common/constants.ts @@ -111,3 +111,14 @@ export const SESSION_ROUTE = '/internal/security/session'; * Allowed image file types for uploading an image as avatar */ export const IMAGE_FILE_TYPES = ['image/svg+xml', 'image/jpeg', 'image/png', 'image/gif']; + +/** + * The API version numbers used with the versioned router. + */ +export const API_VERSIONS = { + roles: { + public: { + v1: '2023-10-31', + }, + }, +}; diff --git a/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts index 223949843fee5..5c6f3bff716fc 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts @@ -9,9 +9,11 @@ import Boom from '@hapi/boom'; import { kibanaResponseFactory } from '@kbn/core/server'; import { coreMock, httpServerMock } from '@kbn/core/server/mocks'; +import type { MockedVersionedRouter } from '@kbn/core-http-router-server-mocks'; import type { LicenseCheck } from '@kbn/licensing-plugin/server'; import { defineDeleteRolesRoutes } from './delete'; +import { API_VERSIONS } from '../../../../common/constants'; import { routeDefinitionParamsMock } from '../../index.mock'; interface TestOptions { @@ -28,6 +30,8 @@ describe('DELETE role', () => { ) => { test(description, async () => { const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + const versionedRouterMock = mockRouteDefinitionParams.router + .versioned as MockedVersionedRouter; const mockCoreContext = coreMock.createRequestHandlerContext(); const mockLicensingContext = { license: { check: jest.fn().mockReturnValue(licenseCheckResult) }, @@ -44,7 +48,9 @@ describe('DELETE role', () => { } defineDeleteRolesRoutes(mockRouteDefinitionParams); - const [[, handler]] = mockRouteDefinitionParams.router.delete.mock.calls; + const handler = versionedRouterMock.getRoute('delete', '/api/security/role/{name}').versions[ + API_VERSIONS.roles.public.v1 + ].handler; const headers = { authorization: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ diff --git a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts index 022e574181425..f0f0182d8c655 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts @@ -8,32 +8,37 @@ import { schema } from '@kbn/config-schema'; import type { RouteDefinitionParams } from '../..'; +import { API_VERSIONS } from '../../../../common/constants'; import { wrapIntoCustomErrorResponse } from '../../../errors'; import { createLicensedRouteHandler } from '../../licensed_route_handler'; export function defineDeleteRolesRoutes({ router }: RouteDefinitionParams) { - router.delete( - { + router.versioned + .delete({ path: '/api/security/role/{name}', - options: { - access: 'public', - summary: `Delete a role`, - }, - validate: { - params: schema.object({ name: schema.string({ minLength: 1 }) }), + access: 'public', + summary: `Delete a role`, + }) + .addVersion( + { + version: API_VERSIONS.roles.public.v1, + validate: { + request: { + params: schema.object({ name: schema.string({ minLength: 1 }) }), + }, + }, }, - }, - createLicensedRouteHandler(async (context, request, response) => { - try { - const esClient = (await context.core).elasticsearch.client; - await esClient.asCurrentUser.security.deleteRole({ - name: request.params.name, - }); + createLicensedRouteHandler(async (context, request, response) => { + try { + const esClient = (await context.core).elasticsearch.client; + await esClient.asCurrentUser.security.deleteRole({ + name: request.params.name, + }); - return response.noContent(); - } catch (error) { - return response.customError(wrapIntoCustomErrorResponse(error)); - } - }) - ); + return response.noContent(); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); } diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts index b09743fd077e2..732fecb6b5372 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts @@ -9,9 +9,11 @@ import Boom from '@hapi/boom'; import { kibanaResponseFactory } from '@kbn/core/server'; import { coreMock, httpServerMock } from '@kbn/core/server/mocks'; +import type { MockedVersionedRouter } from '@kbn/core-http-router-server-mocks'; import type { LicenseCheck } from '@kbn/licensing-plugin/server'; import { defineGetRolesRoutes } from './get'; +import { API_VERSIONS } from '../../../../common/constants'; import { routeDefinitionParamsMock } from '../../index.mock'; const application = 'kibana-.kibana'; @@ -31,6 +33,8 @@ describe('GET role', () => { ) => { test(description, async () => { const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + const versionedRouterMock = mockRouteDefinitionParams.router + .versioned as MockedVersionedRouter; mockRouteDefinitionParams.authz.applicationName = application; mockRouteDefinitionParams.getFeatures = jest.fn().mockResolvedValue([]); @@ -50,7 +54,9 @@ describe('GET role', () => { } defineGetRolesRoutes(mockRouteDefinitionParams); - const [[, handler]] = mockRouteDefinitionParams.router.get.mock.calls; + const handler = versionedRouterMock.getRoute('get', '/api/security/role/{name}').versions[ + API_VERSIONS.roles.public.v1 + ].handler; const headers = { authorization: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get.ts b/x-pack/plugins/security/server/routes/authorization/roles/get.ts index ec2208341dc16..2d6fe10c932aa 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.ts @@ -8,6 +8,7 @@ import { schema } from '@kbn/config-schema'; import type { RouteDefinitionParams } from '../..'; +import { API_VERSIONS } from '../../../../common/constants'; import { transformElasticsearchRoleToRole } from '../../../authorization'; import { wrapIntoCustomErrorResponse } from '../../../errors'; import { createLicensedRouteHandler } from '../../licensed_route_handler'; @@ -18,47 +19,51 @@ export function defineGetRolesRoutes({ getFeatures, logger, }: RouteDefinitionParams) { - router.get( - { + router.versioned + .get({ path: '/api/security/role/{name}', - options: { - access: 'public', - summary: `Get a role`, - }, - validate: { - params: schema.object({ name: schema.string({ minLength: 1 }) }), + access: 'public', + summary: `Get a role`, + }) + .addVersion( + { + version: API_VERSIONS.roles.public.v1, + validate: { + request: { + params: schema.object({ name: schema.string({ minLength: 1 }) }), + }, + }, }, - }, - createLicensedRouteHandler(async (context, request, response) => { - try { - const esClient = (await context.core).elasticsearch.client; + createLicensedRouteHandler(async (context, request, response) => { + try { + const esClient = (await context.core).elasticsearch.client; - const [features, elasticsearchRoles] = await Promise.all([ - getFeatures(), - await esClient.asCurrentUser.security.getRole({ - name: request.params.name, - }), - ]); + const [features, elasticsearchRoles] = await Promise.all([ + getFeatures(), + await esClient.asCurrentUser.security.getRole({ + name: request.params.name, + }), + ]); - const elasticsearchRole = elasticsearchRoles[request.params.name]; + const elasticsearchRole = elasticsearchRoles[request.params.name]; - if (elasticsearchRole) { - return response.ok({ - body: transformElasticsearchRoleToRole( - features, - // @ts-expect-error `SecurityIndicesPrivileges.names` expected to be `string[]` - elasticsearchRole, - request.params.name, - authz.applicationName, - logger - ), - }); - } + if (elasticsearchRole) { + return response.ok({ + body: transformElasticsearchRoleToRole( + features, + // @ts-expect-error `SecurityIndicesPrivileges.names` expected to be `string[]` + elasticsearchRole, + request.params.name, + authz.applicationName, + logger + ), + }); + } - return response.notFound(); - } catch (error) { - return response.customError(wrapIntoCustomErrorResponse(error)); - } - }) - ); + return response.notFound(); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); } diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts index 3fe91ded3342d..26f48e9230b4a 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts @@ -9,9 +9,11 @@ import Boom from '@hapi/boom'; import { kibanaResponseFactory } from '@kbn/core/server'; import { coreMock, httpServerMock } from '@kbn/core/server/mocks'; +import type { MockedVersionedRouter } from '@kbn/core-http-router-server-mocks'; import type { LicenseCheck } from '@kbn/licensing-plugin/server'; import { defineGetAllRolesRoutes } from './get_all'; +import { API_VERSIONS } from '../../../../common/constants'; import { routeDefinitionParamsMock } from '../../index.mock'; const application = 'kibana-.kibana'; @@ -31,6 +33,8 @@ describe('GET all roles', () => { ) => { test(description, async () => { const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + const versionedRouterMock = mockRouteDefinitionParams.router + .versioned as MockedVersionedRouter; mockRouteDefinitionParams.authz.applicationName = application; mockRouteDefinitionParams.getFeatures = jest.fn().mockResolvedValue([]); @@ -50,7 +54,9 @@ describe('GET all roles', () => { } defineGetAllRolesRoutes(mockRouteDefinitionParams); - const [[, handler]] = mockRouteDefinitionParams.router.get.mock.calls; + const handler = versionedRouterMock.getRoute('get', '/api/security/role').versions[ + API_VERSIONS.roles.public.v1 + ].handler; const headers = { authorization: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts index ed31aedba7f31..689718e536b61 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts @@ -6,6 +6,7 @@ */ import type { RouteDefinitionParams } from '../..'; +import { API_VERSIONS } from '../../../../common/constants'; import { compareRolesByName, transformElasticsearchRoleToRole } from '../../../authorization'; import { wrapIntoCustomErrorResponse } from '../../../errors'; import { createLicensedRouteHandler } from '../../licensed_route_handler'; @@ -18,45 +19,47 @@ export function defineGetAllRolesRoutes({ buildFlavor, config, }: RouteDefinitionParams) { - router.get( - { + router.versioned + .get({ path: '/api/security/role', - options: { - access: 'public', - summary: `Get all roles`, + access: 'public', + summary: `Get all roles`, + }) + .addVersion( + { + version: API_VERSIONS.roles.public.v1, + validate: false, }, - validate: false, - }, - createLicensedRouteHandler(async (context, request, response) => { - try { - const hideReservedRoles = buildFlavor === 'serverless'; - const esClient = (await context.core).elasticsearch.client; - const [features, elasticsearchRoles] = await Promise.all([ - getFeatures(), - await esClient.asCurrentUser.security.getRole(), - ]); + createLicensedRouteHandler(async (context, request, response) => { + try { + const hideReservedRoles = buildFlavor === 'serverless'; + const esClient = (await context.core).elasticsearch.client; + const [features, elasticsearchRoles] = await Promise.all([ + getFeatures(), + await esClient.asCurrentUser.security.getRole(), + ]); - // Transform elasticsearch roles into Kibana roles and return in a list sorted by the role name. - return response.ok({ - body: Object.entries(elasticsearchRoles) - .map(([roleName, elasticsearchRole]) => - transformElasticsearchRoleToRole( - features, - // @ts-expect-error @elastic/elasticsearch SecurityIndicesPrivileges.names expected to be string[] - elasticsearchRole, - roleName, - authz.applicationName, - logger + // Transform elasticsearch roles into Kibana roles and return in a list sorted by the role name. + return response.ok({ + body: Object.entries(elasticsearchRoles) + .map(([roleName, elasticsearchRole]) => + transformElasticsearchRoleToRole( + features, + // @ts-expect-error @elastic/elasticsearch SecurityIndicesPrivileges.names expected to be string[] + elasticsearchRole, + roleName, + authz.applicationName, + logger + ) ) - ) - .filter((role) => { - return !hideReservedRoles || !role.metadata?._reserved; - }) - .sort(compareRolesByName), - }); - } catch (error) { - return response.customError(wrapIntoCustomErrorResponse(error)); - } - }) - ); + .filter((role) => { + return !hideReservedRoles || !role.metadata?._reserved; + }) + .sort(compareRolesByName), + }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); } diff --git a/x-pack/plugins/security/server/routes/authorization/roles/post.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/post.test.ts index 0ef752423606d..c28a036a676b6 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/post.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/post.test.ts @@ -7,12 +7,14 @@ import { kibanaResponseFactory } from '@kbn/core/server'; import { coreMock, httpServerMock } from '@kbn/core/server/mocks'; +import type { MockedVersionedRouter } from '@kbn/core-http-router-server-mocks'; import { KibanaFeature } from '@kbn/features-plugin/server'; import type { LicenseCheck } from '@kbn/licensing-plugin/server'; import { GLOBAL_RESOURCE } from '@kbn/security-plugin-types-server'; import type { BulkCreateOrUpdateRolesPayloadSchemaType } from './model/bulk_create_or_update_payload'; import { defineBulkCreateOrUpdateRolesRoutes } from './post'; +import { API_VERSIONS } from '../../../../common/constants'; import { securityFeatureUsageServiceMock } from '../../../feature_usage/index.mock'; import { routeDefinitionParamsMock } from '../../index.mock'; @@ -89,6 +91,7 @@ const postRolesTest = ( ) => { test(description, async () => { const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + const versionedRouterMock = mockRouteDefinitionParams.router.versioned as MockedVersionedRouter; mockRouteDefinitionParams.authz.applicationName = application; mockRouteDefinitionParams.authz.privileges.get.mockReturnValue(privilegeMap); @@ -158,13 +161,15 @@ const postRolesTest = ( ); defineBulkCreateOrUpdateRolesRoutes(mockRouteDefinitionParams); - const [[{ validate }, handler]] = mockRouteDefinitionParams.router.post.mock.calls; + const { handler, config } = versionedRouterMock.getRoute('post', '/api/security/roles') + .versions[API_VERSIONS.roles.public.v1]; const headers = { authorization: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ method: 'post', path: '/api/security/roles', - body: payload !== undefined ? (validate as any).body.validate(payload) : undefined, + body: + payload !== undefined ? (config.validate as any).request.body.validate(payload) : undefined, headers, }); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/post.ts b/x-pack/plugins/security/server/routes/authorization/roles/post.ts index 37967d208bf3a..284c8e9c9a478 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/post.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/post.ts @@ -11,6 +11,7 @@ import { transformPutPayloadToElasticsearchRole, } from './model'; import type { RouteDefinitionParams } from '../..'; +import { API_VERSIONS } from '../../../../common/constants'; import { wrapIntoCustomErrorResponse } from '../../../errors'; import { validateKibanaPrivileges } from '../../../lib'; import { createLicensedRouteHandler } from '../../licensed_route_handler'; @@ -39,97 +40,101 @@ export function defineBulkCreateOrUpdateRolesRoutes({ getFeatures, getFeatureUsageService, }: RouteDefinitionParams) { - router.post( - { + router.versioned + .post({ path: '/api/security/roles', - options: { - access: 'public', - summary: 'Create or update roles', - }, - validate: { - body: getBulkCreateOrUpdatePayloadSchema(() => { - const privileges = authz.privileges.get(); - return { - global: Object.keys(privileges.global), - space: Object.keys(privileges.space), - }; - }), + access: 'public', + summary: 'Create or update roles', + }) + .addVersion( + { + version: API_VERSIONS.roles.public.v1, + validate: { + request: { + body: getBulkCreateOrUpdatePayloadSchema(() => { + const privileges = authz.privileges.get(); + return { + global: Object.keys(privileges.global), + space: Object.keys(privileges.space), + }; + }), + }, + }, }, - }, - createLicensedRouteHandler(async (context, request, response) => { - try { - const esClient = (await context.core).elasticsearch.client; - const features = await getFeatures(); + createLicensedRouteHandler(async (context, request, response) => { + try { + const esClient = (await context.core).elasticsearch.client; + const features = await getFeatures(); - const { roles } = request.body; - const validatedRolesNames = []; - const kibanaErrors: RolesErrorsDetails = {}; + const { roles } = request.body; + const validatedRolesNames = []; + const kibanaErrors: RolesErrorsDetails = {}; - for (const [roleName, role] of Object.entries(roles)) { - const { validationErrors } = validateKibanaPrivileges(features, role.kibana); + for (const [roleName, role] of Object.entries(roles)) { + const { validationErrors } = validateKibanaPrivileges(features, role.kibana); - if (validationErrors.length) { - kibanaErrors[roleName] = { - type: 'kibana_privilege_validation_exception', - reason: `Role cannot be updated due to validation errors: ${JSON.stringify( - validationErrors - )}`, - }; + if (validationErrors.length) { + kibanaErrors[roleName] = { + type: 'kibana_privilege_validation_exception', + reason: `Role cannot be updated due to validation errors: ${JSON.stringify( + validationErrors + )}`, + }; - continue; - } + continue; + } - validatedRolesNames.push(roleName); - } + validatedRolesNames.push(roleName); + } - const rawRoles = await esClient.asCurrentUser.security.getRole( - { name: validatedRolesNames.join(',') }, - { ignore: [404] } - ); + const rawRoles = await esClient.asCurrentUser.security.getRole( + { name: validatedRolesNames.join(',') }, + { ignore: [404] } + ); - const esRolesPayload = Object.fromEntries( - validatedRolesNames.map((roleName) => [ - roleName, - transformPutPayloadToElasticsearchRole( - roles[roleName], - authz.applicationName, - rawRoles[roleName] ? rawRoles[roleName].applications : [] - ), - ]) - ); + const esRolesPayload = Object.fromEntries( + validatedRolesNames.map((roleName) => [ + roleName, + transformPutPayloadToElasticsearchRole( + roles[roleName], + authz.applicationName, + rawRoles[roleName] ? rawRoles[roleName].applications : [] + ), + ]) + ); - const esResponse = await esClient.asCurrentUser.transport.request({ - method: 'POST', - path: '/_security/role', - body: { roles: esRolesPayload }, - }); + const esResponse = await esClient.asCurrentUser.transport.request({ + method: 'POST', + path: '/_security/role', + body: { roles: esRolesPayload }, + }); - for (const roleName of [ - ...(esResponse.created ?? []), - ...(esResponse.updated ?? []), - ...(esResponse.noop ?? []), - ]) { - if (roleGrantsSubFeaturePrivileges(features, roles[roleName])) { - getFeatureUsageService().recordSubFeaturePrivilegeUsage(); + for (const roleName of [ + ...(esResponse.created ?? []), + ...(esResponse.updated ?? []), + ...(esResponse.noop ?? []), + ]) { + if (roleGrantsSubFeaturePrivileges(features, roles[roleName])) { + getFeatureUsageService().recordSubFeaturePrivilegeUsage(); + } } - } - const { created, noop, updated, errors: esErrors } = esResponse; - const hasAnyErrors = Object.keys(kibanaErrors).length || esErrors?.count; + const { created, noop, updated, errors: esErrors } = esResponse; + const hasAnyErrors = Object.keys(kibanaErrors).length || esErrors?.count; - return response.ok({ - body: { - created, - noop, - updated, - ...(hasAnyErrors && { - errors: { ...kibanaErrors, ...(esErrors?.details ?? {}) }, - }), - }, - }); - } catch (error) { - return response.customError(wrapIntoCustomErrorResponse(error)); - } - }) - ); + return response.ok({ + body: { + created, + noop, + updated, + ...(hasAnyErrors && { + errors: { ...kibanaErrors, ...(esErrors?.details ?? {}) }, + }), + }, + }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); } diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts index 642aec90c4748..50665e0494b81 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts @@ -8,11 +8,13 @@ import type { Type } from '@kbn/config-schema'; import { kibanaResponseFactory } from '@kbn/core/server'; import { coreMock, httpServerMock } from '@kbn/core/server/mocks'; +import type { MockedVersionedRouter } from '@kbn/core-http-router-server-mocks'; import { KibanaFeature } from '@kbn/features-plugin/server'; import type { LicenseCheck } from '@kbn/licensing-plugin/server'; import { GLOBAL_RESOURCE } from '@kbn/security-plugin-types-server'; import { definePutRolesRoutes } from './put'; +import { API_VERSIONS } from '../../../../common/constants'; import { securityFeatureUsageServiceMock } from '../../../feature_usage/index.mock'; import { routeDefinitionParamsMock } from '../../index.mock'; @@ -74,6 +76,7 @@ const putRoleTest = ( ) => { test(description, async () => { const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + const versionedRouterMock = mockRouteDefinitionParams.router.versioned as MockedVersionedRouter; mockRouteDefinitionParams.authz.applicationName = application; mockRouteDefinitionParams.authz.privileges.get.mockReturnValue(privilegeMap); @@ -143,7 +146,8 @@ const putRoleTest = ( ); definePutRolesRoutes(mockRouteDefinitionParams); - const [[{ validate }, handler]] = mockRouteDefinitionParams.router.put.mock.calls; + const { handler, config } = versionedRouterMock.getRoute('put', '/api/security/role/{name}') + .versions[API_VERSIONS.roles.public.v1]; const headers = { authorization: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ @@ -151,7 +155,8 @@ const putRoleTest = ( path: `/api/security/role/${name}`, query: { createOnly }, params: { name }, - body: payload !== undefined ? (validate as any).body.validate(payload) : undefined, + body: + payload !== undefined ? (config.validate as any).request.body.validate(payload) : undefined, headers, }); @@ -188,11 +193,15 @@ describe('PUT role', () => { let requestParamsSchema: Type; beforeEach(() => { const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + const versionedRouterMock = mockRouteDefinitionParams.router + .versioned as MockedVersionedRouter; mockRouteDefinitionParams.authz.privileges.get.mockReturnValue(privilegeMap); definePutRolesRoutes(mockRouteDefinitionParams); - const [[{ validate }]] = mockRouteDefinitionParams.router.put.mock.calls; - requestParamsSchema = (validate as any).params; + const { config } = versionedRouterMock.getRoute('put', '/api/security/role/{name}').versions[ + API_VERSIONS.roles.public.v1 + ]; + requestParamsSchema = (config.validate as any).request.params; }); test('requires name in params', () => { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.ts index 6175ba6f4d64f..35542c7a09a3d 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.ts @@ -10,6 +10,7 @@ import { schema } from '@kbn/config-schema'; import { roleGrantsSubFeaturePrivileges } from './lib'; import { getPutPayloadSchema, transformPutPayloadToElasticsearchRole } from './model'; import type { RouteDefinitionParams } from '../..'; +import { API_VERSIONS } from '../../../../common/constants'; import { wrapIntoCustomErrorResponse } from '../../../errors'; import { validateKibanaPrivileges } from '../../../lib'; import { createLicensedRouteHandler } from '../../licensed_route_handler'; @@ -20,75 +21,82 @@ export function definePutRolesRoutes({ getFeatures, getFeatureUsageService, }: RouteDefinitionParams) { - router.put( - { + router.versioned + .put({ path: '/api/security/role/{name}', - options: { - access: 'public', - summary: `Create or update a role`, - }, - validate: { - params: schema.object({ name: schema.string({ minLength: 1, maxLength: 1024 }) }), - query: schema.object({ createOnly: schema.boolean({ defaultValue: false }) }), - body: getPutPayloadSchema(() => { - const privileges = authz.privileges.get(); - return { - global: Object.keys(privileges.global), - space: Object.keys(privileges.space), - }; - }), + access: 'public', + summary: `Create or update a role`, + }) + .addVersion( + { + version: API_VERSIONS.roles.public.v1, + validate: { + request: { + params: schema.object({ name: schema.string({ minLength: 1, maxLength: 1024 }) }), + query: schema.object({ createOnly: schema.boolean({ defaultValue: false }) }), + body: getPutPayloadSchema(() => { + const privileges = authz.privileges.get(); + return { + global: Object.keys(privileges.global), + space: Object.keys(privileges.space), + }; + }), + }, + }, }, - }, - createLicensedRouteHandler(async (context, request, response) => { - const { name } = request.params; - const { createOnly } = request.query; - try { - const esClient = (await context.core).elasticsearch.client; + createLicensedRouteHandler(async (context, request, response) => { + const { name } = request.params; + const { createOnly } = request.query; + try { + const esClient = (await context.core).elasticsearch.client; - const [features, rawRoles] = await Promise.all([ - getFeatures(), - esClient.asCurrentUser.security.getRole({ name: request.params.name }, { ignore: [404] }), - ]); + const [features, rawRoles] = await Promise.all([ + getFeatures(), + esClient.asCurrentUser.security.getRole( + { name: request.params.name }, + { ignore: [404] } + ), + ]); - const { validationErrors } = validateKibanaPrivileges(features, request.body.kibana); + const { validationErrors } = validateKibanaPrivileges(features, request.body.kibana); - if (validationErrors.length) { - return response.badRequest({ - body: { - message: `Role cannot be updated due to validation errors: ${JSON.stringify( - validationErrors - )}`, - }, - }); - } + if (validationErrors.length) { + return response.badRequest({ + body: { + message: `Role cannot be updated due to validation errors: ${JSON.stringify( + validationErrors + )}`, + }, + }); + } - if (createOnly && !!rawRoles[name]) { - return response.conflict({ - body: { - message: `Role already exists and cannot be created: ${name}`, - }, - }); - } + if (createOnly && !!rawRoles[name]) { + return response.conflict({ + body: { + message: `Role already exists and cannot be created: ${name}`, + }, + }); + } - const body = transformPutPayloadToElasticsearchRole( - request.body, - authz.applicationName, - rawRoles[name] ? rawRoles[name].applications : [] - ); + const body = transformPutPayloadToElasticsearchRole( + request.body, + authz.applicationName, + rawRoles[name] ? rawRoles[name].applications : [] + ); - await esClient.asCurrentUser.security.putRole({ - name: request.params.name, - body, - }); + await esClient.asCurrentUser.security.putRole({ + name: request.params.name, + body, + }); - if (roleGrantsSubFeaturePrivileges(features, request.body)) { - getFeatureUsageService().recordSubFeaturePrivilegeUsage(); - } + if (roleGrantsSubFeaturePrivileges(features, request.body)) { + getFeatureUsageService().recordSubFeaturePrivilegeUsage(); + } - return response.noContent(); - } catch (error) { - return response.customError(wrapIntoCustomErrorResponse(error)); - } - }) - ); + return response.noContent(); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); } diff --git a/x-pack/plugins/spaces/common/constants.ts b/x-pack/plugins/spaces/common/constants.ts index d70c332fb62ab..a05e31d73f1c4 100644 --- a/x-pack/plugins/spaces/common/constants.ts +++ b/x-pack/plugins/spaces/common/constants.ts @@ -31,3 +31,12 @@ export const MAX_SPACE_INITIALS = 2; * The path to enter a space. */ export const ENTER_SPACE_PATH = '/spaces/enter'; + +/** + * The API version numbers used with the versioned router. + */ +export const API_VERSIONS = { + public: { + v1: '2023-10-31', + }, +}; diff --git a/x-pack/plugins/spaces/common/index.ts b/x-pack/plugins/spaces/common/index.ts index 65342bf2e43f4..21fee91bf979d 100644 --- a/x-pack/plugins/spaces/common/index.ts +++ b/x-pack/plugins/spaces/common/index.ts @@ -11,6 +11,7 @@ export { SPACE_SEARCH_COUNT_THRESHOLD, ENTER_SPACE_PATH, DEFAULT_SPACE_ID, + API_VERSIONS, } from './constants'; export { addSpaceIdToPath, getSpaceIdFromPath } from './lib/spaces_url_parser'; export type { diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts index f50b73d7f8513..c3c13eeff04bb 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts @@ -16,9 +16,11 @@ import { httpServiceMock, loggingSystemMock, } from '@kbn/core/server/mocks'; +import type { MockedVersionedRouter } from '@kbn/core-http-router-server-mocks'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import { initDeleteSpacesApi } from './delete'; +import { API_VERSIONS } from '../../../../common'; import { spacesConfig } from '../../../lib/__fixtures__'; import { SpacesClientService } from '../../../spaces_client'; import { SpacesService } from '../../../spaces_service'; @@ -36,7 +38,7 @@ describe('Spaces Public API', () => { const setup = async () => { const httpService = httpServiceMock.createSetupContract(); const router = httpService.createRouter(); - + const versionedRouterMock = router.versioned as MockedVersionedRouter; const savedObjectsRepositoryMock = createMockSavedObjectsRepository(spacesSavedObjects); const log = loggingSystemMock.create().get('spaces'); @@ -71,10 +73,13 @@ describe('Spaces Public API', () => { isServerless: false, }); - const [routeDefinition, routeHandler] = router.delete.mock.calls[0]; + const { handler: routeHandler, config } = versionedRouterMock.getRoute( + 'delete', + '/api/spaces/space/{id}' + ).versions[API_VERSIONS.public.v1]; return { - routeValidation: routeDefinition.validate as RouteValidatorConfig<{}, {}, {}>, + routeValidation: (config.validate as any).request as RouteValidatorConfig<{}, {}, {}>, routeHandler, savedObjectsRepositoryMock, }; diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.ts index c39f872b86a00..9fe049599dca6 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/delete.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.ts @@ -11,47 +11,52 @@ import { schema } from '@kbn/config-schema'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import type { ExternalRouteDeps } from '.'; +import { API_VERSIONS } from '../../../../common'; import { wrapError } from '../../../lib/errors'; import { createLicensedRouteHandler } from '../../lib'; export function initDeleteSpacesApi(deps: ExternalRouteDeps) { const { router, log, getSpacesService } = deps; - router.delete( - { + router.versioned + .delete({ path: '/api/spaces/space/{id}', - options: { - access: 'public', - description: `Delete a space`, - }, - validate: { - params: schema.object({ - id: schema.string(), - }), + access: 'public', + description: `Delete a space`, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + params: schema.object({ + id: schema.string(), + }), + }, + }, }, - }, - createLicensedRouteHandler(async (context, request, response) => { - const spacesClient = getSpacesService().createSpacesClient(request); - - const id = request.params.id; - - try { - await spacesClient.delete(id); - } catch (error) { - if (SavedObjectsErrorHelpers.isNotFoundError(error)) { - return response.notFound(); - } else if (SavedObjectsErrorHelpers.isEsCannotExecuteScriptError(error)) { - log.error( - `Failed to delete space '${id}', cannot execute script in Elasticsearch query: ${error.message}` - ); - return response.customError( - wrapError(Boom.badRequest('Cannot execute script in Elasticsearch query')) - ); + createLicensedRouteHandler(async (context, request, response) => { + const spacesClient = getSpacesService().createSpacesClient(request); + + const id = request.params.id; + + try { + await spacesClient.delete(id); + } catch (error) { + if (SavedObjectsErrorHelpers.isNotFoundError(error)) { + return response.notFound(); + } else if (SavedObjectsErrorHelpers.isEsCannotExecuteScriptError(error)) { + log.error( + `Failed to delete space '${id}', cannot execute script in Elasticsearch query: ${error.message}` + ); + return response.customError( + wrapError(Boom.badRequest('Cannot execute script in Elasticsearch query')) + ); + } + return response.customError(wrapError(error)); } - return response.customError(wrapError(error)); - } - return response.noContent(); - }) - ); + return response.noContent(); + }) + ); } diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.test.ts b/x-pack/plugins/spaces/server/routes/api/external/get.test.ts index 3b5774284f19f..38f63202bc08b 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get.test.ts @@ -14,9 +14,11 @@ import { httpServiceMock, loggingSystemMock, } from '@kbn/core/server/mocks'; +import type { MockedVersionedRouter } from '@kbn/core-http-router-server-mocks'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import { initGetSpaceApi } from './get'; +import { API_VERSIONS } from '../../../../common'; import { spacesConfig } from '../../../lib/__fixtures__'; import { SpacesClientService } from '../../../spaces_client'; import { SpacesService } from '../../../spaces_service'; @@ -35,6 +37,7 @@ describe('GET space', () => { const setup = async () => { const httpService = httpServiceMock.createSetupContract(); const router = httpService.createRouter(); + const versionedRouterMock = router.versioned as MockedVersionedRouter; const coreStart = coreMock.createStart(); @@ -70,8 +73,12 @@ describe('GET space', () => { isServerless: false, }); + const { handler } = versionedRouterMock.getRoute('get', '/api/spaces/space/{id}').versions[ + API_VERSIONS.public.v1 + ]; + return { - routeHandler: router.get.mock.calls[0][1], + routeHandler: handler, }; }; diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.ts b/x-pack/plugins/spaces/server/routes/api/external/get.ts index 56592cc531fd4..ee2104ee55302 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get.ts @@ -9,40 +9,44 @@ import { schema } from '@kbn/config-schema'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import type { ExternalRouteDeps } from '.'; +import { API_VERSIONS } from '../../../../common'; import { wrapError } from '../../../lib/errors'; import { createLicensedRouteHandler } from '../../lib'; export function initGetSpaceApi(deps: ExternalRouteDeps) { const { router, getSpacesService } = deps; - router.get( - { + router.versioned + .get({ path: '/api/spaces/space/{id}', - options: { - access: 'public', - description: `Get a space`, - }, - validate: { - params: schema.object({ - id: schema.string(), - }), + access: 'public', + description: `Get a space`, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + params: schema.object({ + id: schema.string(), + }), + }, + }, }, - }, - createLicensedRouteHandler(async (context, request, response) => { - const spaceId = request.params.id; - const spacesClient = getSpacesService().createSpacesClient(request); - - try { - const space = await spacesClient.get(spaceId); - return response.ok({ - body: space, - }); - } catch (error) { - if (SavedObjectsErrorHelpers.isNotFoundError(error)) { - return response.notFound(); + createLicensedRouteHandler(async (context, request, response) => { + const spaceId = request.params.id; + const spacesClient = getSpacesService().createSpacesClient(request); + try { + const space = await spacesClient.get(spaceId); + return response.ok({ + body: space, + }); + } catch (error) { + if (SavedObjectsErrorHelpers.isNotFoundError(error)) { + return response.notFound(); + } + return response.customError(wrapError(error)); } - return response.customError(wrapError(error)); - } - }) - ); + }) + ); } diff --git a/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts b/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts index d2f8162a3f236..a1cbc729c999d 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts @@ -15,10 +15,13 @@ import { httpServiceMock, loggingSystemMock, } from '@kbn/core/server/mocks'; +import type { MockedVersionedRouter } from '@kbn/core-http-router-server-mocks'; +import type { RouteValidatorConfig } from '@kbn/core-http-server'; import { getRequestValidation } from '@kbn/core-http-server'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import { initGetAllSpacesApi } from './get_all'; +import { API_VERSIONS } from '../../../../common'; import { spacesConfig } from '../../../lib/__fixtures__'; import { SpacesClientService } from '../../../spaces_client'; import { SpacesService } from '../../../spaces_service'; @@ -37,6 +40,7 @@ describe('GET /spaces/space', () => { const setup = async () => { const httpService = httpServiceMock.createSetupContract(); const router = httpService.createRouter(); + const versionedRouterMock = router.versioned as MockedVersionedRouter; const coreStart = coreMock.createStart(); @@ -72,9 +76,13 @@ describe('GET /spaces/space', () => { isServerless: false, }); + const { handler, config } = versionedRouterMock.getRoute('get', '/api/spaces/space').versions[ + API_VERSIONS.public.v1 + ]; + return { - routeConfig: router.get.mock.calls[0][0], - routeHandler: router.get.mock.calls[0][1], + routeValidation: (config.validate as any).request as RouteValidatorConfig<{}, {}, {}> | false, + routeHandler: handler, }; }; @@ -92,17 +100,17 @@ describe('GET /spaces/space', () => { }); it(`returns expected result when specifying include_authorized_purposes=true`, async () => { - const { routeConfig, routeHandler } = await setup(); + const { routeValidation, routeHandler } = await setup(); const request = httpServerMock.createKibanaRequest({ method: 'get', query: { purpose, include_authorized_purposes: true }, }); - if (routeConfig.validate === false) { + if (routeValidation === false) { throw new Error('Test setup failure. Expected route validation'); } - const queryParamsValidation = getRequestValidation(routeConfig.validate) + const queryParamsValidation = getRequestValidation(routeValidation) .query! as ObjectType; const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); diff --git a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts index b7b8fc88b85c1..9fa47a808d97f 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts @@ -8,63 +8,67 @@ import { schema } from '@kbn/config-schema'; import type { ExternalRouteDeps } from '.'; -import type { Space } from '../../../../common'; +import { API_VERSIONS, type Space } from '../../../../common'; import { wrapError } from '../../../lib/errors'; import { createLicensedRouteHandler } from '../../lib'; export function initGetAllSpacesApi(deps: ExternalRouteDeps) { const { router, log, getSpacesService } = deps; - router.get( - { + router.versioned + .get({ path: '/api/spaces/space', - options: { - access: 'public', - description: `Get all spaces`, - }, - validate: { - query: schema.object({ - purpose: schema.maybe( - schema.oneOf([ - schema.literal('any'), - schema.literal('copySavedObjectsIntoSpace'), - schema.literal('shareSavedObjectsIntoSpace'), - ]) - ), - include_authorized_purposes: schema.conditional( - schema.siblingRef('purpose'), - schema.string(), - schema.maybe(schema.literal(false)), - schema.maybe(schema.boolean()) - ), - }), + access: 'public', + description: `Get all spaces`, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + query: schema.object({ + purpose: schema.maybe( + schema.oneOf([ + schema.literal('any'), + schema.literal('copySavedObjectsIntoSpace'), + schema.literal('shareSavedObjectsIntoSpace'), + ]) + ), + include_authorized_purposes: schema.conditional( + schema.siblingRef('purpose'), + schema.string(), + schema.maybe(schema.literal(false)), + schema.maybe(schema.boolean()) + ), + }), + }, + }, }, - }, - createLicensedRouteHandler(async (context, request, response) => { - log.debug(`Inside GET /api/spaces/space`); + createLicensedRouteHandler(async (context, request, response) => { + log.debug(`Inside GET /api/spaces/space`); - const { purpose, include_authorized_purposes: includeAuthorizedPurposes } = request.query; + const { purpose, include_authorized_purposes: includeAuthorizedPurposes } = request.query; - const spacesClient = getSpacesService().createSpacesClient(request); + const spacesClient = getSpacesService().createSpacesClient(request); - let spaces: Space[]; + let spaces: Space[]; - try { - log.debug( - `Attempting to retrieve all spaces for ${purpose} purpose with includeAuthorizedPurposes=${includeAuthorizedPurposes}` - ); - spaces = await spacesClient.getAll({ purpose, includeAuthorizedPurposes }); - log.debug( - `Retrieved ${spaces.length} spaces for ${purpose} purpose with includeAuthorizedPurposes=${includeAuthorizedPurposes}` - ); - } catch (error) { - log.debug( - `Error retrieving spaces for ${purpose} purpose with includeAuthorizedPurposes=${includeAuthorizedPurposes}: ${error}` - ); - return response.customError(wrapError(error)); - } + try { + log.debug( + `Attempting to retrieve all spaces for ${purpose} purpose with includeAuthorizedPurposes=${includeAuthorizedPurposes}` + ); + spaces = await spacesClient.getAll({ purpose, includeAuthorizedPurposes }); + log.debug( + `Retrieved ${spaces.length} spaces for ${purpose} purpose with includeAuthorizedPurposes=${includeAuthorizedPurposes}` + ); + } catch (error) { + log.debug( + `Error retrieving spaces for ${purpose} purpose with includeAuthorizedPurposes=${includeAuthorizedPurposes}: ${error}` + ); + return response.customError(wrapError(error)); + } - return response.ok({ body: spaces }); - }) - ); + return response.ok({ body: spaces }); + }) + ); } diff --git a/x-pack/plugins/spaces/server/routes/api/external/post.test.ts b/x-pack/plugins/spaces/server/routes/api/external/post.test.ts index 9b017839fb25c..984d684762159 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/post.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/post.test.ts @@ -16,9 +16,11 @@ import { httpServiceMock, loggingSystemMock, } from '@kbn/core/server/mocks'; +import type { MockedVersionedRouter } from '@kbn/core-http-router-server-mocks'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import { initPostSpacesApi } from './post'; +import { API_VERSIONS } from '../../../../common'; import { spacesConfig } from '../../../lib/__fixtures__'; import { SpacesClientService } from '../../../spaces_client'; import { SpacesService } from '../../../spaces_service'; @@ -36,6 +38,7 @@ describe('Spaces Public API', () => { const setup = async () => { const httpService = httpServiceMock.createSetupContract(); const router = httpService.createRouter(); + const versionedRouterMock = router.versioned as MockedVersionedRouter; const coreStart = coreMock.createStart(); @@ -75,11 +78,13 @@ describe('Spaces Public API', () => { isServerless: false, }); - const [routeDefinition, routeHandler] = router.post.mock.calls[0]; + const { handler, config } = versionedRouterMock.getRoute('post', '/api/spaces/space').versions[ + API_VERSIONS.public.v1 + ]; return { - routeValidation: routeDefinition.validate as RouteValidatorConfig<{}, {}, {}>, - routeHandler, + routeValidation: (config.validate as any).request as RouteValidatorConfig<{}, {}, {}>, + routeHandler: handler, savedObjectsRepositoryMock, }; }; diff --git a/x-pack/plugins/spaces/server/routes/api/external/post.ts b/x-pack/plugins/spaces/server/routes/api/external/post.ts index 8644c0c00e102..5132a50ad0101 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/post.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/post.ts @@ -10,6 +10,7 @@ import Boom from '@hapi/boom'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import type { ExternalRouteDeps } from '.'; +import { API_VERSIONS } from '../../../../common'; import { wrapError } from '../../../lib/errors'; import { getSpaceSchema } from '../../../lib/space_schema'; import { createLicensedRouteHandler } from '../../lib'; @@ -17,37 +18,39 @@ import { createLicensedRouteHandler } from '../../lib'; export function initPostSpacesApi(deps: ExternalRouteDeps) { const { router, log, getSpacesService, isServerless } = deps; - router.post( - { + router.versioned + .post({ path: '/api/spaces/space', - options: { - access: 'public', - description: `Create a space`, - }, - validate: { - body: getSpaceSchema(isServerless), + access: 'public', + description: `Create a space`, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + body: getSpaceSchema(isServerless), + }, + }, }, - }, - createLicensedRouteHandler(async (context, request, response) => { - log.debug(`Inside POST /api/spaces/space`); - const spacesClient = getSpacesService().createSpacesClient(request); - - const space = request.body; - - try { - log.debug(`Attempting to create space`); - const createdSpace = await spacesClient.create(space); - return response.ok({ body: createdSpace }); - } catch (error) { - if (SavedObjectsErrorHelpers.isConflictError(error)) { - const { body } = wrapError( - Boom.conflict(`A space with the identifier ${space.id} already exists.`) - ); - return response.conflict({ body }); + createLicensedRouteHandler(async (context, request, response) => { + log.debug(`Inside POST /api/spaces/space`); + const spacesClient = getSpacesService().createSpacesClient(request); + const space = request.body; + try { + log.debug(`Attempting to create space`); + const createdSpace = await spacesClient.create(space); + return response.ok({ body: createdSpace }); + } catch (error) { + if (SavedObjectsErrorHelpers.isConflictError(error)) { + const { body } = wrapError( + Boom.conflict(`A space with the identifier ${space.id} already exists.`) + ); + return response.conflict({ body }); + } + log.debug(`Error creating space: ${error}`); + return response.customError(wrapError(error)); } - log.debug(`Error creating space: ${error}`); - return response.customError(wrapError(error)); - } - }) - ); + }) + ); } diff --git a/x-pack/plugins/spaces/server/routes/api/external/put.test.ts b/x-pack/plugins/spaces/server/routes/api/external/put.test.ts index fd255a8aadc2b..8aa71d30fc4bb 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/put.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/put.test.ts @@ -16,9 +16,11 @@ import { httpServiceMock, loggingSystemMock, } from '@kbn/core/server/mocks'; +import type { MockedVersionedRouter } from '@kbn/core-http-router-server-mocks'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import { initPutSpacesApi } from './put'; +import { API_VERSIONS } from '../../../../common'; import { spacesConfig } from '../../../lib/__fixtures__'; import { SpacesClientService } from '../../../spaces_client'; import { SpacesService } from '../../../spaces_service'; @@ -36,6 +38,7 @@ describe('PUT /api/spaces/space', () => { const setup = async () => { const httpService = httpServiceMock.createSetupContract(); const router = httpService.createRouter(); + const versionedRouterMock = router.versioned as MockedVersionedRouter; const coreStart = coreMock.createStart(); @@ -75,11 +78,12 @@ describe('PUT /api/spaces/space', () => { isServerless: false, }); - const [routeDefinition, routeHandler] = router.put.mock.calls[0]; + const { handler, config } = versionedRouterMock.getRoute('put', '/api/spaces/space/{id}') + .versions[API_VERSIONS.public.v1]; return { - routeValidation: routeDefinition.validate as RouteValidatorConfig<{}, {}, {}>, - routeHandler, + routeValidation: (config.validate as any).request as RouteValidatorConfig<{}, {}, {}>, + routeHandler: handler, savedObjectsRepositoryMock, }; }; diff --git a/x-pack/plugins/spaces/server/routes/api/external/put.ts b/x-pack/plugins/spaces/server/routes/api/external/put.ts index 25f0d70d75dc3..9a2af2219262e 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/put.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/put.ts @@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import type { ExternalRouteDeps } from '.'; -import type { Space } from '../../../../common'; +import { API_VERSIONS, type Space } from '../../../../common'; import { wrapError } from '../../../lib/errors'; import { getSpaceSchema } from '../../../lib/space_schema'; import { createLicensedRouteHandler } from '../../lib'; @@ -17,37 +17,41 @@ import { createLicensedRouteHandler } from '../../lib'; export function initPutSpacesApi(deps: ExternalRouteDeps) { const { router, getSpacesService, isServerless } = deps; - router.put( - { + router.versioned + .put({ path: '/api/spaces/space/{id}', - options: { - access: 'public', - description: `Update a space`, - }, - validate: { - params: schema.object({ - id: schema.string(), - }), - body: getSpaceSchema(isServerless), + access: 'public', + description: `Update a space`, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + params: schema.object({ + id: schema.string(), + }), + body: getSpaceSchema(isServerless), + }, + }, }, - }, - createLicensedRouteHandler(async (context, request, response) => { - const spacesClient = getSpacesService().createSpacesClient(request); + createLicensedRouteHandler(async (context, request, response) => { + const spacesClient = getSpacesService().createSpacesClient(request); - const space = request.body; - const id = request.params.id; + const space = request.body; + const id = request.params.id; - let result: Space; - try { - result = await spacesClient.update(id, { ...space }); - } catch (error) { - if (SavedObjectsErrorHelpers.isNotFoundError(error)) { - return response.notFound(); + let result: Space; + try { + result = await spacesClient.update(id, { ...space }); + } catch (error) { + if (SavedObjectsErrorHelpers.isNotFoundError(error)) { + return response.notFound(); + } + return response.customError(wrapError(error)); } - return response.customError(wrapError(error)); - } - return response.ok({ body: result }); - }) - ); + return response.ok({ body: result }); + }) + ); } From e319dcb77cfd72fd02a754062962ed1aedb72366 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:49:34 +0000 Subject: [PATCH 08/23] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- x-pack/plugins/security/tsconfig.json | 1 + x-pack/plugins/spaces/tsconfig.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security/tsconfig.json b/x-pack/plugins/security/tsconfig.json index c3df5dda29481..0e941b222ad36 100644 --- a/x-pack/plugins/security/tsconfig.json +++ b/x-pack/plugins/security/tsconfig.json @@ -87,6 +87,7 @@ "@kbn/security-authorization-core", "@kbn/security-role-management-model", "@kbn/security-ui-components", + "@kbn/core-http-router-server-mocks", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/spaces/tsconfig.json b/x-pack/plugins/spaces/tsconfig.json index ba13f984ef66d..ebd0582a4086d 100644 --- a/x-pack/plugins/spaces/tsconfig.json +++ b/x-pack/plugins/spaces/tsconfig.json @@ -37,7 +37,8 @@ "@kbn/utility-types-jest", "@kbn/security-plugin-types-public", "@kbn/cloud-plugin", - "@kbn/core-analytics-browser" + "@kbn/core-analytics-browser", + "@kbn/core-http-router-server-mocks" ], "exclude": [ "target/**/*", From 0aa971e1800c5de4b2c65547d907d036bdab2c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Wed, 25 Sep 2024 16:47:48 +0200 Subject: [PATCH 09/23] Adds version header to axios request in ftr roles util --- .../services/security/role.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts b/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts index 88ea94439984f..98a09ac52456c 100644 --- a/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts @@ -10,6 +10,11 @@ import util from 'util'; import { ToolingLog } from '@kbn/tooling-log'; import { KbnClient } from '@kbn/test'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; + +const HEADERS = Object.freeze({ + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', +}); export class Role { constructor(private log: ToolingLog, private kibanaServer: KbnClient) {} @@ -23,6 +28,7 @@ export class Role { kibana: role.kibana, elasticsearch: role.elasticsearch, }, + headers: HEADERS, retries: 0, }); if (status !== 204) { From 031c564a0bb9efd62613ad96a6dd1b19652f6b5b Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:03:23 +0000 Subject: [PATCH 10/23] [CI] Auto-commit changed files from 'node scripts/notice' --- packages/kbn-ftr-common-functional-ui-services/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/kbn-ftr-common-functional-ui-services/tsconfig.json b/packages/kbn-ftr-common-functional-ui-services/tsconfig.json index 555e696f0ca51..da2f0f62c8ee0 100644 --- a/packages/kbn-ftr-common-functional-ui-services/tsconfig.json +++ b/packages/kbn-ftr-common-functional-ui-services/tsconfig.json @@ -13,6 +13,7 @@ "@kbn/test-subj-selector", "@kbn/ftr-common-functional-services", "@kbn/std", - "@kbn/expect" + "@kbn/expect", + "@kbn/core-http-common" ] } From fe2e7ebf9f0b769b0e47d0caa0b35bc94baf1af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Thu, 26 Sep 2024 12:18:24 +0200 Subject: [PATCH 11/23] Adds version header to spaces FTR service axios config --- x-pack/test/common/services/spaces.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/test/common/services/spaces.ts b/x-pack/test/common/services/spaces.ts index a1657996239ac..b331ea0368de6 100644 --- a/x-pack/test/common/services/spaces.ts +++ b/x-pack/test/common/services/spaces.ts @@ -12,6 +12,7 @@ import { format as formatUrl } from 'url'; import util from 'util'; import Chance from 'chance'; import Url from 'url'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { FtrProviderContext } from '../ftr_provider_context'; const chance = new Chance(); @@ -44,7 +45,10 @@ export function SpacesServiceProvider({ getService }: FtrProviderContext) { : undefined; const axios = Axios.create({ - headers: { 'kbn-xsrf': 'x-pack/ftr/services/spaces/space' }, + headers: { + 'kbn-xsrf': 'x-pack/ftr/services/spaces/space', + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, baseURL: url, maxRedirects: 0, validateStatus: () => true, // we do our own validation below and throw better error messages From 68de9e860ba7f4cb408f681345bf4c43c5175cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Fri, 27 Sep 2024 08:23:46 +0200 Subject: [PATCH 12/23] Adds version to http calls from spaces manager --- .../spaces/public/spaces_manager/spaces_manager.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts b/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts index 962f02ca2bd79..86c44fbff8b11 100644 --- a/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts +++ b/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts @@ -23,6 +23,7 @@ interface SavedObjectTarget { } const TAG_TYPE = 'tag'; +const version = '2023-10-31'; export class SpacesManager { private activeSpace$: BehaviorSubject = new BehaviorSubject(null); @@ -49,11 +50,11 @@ export class SpacesManager { public async getSpaces(options: GetAllSpacesOptions = {}): Promise { const { purpose, includeAuthorizedPurposes } = options; const query = { purpose, include_authorized_purposes: includeAuthorizedPurposes }; - return await this.http.get('/api/spaces/space', { query }); + return await this.http.get('/api/spaces/space', { query, version }); } public async getSpace(id: string): Promise { - return await this.http.get(`/api/spaces/space/${encodeURIComponent(id)}`); + return await this.http.get(`/api/spaces/space/${encodeURIComponent(id)}`, { version }); } public async getActiveSpace({ forceRefresh = false } = {}) { @@ -69,6 +70,7 @@ export class SpacesManager { public async createSpace(space: Space) { await this.http.post(`/api/spaces/space`, { body: JSON.stringify(space), + version, }); } @@ -78,6 +80,7 @@ export class SpacesManager { overwrite: true, }, body: JSON.stringify(space), + version, }); const activeSpaceId = (await this.getActiveSpace()).id; @@ -88,7 +91,7 @@ export class SpacesManager { } public async deleteSpace(space: Space) { - await this.http.delete(`/api/spaces/space/${encodeURIComponent(space.id)}`); + await this.http.delete(`/api/spaces/space/${encodeURIComponent(space.id)}`, { version }); } public async disableLegacyUrlAliases(aliases: LegacyUrlAliasTarget[]) { From 15ea4df3d5a8164d82ea1e94f7241e42ca319898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Fri, 27 Sep 2024 08:26:52 +0200 Subject: [PATCH 13/23] Uses common def for api version --- .../spaces/public/spaces_manager/spaces_manager.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts b/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts index 86c44fbff8b11..d2f2681bd1809 100644 --- a/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts +++ b/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts @@ -13,7 +13,12 @@ import type { SavedObjectsCollectMultiNamespaceReferencesResponse } from '@kbn/c import type { LegacyUrlAliasTarget } from '@kbn/core-saved-objects-common'; import type { Role } from '@kbn/security-plugin-types-common'; -import type { GetAllSpacesOptions, GetSpaceResult, Space } from '../../common'; +import { + API_VERSIONS, + type GetAllSpacesOptions, + type GetSpaceResult, + type Space, +} from '../../common'; import type { CopySavedObjectsToSpaceResponse } from '../copy_saved_objects_to_space/types'; import type { SpaceContentTypeSummaryItem } from '../types'; @@ -23,7 +28,7 @@ interface SavedObjectTarget { } const TAG_TYPE = 'tag'; -const version = '2023-10-31'; +const version = API_VERSIONS.public.v1; export class SpacesManager { private activeSpace$: BehaviorSubject = new BehaviorSubject(null); From 262673dc0727550c3d7ad54e172da5f69b38bcee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Fri, 27 Sep 2024 15:43:32 +0200 Subject: [PATCH 14/23] Comments version prop of fetch options, removes "experimental" --- packages/core/http/core-http-browser/src/types.ts | 5 ++++- .../services/security/role.ts | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/core/http/core-http-browser/src/types.ts b/packages/core/http/core-http-browser/src/types.ts index 0d607274fce4a..f20822015439b 100644 --- a/packages/core/http/core-http-browser/src/types.ts +++ b/packages/core/http/core-http-browser/src/types.ts @@ -322,7 +322,10 @@ export interface HttpFetchOptions extends HttpRequestInit { context?: KibanaExecutionContext; - /** @experimental */ + /** + * When defined, the API version string to used to populate the ELASTIC_HTTP_VERSION_HEADER. + * Defaults to undefined. + */ version?: ApiVersion; } diff --git a/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts b/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts index 98a09ac52456c..1c190286fe6eb 100644 --- a/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts @@ -12,7 +12,7 @@ import { ToolingLog } from '@kbn/tooling-log'; import { KbnClient } from '@kbn/test'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -const HEADERS = Object.freeze({ +const headers = Object.freeze({ [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', }); @@ -28,7 +28,7 @@ export class Role { kibana: role.kibana, elasticsearch: role.elasticsearch, }, - headers: HEADERS, + headers, retries: 0, }); if (status !== 204) { From c85715aa1c307922da9c693b5151558d4158f4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Fri, 27 Sep 2024 15:45:01 +0200 Subject: [PATCH 15/23] Fixes typo --- packages/core/http/core-http-browser/src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/http/core-http-browser/src/types.ts b/packages/core/http/core-http-browser/src/types.ts index f20822015439b..6a1e0a7c358e0 100644 --- a/packages/core/http/core-http-browser/src/types.ts +++ b/packages/core/http/core-http-browser/src/types.ts @@ -323,7 +323,7 @@ export interface HttpFetchOptions extends HttpRequestInit { context?: KibanaExecutionContext; /** - * When defined, the API version string to used to populate the ELASTIC_HTTP_VERSION_HEADER. + * When defined, the API version string used to populate the ELASTIC_HTTP_VERSION_HEADER. * Defaults to undefined. */ version?: ApiVersion; From 5e42731df1a9b2330ac0695f4501211e266a002d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Fri, 27 Sep 2024 16:30:56 +0200 Subject: [PATCH 16/23] Adds versionResolution to FTR runTests --- .../services/security/role.ts | 28 +++++++++---------- .../functional_tests/run_tests/run_tests.ts | 5 ++++ x-pack/test/common/services/spaces.ts | 4 +-- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts b/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts index 1c190286fe6eb..7f3ca86d8248c 100644 --- a/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/security/role.ts @@ -10,27 +10,25 @@ import util from 'util'; import { ToolingLog } from '@kbn/tooling-log'; import { KbnClient } from '@kbn/test'; -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; - -const headers = Object.freeze({ - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', -}); export class Role { constructor(private log: ToolingLog, private kibanaServer: KbnClient) {} public async create(name: string, role: any) { this.log.debug(`creating role ${name}`); - const { data, status, statusText } = await this.kibanaServer.request({ - path: `/api/security/role/${name}`, - method: 'PUT', - body: { - kibana: role.kibana, - elasticsearch: role.elasticsearch, - }, - headers, - retries: 0, - }); + const { data, status, statusText } = await this.kibanaServer + .request({ + path: `/api/security/role/${name}`, + method: 'PUT', + body: { + kibana: role.kibana, + elasticsearch: role.elasticsearch, + }, + retries: 0, + }) + .catch((e) => { + throw new Error(util.inspect(e.axiosError.response, true)); + }); if (status !== 204) { throw new Error( `Expected status code of 204, received ${status} ${statusText}: ${util.inspect(data)}` diff --git a/packages/kbn-test/src/functional_tests/run_tests/run_tests.ts b/packages/kbn-test/src/functional_tests/run_tests/run_tests.ts index 785d6efc085ff..930fc91037d1a 100644 --- a/packages/kbn-test/src/functional_tests/run_tests/run_tests.ts +++ b/packages/kbn-test/src/functional_tests/run_tests/run_tests.ts @@ -120,6 +120,11 @@ export async function runTests(log: ToolingLog, options: RunTestsOptions) { logsDir: options.logsDir, installDir: options.installDir, onEarlyExit, + extraKbnOpts: [ + config.get('serverless') + ? '--server.versioned.versionResolution=newest' + : '--server.versioned.versionResolution=oldest', + ], }); if (abortCtrl.signal.aborted) { diff --git a/x-pack/test/common/services/spaces.ts b/x-pack/test/common/services/spaces.ts index b331ea0368de6..ec02db7c998d6 100644 --- a/x-pack/test/common/services/spaces.ts +++ b/x-pack/test/common/services/spaces.ts @@ -12,7 +12,7 @@ import { format as formatUrl } from 'url'; import util from 'util'; import Chance from 'chance'; import Url from 'url'; -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +// import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { FtrProviderContext } from '../ftr_provider_context'; const chance = new Chance(); @@ -47,7 +47,7 @@ export function SpacesServiceProvider({ getService }: FtrProviderContext) { const axios = Axios.create({ headers: { 'kbn-xsrf': 'x-pack/ftr/services/spaces/space', - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + // [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', }, baseURL: url, maxRedirects: 0, From df5a112ff74fa7a010959f0adf172ee40c2930ef Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:45:19 +0000 Subject: [PATCH 17/23] [CI] Auto-commit changed files from 'node scripts/notice' --- packages/kbn-ftr-common-functional-ui-services/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/kbn-ftr-common-functional-ui-services/tsconfig.json b/packages/kbn-ftr-common-functional-ui-services/tsconfig.json index da2f0f62c8ee0..f1436196d3f21 100644 --- a/packages/kbn-ftr-common-functional-ui-services/tsconfig.json +++ b/packages/kbn-ftr-common-functional-ui-services/tsconfig.json @@ -14,6 +14,5 @@ "@kbn/ftr-common-functional-services", "@kbn/std", "@kbn/expect", - "@kbn/core-http-common" ] } From 2abd2e6a4482247e19f6cb386f9bdedfc38bb6b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Fri, 27 Sep 2024 16:52:00 +0200 Subject: [PATCH 18/23] Removes commented code --- x-pack/test/common/services/spaces.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/test/common/services/spaces.ts b/x-pack/test/common/services/spaces.ts index ec02db7c998d6..98cc54e456200 100644 --- a/x-pack/test/common/services/spaces.ts +++ b/x-pack/test/common/services/spaces.ts @@ -12,7 +12,6 @@ import { format as formatUrl } from 'url'; import util from 'util'; import Chance from 'chance'; import Url from 'url'; -// import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { FtrProviderContext } from '../ftr_provider_context'; const chance = new Chance(); @@ -47,7 +46,6 @@ export function SpacesServiceProvider({ getService }: FtrProviderContext) { const axios = Axios.create({ headers: { 'kbn-xsrf': 'x-pack/ftr/services/spaces/space', - // [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', }, baseURL: url, maxRedirects: 0, From 7e17054cb587bbee1d4f6d2c49a34d80ca8863c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Mon, 30 Sep 2024 12:45:46 +0200 Subject: [PATCH 19/23] Adds API version option to requests in the roles client and edit role page --- .../management/roles/edit_role/edit_role_page.tsx | 3 ++- .../public/management/roles/roles_api_client.ts | 13 ++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx index 02812eda34c7b..58d1e0f8c87f5 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx @@ -46,6 +46,7 @@ import { toMountPoint } from '@kbn/react-kibana-mount'; import type { Cluster } from '@kbn/remote-clusters-plugin/public'; import { REMOTE_CLUSTERS_PATH } from '@kbn/remote-clusters-plugin/public'; import { KibanaPrivileges } from '@kbn/security-role-management-model'; +import { API_VERSIONS as SPACES_API_VERSIONS } from '@kbn/spaces-plugin/common'; import type { Space, SpacesApiUi } from '@kbn/spaces-plugin/public'; import type { PublicMethodsOf } from '@kbn/utility-types'; @@ -272,7 +273,7 @@ function useRole( function useSpaces(http: HttpStart, fatalErrors: FatalErrorsSetup) { const [spaces, setSpaces] = useState<{ enabled: boolean; list: Space[] } | null>(null); useEffect(() => { - http.get('/api/spaces/space').then( + http.get('/api/spaces/space', { version: SPACES_API_VERSIONS.public.v1 }).then( (fetchedSpaces) => setSpaces({ enabled: true, list: fetchedSpaces }), (err: IHttpFetchError) => { // Spaces plugin can be disabled and hence this endpoint can be unavailable. diff --git a/x-pack/plugins/security/public/management/roles/roles_api_client.ts b/x-pack/plugins/security/public/management/roles/roles_api_client.ts index d6dcab658d21c..5c3970e82c516 100644 --- a/x-pack/plugins/security/public/management/roles/roles_api_client.ts +++ b/x-pack/plugins/security/public/management/roles/roles_api_client.ts @@ -9,25 +9,31 @@ import type { HttpStart } from '@kbn/core/public'; import type { BulkUpdatePayload, BulkUpdateRoleResponse } from '@kbn/security-plugin-types-public'; import type { Role, RoleIndexPrivilege, RoleRemoteIndexPrivilege } from '../../../common'; +import { API_VERSIONS } from '../../../common/constants'; import { copyRole } from '../../../common/model'; +const version = API_VERSIONS.roles.public.v1; + export class RolesAPIClient { constructor(private readonly http: HttpStart) {} public getRoles = async () => { - return await this.http.get('/api/security/role'); + return await this.http.get('/api/security/role', { version }); }; public getRole = async (roleName: string) => { - return await this.http.get(`/api/security/role/${encodeURIComponent(roleName)}`); + return await this.http.get(`/api/security/role/${encodeURIComponent(roleName)}`, { + version, + }); }; public deleteRole = async (roleName: string) => { - await this.http.delete(`/api/security/role/${encodeURIComponent(roleName)}`); + await this.http.delete(`/api/security/role/${encodeURIComponent(roleName)}`, { version }); }; public saveRole = async ({ role, createOnly = false }: { role: Role; createOnly?: boolean }) => { await this.http.put(`/api/security/role/${encodeURIComponent(role.name)}`, { + version, body: JSON.stringify(this.transformRoleForSave(copyRole(role))), query: { createOnly }, }); @@ -37,6 +43,7 @@ export class RolesAPIClient { rolesUpdate, }: BulkUpdatePayload): Promise => { return await this.http.post('/api/security/roles', { + version, body: JSON.stringify({ roles: Object.fromEntries( rolesUpdate.map((role) => [role.name, this.transformRoleForSave(copyRole(role))]) From 4de5ea89b7142458cad78521d57ca6ed507f1d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Wed, 2 Oct 2024 11:39:36 +0200 Subject: [PATCH 20/23] Adds OAS tags --- .../security/server/routes/authorization/roles/delete.ts | 3 +++ .../plugins/security/server/routes/authorization/roles/get.ts | 3 +++ .../security/server/routes/authorization/roles/get_all.ts | 3 +++ .../plugins/security/server/routes/authorization/roles/post.ts | 3 +++ .../plugins/security/server/routes/authorization/roles/put.ts | 3 +++ x-pack/plugins/spaces/server/routes/api/external/delete.ts | 3 +++ x-pack/plugins/spaces/server/routes/api/external/get.ts | 3 +++ x-pack/plugins/spaces/server/routes/api/external/get_all.ts | 3 +++ x-pack/plugins/spaces/server/routes/api/external/post.ts | 3 +++ x-pack/plugins/spaces/server/routes/api/external/put.ts | 3 +++ 10 files changed, 30 insertions(+) diff --git a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts index f0f0182d8c655..fe7c97b32d27b 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts @@ -18,6 +18,9 @@ export function defineDeleteRolesRoutes({ router }: RouteDefinitionParams) { path: '/api/security/role/{name}', access: 'public', summary: `Delete a role`, + options: { + tags: ['oas-tag:roles'], + }, }) .addVersion( { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get.ts b/x-pack/plugins/security/server/routes/authorization/roles/get.ts index 2d6fe10c932aa..f36c785758976 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.ts @@ -24,6 +24,9 @@ export function defineGetRolesRoutes({ path: '/api/security/role/{name}', access: 'public', summary: `Get a role`, + options: { + tags: ['oas-tag:roles'], + }, }) .addVersion( { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts index 689718e536b61..07e9a953be8fb 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts @@ -24,6 +24,9 @@ export function defineGetAllRolesRoutes({ path: '/api/security/role', access: 'public', summary: `Get all roles`, + options: { + tags: ['oas-tag:roles'], + }, }) .addVersion( { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/post.ts b/x-pack/plugins/security/server/routes/authorization/roles/post.ts index 284c8e9c9a478..0fe918ee5cc3e 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/post.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/post.ts @@ -45,6 +45,9 @@ export function defineBulkCreateOrUpdateRolesRoutes({ path: '/api/security/roles', access: 'public', summary: 'Create or update roles', + options: { + tags: ['oas-tag:roles'], + }, }) .addVersion( { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.ts index 35542c7a09a3d..16e2ab819e781 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.ts @@ -26,6 +26,9 @@ export function definePutRolesRoutes({ path: '/api/security/role/{name}', access: 'public', summary: `Create or update a role`, + options: { + tags: ['oas-tag:roles'], + }, }) .addVersion( { diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.ts index 9fe049599dca6..515f8811e5dcf 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/delete.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.ts @@ -23,6 +23,9 @@ export function initDeleteSpacesApi(deps: ExternalRouteDeps) { path: '/api/spaces/space/{id}', access: 'public', description: `Delete a space`, + options: { + tags: ['oas-tag:spaces'], + }, }) .addVersion( { diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.ts b/x-pack/plugins/spaces/server/routes/api/external/get.ts index ee2104ee55302..8d4e3c0c359ef 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get.ts @@ -21,6 +21,9 @@ export function initGetSpaceApi(deps: ExternalRouteDeps) { path: '/api/spaces/space/{id}', access: 'public', description: `Get a space`, + options: { + tags: ['oas-tag:spaces'], + }, }) .addVersion( { diff --git a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts index 9fa47a808d97f..baa47ca6956dc 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts @@ -20,6 +20,9 @@ export function initGetAllSpacesApi(deps: ExternalRouteDeps) { path: '/api/spaces/space', access: 'public', description: `Get all spaces`, + options: { + tags: ['oas-tag:spaces'], + }, }) .addVersion( { diff --git a/x-pack/plugins/spaces/server/routes/api/external/post.ts b/x-pack/plugins/spaces/server/routes/api/external/post.ts index 5132a50ad0101..c47ea4ad5f9bf 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/post.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/post.ts @@ -23,6 +23,9 @@ export function initPostSpacesApi(deps: ExternalRouteDeps) { path: '/api/spaces/space', access: 'public', description: `Create a space`, + options: { + tags: ['oas-tag:spaces'], + }, }) .addVersion( { diff --git a/x-pack/plugins/spaces/server/routes/api/external/put.ts b/x-pack/plugins/spaces/server/routes/api/external/put.ts index 9a2af2219262e..10374dc94f600 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/put.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/put.ts @@ -22,6 +22,9 @@ export function initPutSpacesApi(deps: ExternalRouteDeps) { path: '/api/spaces/space/{id}', access: 'public', description: `Update a space`, + options: { + tags: ['oas-tag:spaces'], + }, }) .addVersion( { From 9497dbf3d7a05871bc02626b0b6603efc6343c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjeramysoucy=E2=80=9D?= Date: Thu, 3 Oct 2024 11:52:03 +0200 Subject: [PATCH 21/23] Adds roles and spaces API paths to OAS doc script --- .buildkite/scripts/steps/capture_oas_snapshot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/scripts/steps/capture_oas_snapshot.sh b/.buildkite/scripts/steps/capture_oas_snapshot.sh index 79dfdd96c8fc6..3c82fca5013c5 100755 --- a/.buildkite/scripts/steps/capture_oas_snapshot.sh +++ b/.buildkite/scripts/steps/capture_oas_snapshot.sh @@ -5,7 +5,7 @@ set -euo pipefail source .buildkite/scripts/common/util.sh echo --- Capture OAS snapshot -cmd="node scripts/capture_oas_snapshot --include-path /api/status --include-path /api/alerting/rule/ --include-path /api/alerting/rules --include-path /api/actions" +cmd="node scripts/capture_oas_snapshot --include-path /api/status --include-path /api/alerting/rule/ --include-path /api/alerting/rules --include-path /api/actions --include-path /api/security/role --include-path /api/spaces" if is_pr && ! is_auto_commit_disabled; then cmd="$cmd --update" fi From 6ae6950e7adaa13d395f6d456ed035aa149fea10 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 3 Oct 2024 10:32:17 +0000 Subject: [PATCH 22/23] [CI] Auto-commit changed files from 'node scripts/capture_oas_snapshot --include-path /api/status --include-path /api/alerting/rule/ --include-path /api/alerting/rules --include-path /api/actions --include-path /api/security/role --include-path /api/spaces --update' --- oas_docs/bundle.json | 1427 +++++++++++++++++++++++++++++++ oas_docs/bundle.serverless.json | 320 +++++++ 2 files changed, 1747 insertions(+) diff --git a/oas_docs/bundle.json b/oas_docs/bundle.json index 5fd690a2f6ceb..7c27f050640ec 100644 --- a/oas_docs/bundle.json +++ b/oas_docs/bundle.json @@ -6263,6 +6263,1427 @@ ] } }, + "/api/security/role": { + "get": { + "operationId": "%2Fapi%2Fsecurity%2Frole#0", + "parameters": [], + "responses": {}, + "summary": "Get all roles", + "tags": [ + "roles" + ] + } + }, + "/api/security/role/{name}": { + "delete": { + "operationId": "%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#1", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + }, + { + "in": "path", + "name": "name", + "required": true, + "schema": { + "minLength": 1, + "type": "string" + } + } + ], + "responses": {}, + "summary": "Delete a role", + "tags": [ + "roles" + ] + }, + "get": { + "operationId": "%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "in": "path", + "name": "name", + "required": true, + "schema": { + "minLength": 1, + "type": "string" + } + } + ], + "responses": {}, + "summary": "Get a role", + "tags": [ + "roles" + ] + }, + "put": { + "operationId": "%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#2", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + }, + { + "in": "path", + "name": "name", + "required": true, + "schema": { + "maxLength": 1024, + "minLength": 1, + "type": "string" + } + }, + { + "in": "query", + "name": "createOnly", + "required": false, + "schema": { + "default": false, + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "description": { + "maxLength": 2048, + "type": "string" + }, + "elasticsearch": { + "additionalProperties": false, + "properties": { + "cluster": { + "items": { + "type": "string" + }, + "type": "array" + }, + "indices": { + "items": { + "additionalProperties": false, + "properties": { + "allow_restricted_indices": { + "type": "boolean" + }, + "field_security": { + "additionalProperties": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "object" + }, + "names": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "privileges": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "query": { + "type": "string" + } + }, + "required": [ + "names", + "privileges" + ], + "type": "object" + }, + "type": "array" + }, + "remote_cluster": { + "items": { + "additionalProperties": false, + "properties": { + "clusters": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "privileges": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "privileges", + "clusters" + ], + "type": "object" + }, + "type": "array" + }, + "remote_indices": { + "items": { + "additionalProperties": false, + "properties": { + "allow_restricted_indices": { + "type": "boolean" + }, + "clusters": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "field_security": { + "additionalProperties": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "object" + }, + "names": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "privileges": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "query": { + "type": "string" + } + }, + "required": [ + "clusters", + "names", + "privileges" + ], + "type": "object" + }, + "type": "array" + }, + "run_as": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "kibana": { + "items": { + "additionalProperties": false, + "properties": { + "base": { + "anyOf": [ + { + "items": {}, + "type": "array" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "object" + }, + { + "type": "string" + } + ], + "nullable": true, + "oneOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "feature": { + "additionalProperties": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "object" + }, + "spaces": { + "anyOf": [ + { + "items": { + "enum": [ + "*" + ], + "type": "string" + }, + "maxItems": 1, + "minItems": 1, + "type": "array" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "default": [ + "*" + ] + } + }, + "required": [ + "base" + ], + "type": "object" + }, + "type": "array" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + } + }, + "required": [ + "elasticsearch" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "Create or update a role", + "tags": [ + "roles" + ] + } + }, + "/api/security/roles": { + "post": { + "operationId": "%2Fapi%2Fsecurity%2Froles#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "roles": { + "additionalProperties": { + "additionalProperties": false, + "properties": { + "description": { + "maxLength": 2048, + "type": "string" + }, + "elasticsearch": { + "additionalProperties": false, + "properties": { + "cluster": { + "items": { + "type": "string" + }, + "type": "array" + }, + "indices": { + "items": { + "additionalProperties": false, + "properties": { + "allow_restricted_indices": { + "type": "boolean" + }, + "field_security": { + "additionalProperties": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "object" + }, + "names": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "privileges": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "query": { + "type": "string" + } + }, + "required": [ + "names", + "privileges" + ], + "type": "object" + }, + "type": "array" + }, + "remote_cluster": { + "items": { + "additionalProperties": false, + "properties": { + "clusters": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "privileges": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "privileges", + "clusters" + ], + "type": "object" + }, + "type": "array" + }, + "remote_indices": { + "items": { + "additionalProperties": false, + "properties": { + "allow_restricted_indices": { + "type": "boolean" + }, + "clusters": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "field_security": { + "additionalProperties": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "object" + }, + "names": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "privileges": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "query": { + "type": "string" + } + }, + "required": [ + "clusters", + "names", + "privileges" + ], + "type": "object" + }, + "type": "array" + }, + "run_as": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "kibana": { + "items": { + "additionalProperties": false, + "properties": { + "base": { + "anyOf": [ + { + "items": {}, + "type": "array" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "object" + }, + { + "type": "string" + } + ], + "nullable": true, + "oneOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "feature": { + "additionalProperties": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "object" + }, + "spaces": { + "anyOf": [ + { + "items": { + "enum": [ + "*" + ], + "type": "string" + }, + "maxItems": 1, + "minItems": 1, + "type": "array" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "default": [ + "*" + ] + } + }, + "required": [ + "base" + ], + "type": "object" + }, + "type": "array" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + } + }, + "required": [ + "elasticsearch" + ], + "type": "object" + }, + "type": "object" + } + }, + "required": [ + "roles" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "Create or update roles", + "tags": [ + "roles" + ] + } + }, + "/api/spaces/_copy_saved_objects": { + "post": { + "description": "Copy saved objects to spaces", + "operationId": "%2Fapi%2Fspaces%2F_copy_saved_objects#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "compatibilityMode": { + "default": false, + "type": "boolean" + }, + "createNewCopies": { + "default": true, + "type": "boolean" + }, + "includeReferences": { + "default": false, + "type": "boolean" + }, + "objects": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type", + "id" + ], + "type": "object" + }, + "type": "array" + }, + "overwrite": { + "default": false, + "type": "boolean" + }, + "spaces": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "spaces", + "objects" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "", + "tags": [] + } + }, + "/api/spaces/_disable_legacy_url_aliases": { + "post": { + "description": "Disable legacy URL aliases", + "operationId": "%2Fapi%2Fspaces%2F_disable_legacy_url_aliases#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "aliases": { + "items": { + "additionalProperties": false, + "properties": { + "sourceId": { + "type": "string" + }, + "targetSpace": { + "type": "string" + }, + "targetType": { + "type": "string" + } + }, + "required": [ + "targetSpace", + "targetType", + "sourceId" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "aliases" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "", + "tags": [] + } + }, + "/api/spaces/_get_shareable_references": { + "post": { + "description": "Get shareable references", + "operationId": "%2Fapi%2Fspaces%2F_get_shareable_references#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "objects": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type", + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "objects" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "", + "tags": [] + } + }, + "/api/spaces/_resolve_copy_saved_objects_errors": { + "post": { + "description": "Resolve conflicts copying saved objects", + "operationId": "%2Fapi%2Fspaces%2F_resolve_copy_saved_objects_errors#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "compatibilityMode": { + "default": false, + "type": "boolean" + }, + "createNewCopies": { + "default": true, + "type": "boolean" + }, + "includeReferences": { + "default": false, + "type": "boolean" + }, + "objects": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type", + "id" + ], + "type": "object" + }, + "type": "array" + }, + "retries": { + "additionalProperties": { + "items": { + "additionalProperties": false, + "properties": { + "createNewCopy": { + "type": "boolean" + }, + "destinationId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "ignoreMissingReferences": { + "type": "boolean" + }, + "overwrite": { + "default": false, + "type": "boolean" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type", + "id" + ], + "type": "object" + }, + "type": "array" + }, + "type": "object" + } + }, + "required": [ + "retries", + "objects" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "", + "tags": [] + } + }, + "/api/spaces/_update_objects_spaces": { + "post": { + "description": "Update saved objects in spaces", + "operationId": "%2Fapi%2Fspaces%2F_update_objects_spaces#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "objects": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type", + "id" + ], + "type": "object" + }, + "type": "array" + }, + "spacesToAdd": { + "items": { + "type": "string" + }, + "type": "array" + }, + "spacesToRemove": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "objects", + "spacesToAdd", + "spacesToRemove" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "", + "tags": [] + } + }, + "/api/spaces/space": { + "get": { + "description": "Get all spaces", + "operationId": "%2Fapi%2Fspaces%2Fspace#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "purpose", + "required": false, + "schema": { + "enum": [ + "any", + "copySavedObjectsIntoSpace", + "shareSavedObjectsIntoSpace" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "include_authorized_purposes", + "required": true, + "schema": { + "anyOf": [ + { + "items": {}, + "type": "array" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "object" + }, + { + "type": "string" + } + ], + "nullable": true, + "oneOf": [ + { + "enum": [ + false + ], + "type": "boolean", + "x-oas-optional": true + }, + { + "type": "boolean", + "x-oas-optional": true + } + ] + } + } + ], + "responses": {}, + "summary": "", + "tags": [ + "spaces" + ] + }, + "post": { + "description": "Create a space", + "operationId": "%2Fapi%2Fspaces%2Fspace#1", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "_reserved": { + "type": "boolean" + }, + "color": { + "type": "string" + }, + "description": { + "type": "string" + }, + "disabledFeatures": { + "default": [], + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "type": "string" + }, + "imageUrl": { + "type": "string" + }, + "initials": { + "maxLength": 2, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "solution": { + "enum": [ + "security", + "oblt", + "es", + "classic" + ], + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "", + "tags": [ + "spaces" + ] + } + }, + "/api/spaces/space/{id}": { + "delete": { + "description": "Delete a space", + "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#2", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": {}, + "summary": "", + "tags": [ + "spaces" + ] + }, + "get": { + "description": "Get a space", + "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": {}, + "summary": "", + "tags": [ + "spaces" + ] + }, + "put": { + "description": "Update a space", + "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#1", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "_reserved": { + "type": "boolean" + }, + "color": { + "type": "string" + }, + "description": { + "type": "string" + }, + "disabledFeatures": { + "default": [], + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "type": "string" + }, + "imageUrl": { + "type": "string" + }, + "initials": { + "maxLength": 2, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "solution": { + "enum": [ + "security", + "oblt", + "es", + "classic" + ], + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "", + "tags": [ + "spaces" + ] + } + }, "/api/status": { "get": { "operationId": "%2Fapi%2Fstatus#0", @@ -6360,6 +7781,12 @@ { "name": "connectors" }, + { + "name": "roles" + }, + { + "name": "spaces" + }, { "name": "system" } diff --git a/oas_docs/bundle.serverless.json b/oas_docs/bundle.serverless.json index 5fd690a2f6ceb..c58eef641d6d7 100644 --- a/oas_docs/bundle.serverless.json +++ b/oas_docs/bundle.serverless.json @@ -6263,6 +6263,323 @@ ] } }, + "/api/spaces/space": { + "get": { + "description": "Get all spaces", + "operationId": "%2Fapi%2Fspaces%2Fspace#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "purpose", + "required": false, + "schema": { + "enum": [ + "any", + "copySavedObjectsIntoSpace", + "shareSavedObjectsIntoSpace" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "include_authorized_purposes", + "required": true, + "schema": { + "anyOf": [ + { + "items": {}, + "type": "array" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "object" + }, + { + "type": "string" + } + ], + "nullable": true, + "oneOf": [ + { + "enum": [ + false + ], + "type": "boolean", + "x-oas-optional": true + }, + { + "type": "boolean", + "x-oas-optional": true + } + ] + } + } + ], + "responses": {}, + "summary": "", + "tags": [ + "spaces" + ] + }, + "post": { + "description": "Create a space", + "operationId": "%2Fapi%2Fspaces%2Fspace#1", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "_reserved": { + "type": "boolean" + }, + "color": { + "type": "string" + }, + "description": { + "type": "string" + }, + "disabledFeatures": { + "default": [], + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "type": "string" + }, + "imageUrl": { + "type": "string" + }, + "initials": { + "maxLength": 2, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "", + "tags": [ + "spaces" + ] + } + }, + "/api/spaces/space/{id}": { + "delete": { + "description": "Delete a space", + "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#2", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": {}, + "summary": "", + "tags": [ + "spaces" + ] + }, + "get": { + "description": "Get a space", + "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#0", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": {}, + "summary": "", + "tags": [ + "spaces" + ] + }, + "put": { + "description": "Update a space", + "operationId": "%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#1", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "elastic-api-version", + "schema": { + "default": "2023-10-31", + "enum": [ + "2023-10-31" + ], + "type": "string" + } + }, + { + "description": "A required header to protect against CSRF attacks", + "in": "header", + "name": "kbn-xsrf", + "required": true, + "schema": { + "example": "true", + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json; Elastic-Api-Version=2023-10-31": { + "schema": { + "additionalProperties": false, + "properties": { + "_reserved": { + "type": "boolean" + }, + "color": { + "type": "string" + }, + "description": { + "type": "string" + }, + "disabledFeatures": { + "default": [], + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "type": "string" + }, + "imageUrl": { + "type": "string" + }, + "initials": { + "maxLength": 2, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + } + } + } + }, + "responses": {}, + "summary": "", + "tags": [ + "spaces" + ] + } + }, "/api/status": { "get": { "operationId": "%2Fapi%2Fstatus#0", @@ -6360,6 +6677,9 @@ { "name": "connectors" }, + { + "name": "spaces" + }, { "name": "system" } From b44b34847cd455da3ac9f14b74f7cd6288197bc6 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 3 Oct 2024 11:17:16 +0000 Subject: [PATCH 23/23] [CI] Auto-commit changed files from 'make api-docs && make api-docs-staging' --- .../output/kibana.serverless.staging.yaml | 209 ++++ oas_docs/output/kibana.serverless.yaml | 209 ++++ oas_docs/output/kibana.staging.yaml | 945 ++++++++++++++++++ oas_docs/output/kibana.yaml | 945 ++++++++++++++++++ 4 files changed, 2308 insertions(+) diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml index 17de64aabc4ef..39819e8307e75 100644 --- a/oas_docs/output/kibana.serverless.staging.yaml +++ b/oas_docs/output/kibana.serverless.staging.yaml @@ -16241,6 +16241,214 @@ paths: tags: - Security AI Assistant API - Prompts API + /api/spaces/space: + get: + description: Get all spaces + operationId: '%2Fapi%2Fspaces%2Fspace#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - in: query + name: purpose + required: false + schema: + enum: + - any + - copySavedObjectsIntoSpace + - shareSavedObjectsIntoSpace + type: string + - in: query + name: include_authorized_purposes + required: true + schema: + anyOf: + - items: {} + type: array + - type: boolean + - type: number + - type: object + - type: string + nullable: true + oneOf: + - enum: + - false + type: boolean + x-oas-optional: true + - type: boolean + x-oas-optional: true + responses: {} + summary: '' + tags: + - spaces + post: + description: Create a space + operationId: '%2Fapi%2Fspaces%2Fspace#1' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + _reserved: + type: boolean + color: + type: string + description: + type: string + disabledFeatures: + default: [] + items: + type: string + type: array + id: + type: string + imageUrl: + type: string + initials: + maxLength: 2 + type: string + name: + minLength: 1 + type: string + required: + - id + - name + responses: {} + summary: '' + tags: + - spaces + /api/spaces/space/{id}: + delete: + description: Delete a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#2' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: id + required: true + schema: + type: string + responses: {} + summary: '' + tags: + - spaces + get: + description: Get a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - in: path + name: id + required: true + schema: + type: string + responses: {} + summary: '' + tags: + - spaces + put: + description: Update a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#1' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: id + required: true + schema: + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + _reserved: + type: boolean + color: + type: string + description: + type: string + disabledFeatures: + default: [] + items: + type: string + type: array + id: + type: string + imageUrl: + type: string + initials: + maxLength: 2 + type: string + name: + minLength: 1 + type: string + required: + - id + - name + responses: {} + summary: '' + tags: + - spaces /api/status: get: operationId: '%2Fapi%2Fstatus#0' @@ -33323,4 +33531,5 @@ tags: name: Security Timeline API - description: SLO APIs enable you to define, manage and track service-level objectives name: slo + - name: spaces - name: system diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index 1b4209e9eec0a..c30f683b3bf97 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -9860,6 +9860,214 @@ paths: -X POST api/saved_objects/_import?createNewCopies=true -H "kbn-xsrf: true" --form file=@file.ndjson + /api/spaces/space: + get: + description: Get all spaces + operationId: '%2Fapi%2Fspaces%2Fspace#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - in: query + name: purpose + required: false + schema: + enum: + - any + - copySavedObjectsIntoSpace + - shareSavedObjectsIntoSpace + type: string + - in: query + name: include_authorized_purposes + required: true + schema: + anyOf: + - items: {} + type: array + - type: boolean + - type: number + - type: object + - type: string + nullable: true + oneOf: + - enum: + - false + type: boolean + x-oas-optional: true + - type: boolean + x-oas-optional: true + responses: {} + summary: '' + tags: + - spaces + post: + description: Create a space + operationId: '%2Fapi%2Fspaces%2Fspace#1' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + _reserved: + type: boolean + color: + type: string + description: + type: string + disabledFeatures: + default: [] + items: + type: string + type: array + id: + type: string + imageUrl: + type: string + initials: + maxLength: 2 + type: string + name: + minLength: 1 + type: string + required: + - id + - name + responses: {} + summary: '' + tags: + - spaces + /api/spaces/space/{id}: + delete: + description: Delete a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#2' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: id + required: true + schema: + type: string + responses: {} + summary: '' + tags: + - spaces + get: + description: Get a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - in: path + name: id + required: true + schema: + type: string + responses: {} + summary: '' + tags: + - spaces + put: + description: Update a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#1' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: id + required: true + schema: + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + _reserved: + type: boolean + color: + type: string + description: + type: string + disabledFeatures: + default: [] + items: + type: string + type: array + id: + type: string + imageUrl: + type: string + initials: + maxLength: 2 + type: string + name: + minLength: 1 + type: string + required: + - id + - name + responses: {} + summary: '' + tags: + - spaces /api/status: get: operationId: '%2Fapi%2Fstatus#0' @@ -16476,4 +16684,5 @@ tags: x-displayName: Saved objects - description: SLO APIs enable you to define, manage and track service-level objectives name: slo + - name: spaces - name: system diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml index 5830ef5ce40f7..3114d0bb7622a 100644 --- a/oas_docs/output/kibana.staging.yaml +++ b/oas_docs/output/kibana.staging.yaml @@ -20330,6 +20330,949 @@ paths: tags: - Security AI Assistant API - Prompts API + /api/security/role: + get: + operationId: '%2Fapi%2Fsecurity%2Frole#0' + parameters: [] + responses: {} + summary: Get all roles + tags: + - roles + /api/security/role/{name}: + delete: + operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#1' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: name + required: true + schema: + minLength: 1 + type: string + responses: {} + summary: Delete a role + tags: + - roles + get: + operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - in: path + name: name + required: true + schema: + minLength: 1 + type: string + responses: {} + summary: Get a role + tags: + - roles + put: + operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#2' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: name + required: true + schema: + maxLength: 1024 + minLength: 1 + type: string + - in: query + name: createOnly + required: false + schema: + default: false + type: boolean + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + description: + maxLength: 2048 + type: string + elasticsearch: + additionalProperties: false + type: object + properties: + cluster: + items: + type: string + type: array + indices: + items: + additionalProperties: false + type: object + properties: + allow_restricted_indices: + type: boolean + field_security: + additionalProperties: + items: + type: string + type: array + type: object + names: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + query: + type: string + required: + - names + - privileges + type: array + remote_cluster: + items: + additionalProperties: false + type: object + properties: + clusters: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + required: + - privileges + - clusters + type: array + remote_indices: + items: + additionalProperties: false + type: object + properties: + allow_restricted_indices: + type: boolean + clusters: + items: + type: string + minItems: 1 + type: array + field_security: + additionalProperties: + items: + type: string + type: array + type: object + names: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + query: + type: string + required: + - clusters + - names + - privileges + type: array + run_as: + items: + type: string + type: array + kibana: + items: + additionalProperties: false + type: object + properties: + base: + anyOf: + - items: {} + type: array + - type: boolean + - type: number + - type: object + - type: string + nullable: true + oneOf: + - items: + type: string + type: array + - items: + type: string + type: array + feature: + additionalProperties: + items: + type: string + type: array + type: object + spaces: + anyOf: + - items: + enum: + - '*' + type: string + maxItems: 1 + minItems: 1 + type: array + - items: + type: string + type: array + default: + - '*' + required: + - base + type: array + metadata: + additionalProperties: {} + type: object + required: + - elasticsearch + responses: {} + summary: Create or update a role + tags: + - roles + /api/security/roles: + post: + operationId: '%2Fapi%2Fsecurity%2Froles#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + roles: + additionalProperties: + additionalProperties: false + type: object + properties: + description: + maxLength: 2048 + type: string + elasticsearch: + additionalProperties: false + type: object + properties: + cluster: + items: + type: string + type: array + indices: + items: + additionalProperties: false + type: object + properties: + allow_restricted_indices: + type: boolean + field_security: + additionalProperties: + items: + type: string + type: array + type: object + names: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + query: + type: string + required: + - names + - privileges + type: array + remote_cluster: + items: + additionalProperties: false + type: object + properties: + clusters: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + required: + - privileges + - clusters + type: array + remote_indices: + items: + additionalProperties: false + type: object + properties: + allow_restricted_indices: + type: boolean + clusters: + items: + type: string + minItems: 1 + type: array + field_security: + additionalProperties: + items: + type: string + type: array + type: object + names: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + query: + type: string + required: + - clusters + - names + - privileges + type: array + run_as: + items: + type: string + type: array + kibana: + items: + additionalProperties: false + type: object + properties: + base: + anyOf: + - items: {} + type: array + - type: boolean + - type: number + - type: object + - type: string + nullable: true + oneOf: + - items: + type: string + type: array + - items: + type: string + type: array + feature: + additionalProperties: + items: + type: string + type: array + type: object + spaces: + anyOf: + - items: + enum: + - '*' + type: string + maxItems: 1 + minItems: 1 + type: array + - items: + type: string + type: array + default: + - '*' + required: + - base + type: array + metadata: + additionalProperties: {} + type: object + required: + - elasticsearch + type: object + required: + - roles + responses: {} + summary: Create or update roles + tags: + - roles + /api/spaces/_copy_saved_objects: + post: + description: Copy saved objects to spaces + operationId: '%2Fapi%2Fspaces%2F_copy_saved_objects#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + compatibilityMode: + default: false + type: boolean + createNewCopies: + default: true + type: boolean + includeReferences: + default: false + type: boolean + objects: + items: + additionalProperties: false + type: object + properties: + id: + type: string + type: + type: string + required: + - type + - id + type: array + overwrite: + default: false + type: boolean + spaces: + items: + type: string + type: array + required: + - spaces + - objects + responses: {} + summary: '' + tags: [] + /api/spaces/_disable_legacy_url_aliases: + post: + description: Disable legacy URL aliases + operationId: '%2Fapi%2Fspaces%2F_disable_legacy_url_aliases#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + aliases: + items: + additionalProperties: false + type: object + properties: + sourceId: + type: string + targetSpace: + type: string + targetType: + type: string + required: + - targetSpace + - targetType + - sourceId + type: array + required: + - aliases + responses: {} + summary: '' + tags: [] + /api/spaces/_get_shareable_references: + post: + description: Get shareable references + operationId: '%2Fapi%2Fspaces%2F_get_shareable_references#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + objects: + items: + additionalProperties: false + type: object + properties: + id: + type: string + type: + type: string + required: + - type + - id + type: array + required: + - objects + responses: {} + summary: '' + tags: [] + /api/spaces/_resolve_copy_saved_objects_errors: + post: + description: Resolve conflicts copying saved objects + operationId: '%2Fapi%2Fspaces%2F_resolve_copy_saved_objects_errors#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + compatibilityMode: + default: false + type: boolean + createNewCopies: + default: true + type: boolean + includeReferences: + default: false + type: boolean + objects: + items: + additionalProperties: false + type: object + properties: + id: + type: string + type: + type: string + required: + - type + - id + type: array + retries: + additionalProperties: + items: + additionalProperties: false + type: object + properties: + createNewCopy: + type: boolean + destinationId: + type: string + id: + type: string + ignoreMissingReferences: + type: boolean + overwrite: + default: false + type: boolean + type: + type: string + required: + - type + - id + type: array + type: object + required: + - retries + - objects + responses: {} + summary: '' + tags: [] + /api/spaces/_update_objects_spaces: + post: + description: Update saved objects in spaces + operationId: '%2Fapi%2Fspaces%2F_update_objects_spaces#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + objects: + items: + additionalProperties: false + type: object + properties: + id: + type: string + type: + type: string + required: + - type + - id + type: array + spacesToAdd: + items: + type: string + type: array + spacesToRemove: + items: + type: string + type: array + required: + - objects + - spacesToAdd + - spacesToRemove + responses: {} + summary: '' + tags: [] + /api/spaces/space: + get: + description: Get all spaces + operationId: '%2Fapi%2Fspaces%2Fspace#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - in: query + name: purpose + required: false + schema: + enum: + - any + - copySavedObjectsIntoSpace + - shareSavedObjectsIntoSpace + type: string + - in: query + name: include_authorized_purposes + required: true + schema: + anyOf: + - items: {} + type: array + - type: boolean + - type: number + - type: object + - type: string + nullable: true + oneOf: + - enum: + - false + type: boolean + x-oas-optional: true + - type: boolean + x-oas-optional: true + responses: {} + summary: '' + tags: + - spaces + post: + description: Create a space + operationId: '%2Fapi%2Fspaces%2Fspace#1' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + _reserved: + type: boolean + color: + type: string + description: + type: string + disabledFeatures: + default: [] + items: + type: string + type: array + id: + type: string + imageUrl: + type: string + initials: + maxLength: 2 + type: string + name: + minLength: 1 + type: string + solution: + enum: + - security + - oblt + - es + - classic + type: string + required: + - id + - name + responses: {} + summary: '' + tags: + - spaces + /api/spaces/space/{id}: + delete: + description: Delete a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#2' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: id + required: true + schema: + type: string + responses: {} + summary: '' + tags: + - spaces + get: + description: Get a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - in: path + name: id + required: true + schema: + type: string + responses: {} + summary: '' + tags: + - spaces + put: + description: Update a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#1' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: id + required: true + schema: + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + _reserved: + type: boolean + color: + type: string + description: + type: string + disabledFeatures: + default: [] + items: + type: string + type: array + id: + type: string + imageUrl: + type: string + initials: + maxLength: 2 + type: string + name: + minLength: 1 + type: string + solution: + enum: + - security + - oblt + - es + - classic + type: string + required: + - id + - name + responses: {} + summary: '' + tags: + - spaces /api/status: get: operationId: '%2Fapi%2Fstatus#0' @@ -41270,6 +42213,7 @@ tags: - name: Fleet uninstall tokens - description: Machine learning name: ml + - name: roles - description: > Export sets of saved objects that you want to import into {kib}, resolve import errors, and rotate an encryption key for encrypted saved objects @@ -41325,4 +42269,5 @@ tags: name: Security Timeline API - description: SLO APIs enable you to define, manage and track service-level objectives name: slo + - name: spaces - name: system diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index 35a446f538a6a..da28a9a3ade65 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -13132,6 +13132,949 @@ paths: summary: Resolve a saved object tags: - saved objects + /api/security/role: + get: + operationId: '%2Fapi%2Fsecurity%2Frole#0' + parameters: [] + responses: {} + summary: Get all roles + tags: + - roles + /api/security/role/{name}: + delete: + operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#1' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: name + required: true + schema: + minLength: 1 + type: string + responses: {} + summary: Delete a role + tags: + - roles + get: + operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - in: path + name: name + required: true + schema: + minLength: 1 + type: string + responses: {} + summary: Get a role + tags: + - roles + put: + operationId: '%2Fapi%2Fsecurity%2Frole%2F%7Bname%7D#2' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: name + required: true + schema: + maxLength: 1024 + minLength: 1 + type: string + - in: query + name: createOnly + required: false + schema: + default: false + type: boolean + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + description: + maxLength: 2048 + type: string + elasticsearch: + additionalProperties: false + type: object + properties: + cluster: + items: + type: string + type: array + indices: + items: + additionalProperties: false + type: object + properties: + allow_restricted_indices: + type: boolean + field_security: + additionalProperties: + items: + type: string + type: array + type: object + names: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + query: + type: string + required: + - names + - privileges + type: array + remote_cluster: + items: + additionalProperties: false + type: object + properties: + clusters: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + required: + - privileges + - clusters + type: array + remote_indices: + items: + additionalProperties: false + type: object + properties: + allow_restricted_indices: + type: boolean + clusters: + items: + type: string + minItems: 1 + type: array + field_security: + additionalProperties: + items: + type: string + type: array + type: object + names: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + query: + type: string + required: + - clusters + - names + - privileges + type: array + run_as: + items: + type: string + type: array + kibana: + items: + additionalProperties: false + type: object + properties: + base: + anyOf: + - items: {} + type: array + - type: boolean + - type: number + - type: object + - type: string + nullable: true + oneOf: + - items: + type: string + type: array + - items: + type: string + type: array + feature: + additionalProperties: + items: + type: string + type: array + type: object + spaces: + anyOf: + - items: + enum: + - '*' + type: string + maxItems: 1 + minItems: 1 + type: array + - items: + type: string + type: array + default: + - '*' + required: + - base + type: array + metadata: + additionalProperties: {} + type: object + required: + - elasticsearch + responses: {} + summary: Create or update a role + tags: + - roles + /api/security/roles: + post: + operationId: '%2Fapi%2Fsecurity%2Froles#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + roles: + additionalProperties: + additionalProperties: false + type: object + properties: + description: + maxLength: 2048 + type: string + elasticsearch: + additionalProperties: false + type: object + properties: + cluster: + items: + type: string + type: array + indices: + items: + additionalProperties: false + type: object + properties: + allow_restricted_indices: + type: boolean + field_security: + additionalProperties: + items: + type: string + type: array + type: object + names: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + query: + type: string + required: + - names + - privileges + type: array + remote_cluster: + items: + additionalProperties: false + type: object + properties: + clusters: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + required: + - privileges + - clusters + type: array + remote_indices: + items: + additionalProperties: false + type: object + properties: + allow_restricted_indices: + type: boolean + clusters: + items: + type: string + minItems: 1 + type: array + field_security: + additionalProperties: + items: + type: string + type: array + type: object + names: + items: + type: string + minItems: 1 + type: array + privileges: + items: + type: string + minItems: 1 + type: array + query: + type: string + required: + - clusters + - names + - privileges + type: array + run_as: + items: + type: string + type: array + kibana: + items: + additionalProperties: false + type: object + properties: + base: + anyOf: + - items: {} + type: array + - type: boolean + - type: number + - type: object + - type: string + nullable: true + oneOf: + - items: + type: string + type: array + - items: + type: string + type: array + feature: + additionalProperties: + items: + type: string + type: array + type: object + spaces: + anyOf: + - items: + enum: + - '*' + type: string + maxItems: 1 + minItems: 1 + type: array + - items: + type: string + type: array + default: + - '*' + required: + - base + type: array + metadata: + additionalProperties: {} + type: object + required: + - elasticsearch + type: object + required: + - roles + responses: {} + summary: Create or update roles + tags: + - roles + /api/spaces/_copy_saved_objects: + post: + description: Copy saved objects to spaces + operationId: '%2Fapi%2Fspaces%2F_copy_saved_objects#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + compatibilityMode: + default: false + type: boolean + createNewCopies: + default: true + type: boolean + includeReferences: + default: false + type: boolean + objects: + items: + additionalProperties: false + type: object + properties: + id: + type: string + type: + type: string + required: + - type + - id + type: array + overwrite: + default: false + type: boolean + spaces: + items: + type: string + type: array + required: + - spaces + - objects + responses: {} + summary: '' + tags: [] + /api/spaces/_disable_legacy_url_aliases: + post: + description: Disable legacy URL aliases + operationId: '%2Fapi%2Fspaces%2F_disable_legacy_url_aliases#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + aliases: + items: + additionalProperties: false + type: object + properties: + sourceId: + type: string + targetSpace: + type: string + targetType: + type: string + required: + - targetSpace + - targetType + - sourceId + type: array + required: + - aliases + responses: {} + summary: '' + tags: [] + /api/spaces/_get_shareable_references: + post: + description: Get shareable references + operationId: '%2Fapi%2Fspaces%2F_get_shareable_references#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + objects: + items: + additionalProperties: false + type: object + properties: + id: + type: string + type: + type: string + required: + - type + - id + type: array + required: + - objects + responses: {} + summary: '' + tags: [] + /api/spaces/_resolve_copy_saved_objects_errors: + post: + description: Resolve conflicts copying saved objects + operationId: '%2Fapi%2Fspaces%2F_resolve_copy_saved_objects_errors#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + compatibilityMode: + default: false + type: boolean + createNewCopies: + default: true + type: boolean + includeReferences: + default: false + type: boolean + objects: + items: + additionalProperties: false + type: object + properties: + id: + type: string + type: + type: string + required: + - type + - id + type: array + retries: + additionalProperties: + items: + additionalProperties: false + type: object + properties: + createNewCopy: + type: boolean + destinationId: + type: string + id: + type: string + ignoreMissingReferences: + type: boolean + overwrite: + default: false + type: boolean + type: + type: string + required: + - type + - id + type: array + type: object + required: + - retries + - objects + responses: {} + summary: '' + tags: [] + /api/spaces/_update_objects_spaces: + post: + description: Update saved objects in spaces + operationId: '%2Fapi%2Fspaces%2F_update_objects_spaces#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + objects: + items: + additionalProperties: false + type: object + properties: + id: + type: string + type: + type: string + required: + - type + - id + type: array + spacesToAdd: + items: + type: string + type: array + spacesToRemove: + items: + type: string + type: array + required: + - objects + - spacesToAdd + - spacesToRemove + responses: {} + summary: '' + tags: [] + /api/spaces/space: + get: + description: Get all spaces + operationId: '%2Fapi%2Fspaces%2Fspace#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - in: query + name: purpose + required: false + schema: + enum: + - any + - copySavedObjectsIntoSpace + - shareSavedObjectsIntoSpace + type: string + - in: query + name: include_authorized_purposes + required: true + schema: + anyOf: + - items: {} + type: array + - type: boolean + - type: number + - type: object + - type: string + nullable: true + oneOf: + - enum: + - false + type: boolean + x-oas-optional: true + - type: boolean + x-oas-optional: true + responses: {} + summary: '' + tags: + - spaces + post: + description: Create a space + operationId: '%2Fapi%2Fspaces%2Fspace#1' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + _reserved: + type: boolean + color: + type: string + description: + type: string + disabledFeatures: + default: [] + items: + type: string + type: array + id: + type: string + imageUrl: + type: string + initials: + maxLength: 2 + type: string + name: + minLength: 1 + type: string + solution: + enum: + - security + - oblt + - es + - classic + type: string + required: + - id + - name + responses: {} + summary: '' + tags: + - spaces + /api/spaces/space/{id}: + delete: + description: Delete a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#2' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: id + required: true + schema: + type: string + responses: {} + summary: '' + tags: + - spaces + get: + description: Get a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#0' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - in: path + name: id + required: true + schema: + type: string + responses: {} + summary: '' + tags: + - spaces + put: + description: Update a space + operationId: '%2Fapi%2Fspaces%2Fspace%2F%7Bid%7D#1' + parameters: + - description: The version of the API to use + in: header + name: elastic-api-version + schema: + default: '2023-10-31' + enum: + - '2023-10-31' + type: string + - description: A required header to protect against CSRF attacks + in: header + name: kbn-xsrf + required: true + schema: + example: 'true' + type: string + - in: path + name: id + required: true + schema: + type: string + requestBody: + content: + application/json; Elastic-Api-Version=2023-10-31: + schema: + additionalProperties: false + type: object + properties: + _reserved: + type: boolean + color: + type: string + description: + type: string + disabledFeatures: + default: [] + items: + type: string + type: array + id: + type: string + imageUrl: + type: string + initials: + maxLength: 2 + type: string + name: + minLength: 1 + type: string + solution: + enum: + - security + - oblt + - es + - classic + type: string + required: + - id + - name + responses: {} + summary: '' + tags: + - spaces /api/status: get: operationId: '%2Fapi%2Fstatus#0' @@ -23448,6 +24391,7 @@ tags: - name: Fleet uninstall tokens - description: Machine learning name: ml + - name: roles - description: > Export sets of saved objects that you want to import into {kib}, resolve import errors, and rotate an encryption key for encrypted saved objects @@ -23474,4 +24418,5 @@ tags: x-displayName: Saved objects - description: SLO APIs enable you to define, manage and track service-level objectives name: slo + - name: spaces - name: system