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 NameExistsError from '../error/name-exists-error';
|
||||||
import { IEnvironmentStore } from 'lib/types/stores/environment-store';
|
import { IEnvironmentStore } from 'lib/types/stores/environment-store';
|
||||||
import RoleInUseError from '../error/role-in-use-error';
|
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_PROJECTS = '*';
|
||||||
export const ALL_ENVS = '*';
|
export const ALL_ENVS = '*';
|
||||||
@ -386,12 +388,11 @@ export class AccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async createRole(role: IRoleCreation): Promise<ICustomRole> {
|
async createRole(role: IRoleCreation): Promise<ICustomRole> {
|
||||||
await this.validateRole(role);
|
|
||||||
const baseRole = {
|
const baseRole = {
|
||||||
name: role.name,
|
...(await this.validateRole(role)),
|
||||||
description: role.description,
|
roleType: CUSTOM_ROLE_TYPE,
|
||||||
roleType: 'custom',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const rolePermissions = role.permissions;
|
const rolePermissions = role.permissions;
|
||||||
const newRole = await this.roleStore.create(baseRole);
|
const newRole = await this.roleStore.create(baseRole);
|
||||||
if (rolePermissions) {
|
if (rolePermissions) {
|
||||||
@ -451,8 +452,9 @@ export class AccessService {
|
|||||||
async validateRole(
|
async validateRole(
|
||||||
role: IRoleCreation,
|
role: IRoleCreation,
|
||||||
existingId?: number,
|
existingId?: number,
|
||||||
): Promise<void> {
|
): Promise<IRoleCreation> {
|
||||||
|
const cleanedRole = await roleSchema.validateAsync(role);
|
||||||
await this.validateRoleIsUnique(role.name, existingId);
|
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 ROOT_PERMISSION_TYPE = 'root';
|
||||||
export const ENVIRONMENT_PERMISSION_TYPE = 'environment';
|
export const ENVIRONMENT_PERMISSION_TYPE = 'environment';
|
||||||
export const PROJECT_PERMISSION_TYPE = 'project';
|
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,
|
p.id as permission_id,
|
||||||
'*' environment
|
'*' environment
|
||||||
FROM permissions p
|
FROM permissions p
|
||||||
WHERE p.permission = 'ADMIN'
|
WHERE p.permission = 'ADMIN';
|
||||||
`,
|
`,
|
||||||
cb,
|
cb,
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user