cypress: permission cypress part 1 (#14850)

* cypress: permission cypress part 1

* fix searchIndex spec

* added permission based cypress

---------

Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
This commit is contained in:
Shailesh Parmar 2024-01-25 18:22:45 +05:30 committed by GitHub
parent cb7db8ce8f
commit 6a1c13687e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 477 additions and 3 deletions

View File

@ -20,6 +20,7 @@ import { SidebarItem } from '../../constants/Entity.interface';
import { VISIT_SERVICE_PAGE_DETAILS } from '../../constants/service.constants';
import { GlobalSettingOptions } from '../../constants/settings.constant';
import {
checkNoPermissionPlaceholder,
permanentDeleteUser,
restoreUser,
softDeleteUser,
@ -76,6 +77,60 @@ class UsersTestClass {
cy.get('[data-testid="edit-lineage"]').should('be.disabled');
}
viewPermissions(permission?: {
viewSampleData?: boolean;
viewQueries?: boolean;
viewTests?: boolean;
editDisplayName?: boolean;
}) {
// check Add domain permission
cy.get('[data-testid="add-domain"]').should('not.be.exist');
cy.get('[data-testid="edit-displayName-button"]').should(
permission?.editDisplayName ? 'be.exist' : 'not.be.exist'
);
// check edit owner permission
cy.get('[data-testid="edit-owner"]').should('not.be.exist');
// check edit description permission
cy.get('[data-testid="edit-description"]').should('not.be.exist');
// check edit tier permission
cy.get('[data-testid="edit-tier"]').should('not.be.exist');
// check add tags button
cy.get(
':nth-child(2) > [data-testid="tags-container"] > [data-testid="entity-tags"] > .m-t-xss > .ant-tag'
).should('not.be.exist');
// check add glossary term button
cy.get(
':nth-child(3) > [data-testid="glossary-container"] > [data-testid="entity-tags"] > .m-t-xss > .ant-tag'
).should('not.be.exist');
// check edit tier permission
cy.get('[data-testid="manage-button"]').should(
permission?.editDisplayName ? 'be.visible' : 'not.be.exist'
);
if (permission?.editDisplayName) {
interceptURL('PATCH', '/api/v1/tables/*', 'updateName');
cy.get('[data-testid="manage-button"]').click();
cy.get('[data-testid="rename-button"]').click();
cy.get('#displayName').clear().type('updated-table-name');
cy.get('[data-testid="save-button"]').click();
verifyResponseStatusCode('@updateName', 200);
cy.get('[data-testid="entity-header-display-name').should(
'contain',
'updated-table-name'
);
}
cy.get('[data-testid="sample_data"]').click();
checkNoPermissionPlaceholder(permission?.viewSampleData);
cy.get('[data-testid="table_queries"]').click();
checkNoPermissionPlaceholder(permission?.viewQueries);
cy.get('[data-testid="profiler"]').click();
checkNoPermissionPlaceholder(permission?.viewTests);
cy.get('[data-testid="lineage"]').click();
cy.get('[data-testid="edit-lineage"]').should('be.disabled');
cy.get('[data-testid="custom_properties"]').click();
checkNoPermissionPlaceholder();
}
checkStewardServicesPermissions() {
cy.sidebarClick(SidebarItem.EXPLORE);
Object.values(VISIT_SERVICE_PAGE_DETAILS).forEach((service) => {

View File

@ -375,3 +375,15 @@ export const editRole = (username: string, role: string) => {
cy.get('.ant-collapse-expand-icon > .anticon > svg').scrollIntoView();
cy.get(`[data-testid=chip-container]`).should('contain', role);
};
export const checkNoPermissionPlaceholder = (permission = false) => {
cy.get('[data-testid="permission-error-placeholder"]').should(
permission ? 'not.exist' : 'be.visible'
);
if (!permission) {
cy.get('[data-testid="permission-error-placeholder"]').should(
'contain',
'You dont have access, please check with the admin to get permissions'
);
}
};

View File

@ -0,0 +1,409 @@
/*
* Copyright 2024 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 {
interceptURL,
login,
uuid,
verifyResponseStatusCode,
} from '../../common/common';
import UsersTestClass from '../../common/Entities/UserClass';
import { hardDeleteService } from '../../common/EntityUtils';
import {
createEntityTableViaREST,
visitEntityDetailsPage,
} from '../../common/Utils/Entity';
import { EntityType } from '../../constants/Entity.interface';
import { DATABASE_SERVICE, USER_DETAILS } from '../../constants/EntityConstant';
import { SERVICE_CATEGORIES } from '../../constants/service.constants';
type RoleType = {
name: string;
policies: string[];
id?: string;
};
type PolicyType = {
name: string;
rules: {
name: string;
resources: string[];
operations: string[];
effect: string;
}[];
id?: string;
};
type OrganizationTeamType = {
id: string;
policies: {
id: string;
type: string;
}[];
defaultRoles: {
id: string;
type: string;
}[];
};
const entity = new UsersTestClass();
const policy: PolicyType = {
name: `cy-permission-policy-${uuid()}`,
rules: [
{
name: `cy-permission-rule-${uuid()}`,
resources: ['All'],
operations: ['ViewBasic'],
effect: 'allow',
},
],
};
const role: RoleType = {
name: `cy-permission-role-${uuid()}`,
policies: [policy.name],
};
const tableFqn = `${DATABASE_SERVICE.entity.databaseSchema}.${DATABASE_SERVICE.entity.name}`;
const testSuite = {
name: `${tableFqn}.testSuite`,
executableEntityReference: tableFqn,
};
const testCase = {
name: `user_tokens_table_column_name_to_exist_${uuid()}`,
entityLink: `<#E::table::${testSuite.executableEntityReference}>`,
parameterValues: [{ name: 'columnName', value: 'id' }],
testDefinition: 'tableColumnNameToExist',
description: 'test case description',
testSuite: testSuite.name,
};
let organizationTeam = {} as OrganizationTeamType;
let userId = '';
const viewPermissions = [
{
title: 'ViewBasic, ViewSampleData & ViewQueries permission',
data: {
patch: [
{ op: 'add', path: '/rules/0/operations/1', value: 'ViewSampleData' },
{ op: 'add', path: '/rules/0/operations/2', value: 'ViewQueries' },
],
permission: { viewSampleData: true, viewQueries: true },
},
},
{
title: 'ViewBasic, ViewSampleData, ViewQueries & ViewTests permission',
data: {
patch: [{ op: 'add', path: '/rules/0/operations/3', value: 'ViewTests' }],
permission: {
viewSampleData: true,
viewQueries: true,
viewTests: true,
},
},
},
{
title: 'EditDisplayName permission',
data: {
patch: [
{ op: 'add', path: '/rules/0/operations/4', value: 'EditDisplayName' },
],
permission: {
viewSampleData: true,
viewQueries: true,
viewTests: true,
editDisplayName: true,
},
},
},
];
const createViewBasicRoleViaREST = ({ token }) => {
cy.request({
method: 'POST',
url: `/api/v1/policies`,
headers: { Authorization: `Bearer ${token}` },
body: policy,
}).then((response) => {
policy.id = response.body.id;
cy.request({
method: 'POST',
url: `/api/v1/roles`,
headers: { Authorization: `Bearer ${token}` },
body: role,
}).then((roleResponse) => {
role.id = roleResponse.body.id;
cy.request({
method: 'GET',
url: `/api/v1/teams/name/Organization?fields=defaultRoles,policies`,
headers: { Authorization: `Bearer ${token}` },
}).then((orgResponse) => {
organizationTeam = orgResponse.body;
cy.request({
method: 'PATCH',
url: `/api/v1/teams/${orgResponse.body.id}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json-patch+json',
},
body: [
{
op: 'replace',
path: '/policies/0',
value: {
id: response.body.id,
type: 'policy',
},
},
{
op: 'replace',
path: '/defaultRoles/0',
value: {
id: roleResponse.body.id,
type: 'role',
},
},
],
});
});
});
});
};
const preRequisite = () => {
cy.login();
cy.getAllLocalStorage().then((data) => {
const token = Object.values(data)[0].oidcIdToken;
createViewBasicRoleViaREST({
token,
});
cy.request({
method: 'POST',
url: `/api/v1/users/signup`,
headers: { Authorization: `Bearer ${token}` },
body: USER_DETAILS,
}).then((response) => {
userId = response.body.id;
});
createEntityTableViaREST({
token,
...DATABASE_SERVICE,
tables: [],
});
cy.request({
method: 'POST',
url: `/api/v1/tables`,
headers: { Authorization: `Bearer ${token}` },
body: DATABASE_SERVICE.entity,
}).then((response) => {
cy.request({
method: 'POST',
url: `/api/v1/queries`,
headers: { Authorization: `Bearer ${token}` },
body: {
query: `select * from dim_address_${uuid()}`,
queryUsedIn: [{ id: response.body.id, type: 'table' }],
queryDate: Date.now(),
service: 'sample_data',
},
});
cy.request({
method: 'POST',
url: `/api/v1/dataQuality/testSuites/executable`,
headers: { Authorization: `Bearer ${token}` },
body: testSuite,
}).then(() => {
cy.request({
method: 'POST',
url: `/api/v1/dataQuality/testCases`,
headers: { Authorization: `Bearer ${token}` },
body: testCase,
});
});
});
});
cy.logout();
};
const cleanUp = () => {
cy.login();
cy.getAllLocalStorage().then((data) => {
const token = Object.values(data)[0].oidcIdToken;
hardDeleteService({
token,
serviceFqn: DATABASE_SERVICE.service.name,
serviceType: SERVICE_CATEGORIES.DATABASE_SERVICES,
});
cy.request({
method: 'DELETE',
url: `/api/v1/roles/${role.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
cy.request({
method: 'DELETE',
url: `/api/v1/policies/${policy.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
cy.request({
method: 'PATCH',
url: `/api/v1/teams/${organizationTeam.id}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json-patch+json',
},
body: [
{
op: 'add',
path: '/policies/0',
value: {
id: organizationTeam.policies[0].id,
type: 'policy',
},
},
{
op: 'add',
path: '/defaultRoles/0',
value: {
id: organizationTeam.defaultRoles[0].id,
type: 'role',
},
},
],
});
// Delete created user
cy.request({
method: 'DELETE',
url: `/api/v1/users/${userId}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
});
};
const checkPermission = (permission?: {
viewSampleData?: boolean;
viewQueries?: boolean;
viewTests?: boolean;
editDisplayName?: boolean;
}) => {
login(USER_DETAILS.email, USER_DETAILS.password);
visitEntityDetailsPage({
term: DATABASE_SERVICE.entity.name,
serviceName: DATABASE_SERVICE.service.name,
entity: EntityType.Table,
});
entity.viewPermissions(permission);
cy.logout();
};
const updatePolicy = (
patch: { op: string; path: string; value: unknown }[]
) => {
cy.login();
cy.getAllLocalStorage().then((data) => {
const token = Object.values(data)[0].oidcIdToken;
cy.request({
method: 'PATCH',
url: `/api/v1/policies/${policy.id}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json-patch+json',
},
body: patch,
});
});
cy.logout();
cy.reload();
};
describe('Permissions', () => {
before(preRequisite);
after(cleanUp);
it('ViewBasic permission', () => {
checkPermission();
});
viewPermissions.forEach((permissionData) => {
it(`check ${permissionData.title}`, () => {
updatePolicy(permissionData.data.patch);
checkPermission(permissionData.data.permission);
});
});
it('EditQuery permission', () => {
updatePolicy([
{
op: 'add',
path: '/rules/1',
value: {
name: `cy-edit-query-rule-${uuid()}`,
resources: ['query'],
operations: ['ViewAll', 'EditAll'],
effect: 'allow',
},
},
{ op: 'add', path: '/rules/0/operations/5', value: 'EditQueries' },
]);
login(USER_DETAILS.email, USER_DETAILS.password);
visitEntityDetailsPage({
term: DATABASE_SERVICE.entity.name,
serviceName: DATABASE_SERVICE.service.name,
entity: EntityType.Table,
});
interceptURL('GET', '/api/v1/queries?*', 'getQueries');
cy.get('[data-testid="table_queries"]').click();
verifyResponseStatusCode('@getQueries', 200);
cy.get('[data-testid="more-option-btn"]').click();
cy.get('[data-menu-id*="edit-query"]').click();
interceptURL('PATCH', '/api/v1/queries/*', 'updateQuery');
cy.get('.CodeMirror-line').click().type('updated');
cy.get('[data-testid="save-query-btn"]').click();
verifyResponseStatusCode('@updateQuery', 200);
cy.logout();
});
it('EditTest permission', () => {
updatePolicy([
{ op: 'add', path: '/rules/1/operations/6', value: 'EditTests' },
{
op: 'add',
path: '/rules/2',
value: {
name: `cy-edit-test-case-rule-${uuid()}`,
resources: ['testCase'],
operations: ['ViewAll', 'EditAll'],
effect: 'allow',
},
},
]);
login(USER_DETAILS.email, USER_DETAILS.password);
visitEntityDetailsPage({
term: DATABASE_SERVICE.entity.name,
serviceName: DATABASE_SERVICE.service.name,
entity: EntityType.Table,
});
interceptURL('GET', '/api/v1/dataQuality/testCases?fields=*', 'testCase');
cy.get('[data-testid="profiler"]').click();
cy.get('[data-testid="profiler-tab-left-panel"]')
.contains('Data Quality')
.click();
verifyResponseStatusCode('@testCase', 200);
cy.get(`[data-testid="edit-${testCase.name}"]`).click();
cy.get('#tableTestForm_params_columnName')
.scrollIntoView()
.clear()
.type('test');
interceptURL('PATCH', '/api/v1/dataQuality/testCases/*', 'updateTest');
cy.get('.ant-modal-footer').contains('Submit').click();
verifyResponseStatusCode('@updateTest', 200);
});
});

View File

@ -206,9 +206,7 @@ describe('Prerequisite for data steward role tests', () => {
interceptURL('GET', `/api/v1/users/name/${USER_NAME}*`, 'getUserDetails');
cy.get(
`[data-row-key="${USER_CREDENTIALS.id}"] [data-testid="${USER_NAME}"]`
).click();
cy.get(`[data-testid="${USER_NAME}"]`).click();
verifyResponseStatusCode('@getUserDetails', 200);