Skip to content

Commit

Permalink
[Spaces] Inited spaces API for serverless (elastic#184418)
Browse files Browse the repository at this point in the history
## Summary

Enabled spaces API for serverless in preparation for custom spaces and
custom roles.

The ability to create or delete spaces is still guarded by the
`xpack.spaces.maxSpaces: 1` setting.

### Hot to test
```
# should update default space name
PUT kbn:/api/spaces/space/default 
{
  "id": "default",
  "name": "Default name"
}

# should fail to create space because maxSpaces is set to 1
POST kbn:/api/spaces/space 
{
  "name": "my-space",
  "id": "my-space",
  "description": "a description",
  "color": "#5c5959",
  "disabledFeatures": ["canvas"]
}

# should fail to delete reserved space
DELETE kbn:/api/spaces/space/default

# should return empty list
POST kbn:/api/spaces/_get_shareable_references
{
  "objects": [{"type": "a", "id": "a"}]
}
```

### Checklist

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


### For maintainers

- [x] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)


### Release note
Enabled spaces API for serverless in preparation for custom spaces and
custom roles. The ability to create or delete spaces is still guarded by
the `xpack.spaces.maxSpaces` setting.

---------

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
elena-shostak and kibanamachine authored Jun 3, 2024
1 parent 99d5ef0 commit 9bb0018
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 80 deletions.
13 changes: 7 additions & 6 deletions x-pack/plugins/spaces/server/routes/api/external/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ export function initExternalSpacesApi(deps: ExternalRouteDeps) {
// In the serverless environment, Spaces are enabled but are effectively hidden from the user. We
// do not support more than 1 space: the default space. These HTTP APIs for creating, deleting,
// updating, and manipulating saved objects across multiple spaces are not needed.
initPutSpacesApi(deps);
initDeleteSpacesApi(deps);
initPostSpacesApi(deps);
initCopyToSpacesApi(deps);
initUpdateObjectsSpacesApi(deps);
initGetShareableReferencesApi(deps);

if (!deps.isServerless) {
initPutSpacesApi(deps);
initDeleteSpacesApi(deps);
initPostSpacesApi(deps);
initCopyToSpacesApi(deps);
initUpdateObjectsSpacesApi(deps);
initGetShareableReferencesApi(deps);
initDisableLegacyUrlAliasesApi(deps);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,94 +30,90 @@ export default function ({ getService }: FtrProviderContext) {
});

describe('route access', () => {
describe('disabled', () => {
it('#delete', async () => {
const { body, status } = await supertestWithoutAuth
.delete('/api/spaces/space/default')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);
it('#delete', async () => {
const { body, status } = await supertestWithoutAuth
.delete('/api/spaces/space/default')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);

// normally we'd get a 400 bad request if we tried to delete the default space
svlCommonApi.assertApiNotFound(body, status);
});
svlCommonApi.assertResponseStatusCode(400, status, body);
});

it('#create', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/space')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader)
.send({
id: 'custom',
name: 'Custom',
disabledFeatures: [],
});

svlCommonApi.assertApiNotFound(body, status);
});
it('#create', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/space')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader)
.send({
id: 'custom',
name: 'Custom',
disabledFeatures: [],
});

it('#update requires internal header', async () => {
const { body, status } = await supertestWithoutAuth
.put('/api/spaces/space/default')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader)
.send({
id: 'default',
name: 'UPDATED!',
disabledFeatures: [],
});
svlCommonApi.assertResponseStatusCode(400, status, body);
});

svlCommonApi.assertApiNotFound(body, status);
});
it('#update requires internal header', async () => {
const { body, status } = await supertestWithoutAuth
.put('/api/spaces/space/default')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader)
.send({
id: 'default',
name: 'UPDATED!',
disabledFeatures: [],
});

it('#copyToSpace', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/_copy_saved_objects')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);
svlCommonApi.assertResponseStatusCode(200, status, body);
});

// without a request body we would normally a 400 bad request if the endpoint was registered
svlCommonApi.assertApiNotFound(body, status);
});
it('#copyToSpace', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/_copy_saved_objects')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);

it('#resolveCopyToSpaceErrors', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/_resolve_copy_saved_objects_errors')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);
svlCommonApi.assertResponseStatusCode(400, status, body);
});

// without a request body we would normally a 400 bad request if the endpoint was registered
svlCommonApi.assertApiNotFound(body, status);
});
it('#resolveCopyToSpaceErrors', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/_resolve_copy_saved_objects_errors')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);

it('#updateObjectsSpaces', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/_update_objects_spaces')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);
svlCommonApi.assertResponseStatusCode(400, status, body);
});

// without a request body we would normally a 400 bad request if the endpoint was registered
svlCommonApi.assertApiNotFound(body, status);
});
it('#updateObjectsSpaces', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/_update_objects_spaces')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);

it('#getShareableReferences', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/_get_shareable_references')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);
svlCommonApi.assertResponseStatusCode(400, status, body);
});

// without a request body we would normally a 400 bad request if the endpoint was registered
svlCommonApi.assertApiNotFound(body, status);
});
it('#getShareableReferences', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/_get_shareable_references')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader)
.send({
objects: [{ type: 'a', id: 'a' }],
});

it('#disableLegacyUrlAliases', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/_disable_legacy_url_aliases')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);
svlCommonApi.assertResponseStatusCode(200, status, body);
});

// without a request body we would normally a 400 bad request if the endpoint was registered
svlCommonApi.assertApiNotFound(body, status);
});
it('#disableLegacyUrlAliases', async () => {
const { body, status } = await supertestWithoutAuth
.post('/api/spaces/_disable_legacy_url_aliases')
.set(internalRequestHeader)
.set(roleAuthc.apiKeyHeader);

// without a request body we would normally a 400 bad request if the endpoint was registered
svlCommonApi.assertApiNotFound(body, status);
});

describe('internal', () => {
Expand Down

0 comments on commit 9bb0018

Please sign in to comment.