Skip to content

Commit

Permalink
filter high level groups and action groups by cluster and index (open…
Browse files Browse the repository at this point in the history
…search-project#1482)

* filter high level groups and action groups by cluster and index

Signed-off-by: Derek Ho <dxho@amazon.com>

* remove unecessary console

Signed-off-by: Derek Ho <dxho@amazon.com>

* add semicolon back

Signed-off-by: Derek Ho <dxho@amazon.com>

* use map instead of flat map

Signed-off-by: Derek Ho <dxho@amazon.com>

* fix lint

Signed-off-by: Derek Ho <dxho@amazon.com>

* fix tests

Signed-off-by: Derek Ho <dxho@amazon.com>

* revert file

Signed-off-by: Derek Ho <dxho@amazon.com>

* fix up tests

Signed-off-by: Derek Ho <dxho@amazon.com>

* lint

Signed-off-by: Derek Ho <dxho@amazon.com>

---------

Signed-off-by: Derek Ho <dxho@amazon.com>
  • Loading branch information
derek-ho authored Jul 11, 2023
1 parent 32c02c8 commit 5fd8018
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 5 deletions.
23 changes: 18 additions & 5 deletions public/apps/configuration/panels/role-edit/role-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {
} from './tenant-panel';
import { RoleIndexPermissionStateClass, RoleTenantPermissionStateClass } from './types';
import { buildHashUrl, buildUrl } from '../../utils/url-builder';
import { ComboBoxOptions, ResourceType, Action } from '../../types';
import { ComboBoxOptions, ResourceType, Action, ActionGroupItem } from '../../types';
import {
useToastState,
createUnknownErrorToast,
Expand Down Expand Up @@ -106,12 +106,12 @@ export function RoleEdit(props: RoleEditDeps) {
}
}, [addToast, props.action, props.coreStart.http, props.sourceRoleName]);

const [actionGroups, setActionGroups] = useState<string[]>([]);
const [actionGroups, setActionGroups] = useState<Array<[string, ActionGroupItem]>>([]);
React.useEffect(() => {
const fetchActionGroupNames = async () => {
try {
const actionGroupsObject = await fetchActionGroups(props.coreStart.http);
setActionGroups(Object.keys(actionGroupsObject));
setActionGroups(Object.entries(actionGroupsObject));
} catch (e) {
addToast(createUnknownErrorToast('actionGroup', 'load data'));
console.error(e);
Expand Down Expand Up @@ -167,12 +167,25 @@ export function RoleEdit(props: RoleEditDeps) {
const clusterWisePermissionOptions = [
{
label: 'Permission groups',
options: actionGroups.map(stringToComboBoxOption),
options: actionGroups
.filter((actionGroup) => actionGroup[1].type === 'cluster')
.map((actionGroup) => actionGroup[0])
.map(stringToComboBoxOption),
},
{
label: 'Cluster permissions',
options: CLUSTER_PERMISSIONS.map(stringToComboBoxOption),
},
];

const indexWisePermissionOptions = [
{
label: 'Permission groups',
options: actionGroups
.filter((actionGroup) => actionGroup[1].type === 'index')
.map((actionGroup) => actionGroup[0])
.map(stringToComboBoxOption),
},
{
label: 'Index permissions',
options: INDEX_PERMISSIONS.map(stringToComboBoxOption),
Expand Down Expand Up @@ -219,7 +232,7 @@ export function RoleEdit(props: RoleEditDeps) {
<IndexPermissionPanel
state={roleIndexPermission}
setState={setRoleIndexPermission}
optionUniverse={clusterWisePermissionOptions}
optionUniverse={indexWisePermissionOptions}
/>
<EuiSpacer size="m" />
<TenantPanel
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* Copyright OpenSearch Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import React from 'react';
import { ClusterPermissionPanel } from '../cluster-permission-panel';
import { RoleEdit } from '../role-edit';
import { ActionGroupItem } from '../../../types';
import { fetchActionGroups } from '../../../utils/action-groups-utils';

import { render, waitFor } from '@testing-library/react';

import { act } from 'react-dom/test-utils';
import { IndexPermissionPanel } from '../index-permission-panel';
import { CLUSTER_PERMISSIONS, INDEX_PERMISSIONS } from '../../../constants';

jest.mock('../../../utils/role-detail-utils', () => ({
getRoleDetail: jest.fn().mockReturnValue({
cluster_permissions: [],
index_permissions: [],
tenant_permissions: [],
reserved: false,
}),
updateRole: jest.fn(),
}));
jest.mock('../../../utils/action-groups-utils');

jest.mock('../cluster-permission-panel', () => ({
ClusterPermissionPanel: jest.fn(() => null) as jest.Mock,
}));

jest.mock('../index-permission-panel', () => ({
IndexPermissionPanel: jest.fn(() => null) as jest.Mock,
}));

describe('Role edit filtering', () => {
const sampleSourceRole = 'role';
const mockCoreStart = {
http: 1,
};

(fetchActionGroups as jest.Mock).mockResolvedValue({
data_access: {
reserved: true,
hidden: false,
allowed_actions: ['indices:data/*', 'crud'],
type: 'index',
description: 'Allow all read/write operations on data',
static: true,
},
cluster_manage_pipelines: {
reserved: true,
hidden: false,
allowed_actions: ['cluster:admin/ingest/pipeline/*'],
type: 'cluster',
description: 'Manage pipelines',
static: true,
},
});

it('basic cluster permission panel rendering', async () => {
const action = 'create';
const buildBreadcrumbs = jest.fn();

render(
<RoleEdit
action={action}
sourceRoleName={sampleSourceRole}
buildBreadcrumbs={buildBreadcrumbs}
coreStart={mockCoreStart as any}
navigation={{} as any}
params={{} as any}
config={{} as any}
/>
);

await act(async () => {
await waitFor(() => {
expect(ClusterPermissionPanel).toHaveBeenCalled();
});
});

const lastCallArgs =
ClusterPermissionPanel.mock.calls[ClusterPermissionPanel.mock.calls.length - 1];
const [props] = lastCallArgs;

// Cluster Permission Panel props is filtered to action groups with type cluster, and only the cluster permission constants
expect(props.optionUniverse).toEqual([
{
label: 'Permission groups',
options: [
{
label: 'cluster_manage_pipelines',
},
],
},
{
label: 'Cluster permissions',
options: CLUSTER_PERMISSIONS.map((x) => {
return { label: x };
}),
},
]);
});

it('basic index permission panel rendering', async () => {
const action = 'create';
const buildBreadcrumbs = jest.fn();

render(
<RoleEdit
action={action}
sourceRoleName={sampleSourceRole}
buildBreadcrumbs={buildBreadcrumbs}
coreStart={mockCoreStart as any}
navigation={{} as any}
params={{} as any}
config={{} as any}
/>
);

await act(async () => {
await waitFor(() => {
expect(IndexPermissionPanel).toHaveBeenCalled();
});
});

const lastCallArgs =
IndexPermissionPanel.mock.calls[IndexPermissionPanel.mock.calls.length - 1];
const [props] = lastCallArgs;

// Index Permission Panel props is filtered to action groups with type index, and only the index permission constants
expect(props.optionUniverse).toEqual([
{
label: 'Permission groups',
options: [
{
label: 'data_access',
},
],
},
{
label: 'Index permissions',
options: INDEX_PERMISSIONS.map((x) => {
return { label: x };
}),
},
]);
});
});

0 comments on commit 5fd8018

Please sign in to comment.