mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-05 17:53:12 +02:00
feat: Schema validation for roles
This commit is contained in:
parent
5abe99f431
commit
95b50acdd8
83
src/lib/schema/role-schema.test.ts
Normal file
83
src/lib/schema/role-schema.test.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { roleSchema } from './role-schema';
|
||||
|
||||
test('role schema rejects a role without a name', async () => {
|
||||
expect.assertions(1);
|
||||
const role = {
|
||||
permissions: [],
|
||||
};
|
||||
|
||||
try {
|
||||
await roleSchema.validateAsync(role);
|
||||
} catch (error) {
|
||||
expect(error.details[0].message).toBe('"name" is required');
|
||||
}
|
||||
});
|
||||
|
||||
test('role schema allows a role with an empty description', async () => {
|
||||
const role = {
|
||||
name: 'Brønsted',
|
||||
description: '',
|
||||
};
|
||||
|
||||
const value = await roleSchema.validateAsync(role);
|
||||
expect(value.description).toEqual('');
|
||||
});
|
||||
|
||||
test('role schema rejects a role with a broken permission list', async () => {
|
||||
expect.assertions(1);
|
||||
const role = {
|
||||
name: 'Mendeleev',
|
||||
permissions: [
|
||||
{
|
||||
aPropertyThatIsAproposToNothing: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
try {
|
||||
await roleSchema.validateAsync(role);
|
||||
} catch (error) {
|
||||
expect(error.details[0].message).toBe(
|
||||
'"permissions[0].id" is required',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('role schema allows a role with an empty permission list', async () => {
|
||||
const role = {
|
||||
name: 'Avogadro',
|
||||
permissions: [],
|
||||
};
|
||||
|
||||
const value = await roleSchema.validateAsync(role);
|
||||
expect(value.permissions).toEqual([]);
|
||||
});
|
||||
|
||||
test('role schema allows a role with a null list', async () => {
|
||||
const role = {
|
||||
name: 'Curie',
|
||||
permissions: null,
|
||||
};
|
||||
|
||||
const value = await roleSchema.validateAsync(role);
|
||||
expect(value.permissions).toEqual(null);
|
||||
});
|
||||
|
||||
test('role schema allows an undefined with a null list', async () => {
|
||||
const role = {
|
||||
name: 'Fischer',
|
||||
};
|
||||
|
||||
const value = await roleSchema.validateAsync(role);
|
||||
expect(value.permissions).toEqual(undefined);
|
||||
});
|
||||
|
||||
test('role schema strips roleType if present', async () => {
|
||||
const role = {
|
||||
name: 'Grignard',
|
||||
roleType: 'Organic Chemistry',
|
||||
};
|
||||
|
||||
const value = await roleSchema.validateAsync(role);
|
||||
expect(value.roleType).toEqual(undefined);
|
||||
});
|
22
src/lib/schema/role-schema.ts
Normal file
22
src/lib/schema/role-schema.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import joi from 'joi';
|
||||
|
||||
export const permissionRoleSchema = joi
|
||||
.object()
|
||||
.keys({
|
||||
id: joi.number().required(),
|
||||
enivronment: joi.string().allow(null).optional(),
|
||||
})
|
||||
.options({ stripUnknown: true, allowUnknown: false, abortEarly: false });
|
||||
|
||||
export const roleSchema = joi
|
||||
.object()
|
||||
.keys({
|
||||
name: joi.string().required(),
|
||||
description: joi.string().optional().allow('').allow(null).default(''),
|
||||
permissions: joi
|
||||
.array()
|
||||
.allow(null)
|
||||
.optional()
|
||||
.items(permissionRoleSchema),
|
||||
})
|
||||
.options({ stripUnknown: true, allowUnknown: false, abortEarly: false });
|
@ -23,6 +23,8 @@ import { IRoleStore } from 'lib/types/stores/role-store';
|
||||
import NameExistsError from '../error/name-exists-error';
|
||||
import { IEnvironmentStore } from 'lib/types/stores/environment-store';
|
||||
import RoleInUseError from '../error/role-in-use-error';
|
||||
import { roleSchema } from '../schema/role-schema';
|
||||
import { CUSTOM_ROLE_TYPE } from '../util/constants';
|
||||
|
||||
export const ALL_PROJECTS = '*';
|
||||
export const ALL_ENVS = '*';
|
||||
@ -386,12 +388,11 @@ export class AccessService {
|
||||
}
|
||||
|
||||
async createRole(role: IRoleCreation): Promise<ICustomRole> {
|
||||
await this.validateRole(role);
|
||||
const baseRole = {
|
||||
name: role.name,
|
||||
description: role.description,
|
||||
roleType: 'custom',
|
||||
...(await this.validateRole(role)),
|
||||
roleType: CUSTOM_ROLE_TYPE,
|
||||
};
|
||||
|
||||
const rolePermissions = role.permissions;
|
||||
const newRole = await this.roleStore.create(baseRole);
|
||||
if (rolePermissions) {
|
||||
@ -451,8 +452,9 @@ export class AccessService {
|
||||
async validateRole(
|
||||
role: IRoleCreation,
|
||||
existingId?: number,
|
||||
): Promise<void> {
|
||||
): Promise<IRoleCreation> {
|
||||
const cleanedRole = await roleSchema.validateAsync(role);
|
||||
await this.validateRoleIsUnique(role.name, existingId);
|
||||
//Handle schema validation here...
|
||||
return cleanedRole;
|
||||
}
|
||||
}
|
||||
|
@ -3,3 +3,5 @@ export const DEFAULT_ENV = 'default';
|
||||
export const ROOT_PERMISSION_TYPE = 'root';
|
||||
export const ENVIRONMENT_PERMISSION_TYPE = 'environment';
|
||||
export const PROJECT_PERMISSION_TYPE = 'project';
|
||||
|
||||
export const CUSTOM_ROLE_TYPE = 'custom';
|
||||
|
@ -167,7 +167,7 @@ exports.up = function (db, cb) {
|
||||
p.id as permission_id,
|
||||
'*' environment
|
||||
FROM permissions p
|
||||
WHERE p.permission = 'ADMIN'
|
||||
WHERE p.permission = 'ADMIN';
|
||||
`,
|
||||
cb,
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user