Skip to content

Commit

Permalink
[Workspace]Response forbidden error for not permitted workspace (#8641)…
Browse files Browse the repository at this point in the history
… (#8647)

* Response forbiden error for not permitted workspace



* Changeset file for PR #8641 created/updated

* Increase test coverage



---------



(cherry picked from commit 8d30da4)

Signed-off-by: Lin Wang <[email protected]>
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 18, 2024
1 parent d4fa7f8 commit 5a7042a
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/8641.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- [Workspace] Response forbidden error for not permitted workspace ([#8641](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8641))
116 changes: 116 additions & 0 deletions src/plugins/home/server/services/sample_data/routes/install.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { CoreSetup, RequestHandlerContext } from 'src/core/server';
import { coreMock, httpServerMock } from '../../../../../../core/server/mocks';
import { SavedObjectsErrorHelpers } from '../../../../../../core/server';
import { updateWorkspaceState } from '../../../../../../core/server/utils';
import { flightsSpecProvider } from '../data_sets';
import { SampleDatasetSchema } from '../lib/sample_dataset_registry_types';
Expand Down Expand Up @@ -222,4 +223,119 @@ describe('sample data install route', () => {
},
});
});

it('handler response forbidden error when bulkCreate forbidden inside workspace', async () => {
const mockWorkspaceId = 'workspace';

const mockClient = jest.fn().mockResolvedValue(true);

const mockSOClientGetResponse = {
saved_objects: [
{
type: 'dashboard',
id: '12345',
namespaces: ['default'],
attributes: { title: 'dashboard' },
},
],
};
const mockSOClient = {
bulkCreate: jest
.fn()
.mockRejectedValue(
SavedObjectsErrorHelpers.decorateForbiddenError(new Error('Invalid workspace permission'))
),
get: jest.fn().mockResolvedValue(mockSOClientGetResponse),
};

const mockContext = {
core: {
opensearch: {
legacy: {
client: { callAsCurrentUser: mockClient },
},
},
savedObjects: { client: mockSOClient },
},
};
const mockBody = { id: 'flights' };
const mockQuery = {};
const mockRequest = httpServerMock.createOpenSearchDashboardsRequest({
params: mockBody,
query: mockQuery,
});
updateWorkspaceState(mockRequest, { requestWorkspaceId: mockWorkspaceId });
const mockResponse = httpServerMock.createResponseFactory();

createInstallRoute(
mockCoreSetup.http.createRouter(),
sampleDatasets,
mockLogger,
mockUsageTracker
);

const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value;
const handler = mockRouter.post.mock.calls[0][1];

await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse);

expect(mockResponse.forbidden).toBeCalled();
expect(mockResponse.forbidden.mock.calls[0][0]).toMatchObject({
body: expect.stringContaining('Invalid workspace permission'),
});
});

it('handler response internal error when bulkCreate throw error', async () => {
const mockClient = jest.fn().mockResolvedValue(true);

const mockSOClientGetResponse = {
saved_objects: [
{
type: 'dashboard',
id: '12345',
namespaces: ['default'],
attributes: { title: 'dashboard' },
},
],
};
const mockSOClient = {
bulkCreate: jest.fn().mockRejectedValue(new Error('Unknown error')),
get: jest.fn().mockResolvedValue(mockSOClientGetResponse),
};

const mockContext = {
core: {
opensearch: {
legacy: {
client: { callAsCurrentUser: mockClient },
},
},
savedObjects: { client: mockSOClient },
},
};
const mockBody = { id: 'flights' };
const mockQuery = {};
const mockRequest = httpServerMock.createOpenSearchDashboardsRequest({
params: mockBody,
query: mockQuery,
});
const mockResponse = httpServerMock.createResponseFactory();

createInstallRoute(
mockCoreSetup.http.createRouter(),
sampleDatasets,
mockLogger,
mockUsageTracker
);

const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value;
const handler = mockRouter.post.mock.calls[0][1];

await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse);

expect(mockResponse.internalError).toBeCalled();
expect(mockResponse.internalError.mock.calls[0][0]).toMatchObject({
body: expect.stringContaining('Unknown error'),
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import { schema } from '@osd/config-schema';
import { IRouter, LegacyCallAPIOptions, Logger } from 'src/core/server';
import { getWorkspaceState } from '../../../../../../core/server/utils';
import { SavedObjectsErrorHelpers } from '../../../../../../core/server';
import { SampleDatasetSchema } from '../lib/sample_dataset_registry_types';
import { createIndexName } from '../lib/create_index_name';
import {
Expand Down Expand Up @@ -217,6 +218,9 @@ export function createInstallRoute(
} catch (err) {
const errMsg = `bulkCreate failed, error: ${err.message}`;
logger.warn(errMsg);
if (workspaceId && SavedObjectsErrorHelpers.isForbiddenError(err)) {
return res.forbidden({ body: errMsg });
}
return res.internalError({ body: errMsg });
}
const errors = createResults.saved_objects.filter((savedObjectCreateResult) => {
Expand Down

0 comments on commit 5a7042a

Please sign in to comment.