Merge pull request #2134 from automatisch/permission-tests
Permission tests
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`Permission model > jsonSchema should have correct validations 1`] = `
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"action": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"conditions": {
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"roleId": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"roleId",
|
||||||
|
"action",
|
||||||
|
"subject",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
}
|
||||||
|
`;
|
@@ -19,25 +19,39 @@ class Permission extends Base {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static sanitize(permissions) {
|
static filter(permissions) {
|
||||||
const sanitizedPermissions = permissions.filter((permission) => {
|
const sanitizedPermissions = permissions.filter((permission) => {
|
||||||
const { action, subject, conditions } = permission;
|
const { action, subject, conditions } = permission;
|
||||||
|
|
||||||
const relevantAction = permissionCatalog.actions.find(
|
const relevantAction = this.findAction(action);
|
||||||
(actionCatalogItem) => actionCatalogItem.key === action
|
const validSubject = this.isSubjectValid(subject, relevantAction);
|
||||||
);
|
const validConditions = this.areConditionsValid(conditions);
|
||||||
const validSubject = relevantAction.subjects.includes(subject);
|
|
||||||
const validConditions = conditions.every((condition) => {
|
|
||||||
return !!permissionCatalog.conditions.find(
|
|
||||||
(conditionCatalogItem) => conditionCatalogItem.key === condition
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return validSubject && validConditions;
|
return relevantAction && validSubject && validConditions;
|
||||||
});
|
});
|
||||||
|
|
||||||
return sanitizedPermissions;
|
return sanitizedPermissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static findAction(action) {
|
||||||
|
return permissionCatalog.actions.find(
|
||||||
|
(actionCatalogItem) => actionCatalogItem.key === action
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static isSubjectValid(subject, action) {
|
||||||
|
return action && action.subjects.includes(subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
static areConditionsValid(conditions) {
|
||||||
|
return conditions.every((condition) => this.isConditionValid(condition));
|
||||||
|
}
|
||||||
|
|
||||||
|
static isConditionValid(condition) {
|
||||||
|
return !!permissionCatalog.conditions.find(
|
||||||
|
(conditionCatalogItem) => conditionCatalogItem.key === condition
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Permission;
|
export default Permission;
|
||||||
|
95
packages/backend/src/models/permission.test.js
Normal file
95
packages/backend/src/models/permission.test.js
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import Permission from './permission';
|
||||||
|
import permissionCatalog from '../helpers/permission-catalog.ee.js';
|
||||||
|
|
||||||
|
describe('Permission model', () => {
|
||||||
|
it('tableName should return correct name', () => {
|
||||||
|
expect(Permission.tableName).toBe('permissions');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('jsonSchema should have correct validations', () => {
|
||||||
|
expect(Permission.jsonSchema).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filter should return only valid permissions based on permission catalog', () => {
|
||||||
|
const permissions = [
|
||||||
|
{ action: 'read', subject: 'Flow', conditions: ['isCreator'] },
|
||||||
|
{ action: 'delete', subject: 'Connection', conditions: [] },
|
||||||
|
{ action: 'publish', subject: 'Flow', conditions: ['isCreator'] },
|
||||||
|
{ action: 'update', subject: 'Execution', conditions: [] }, // Invalid subject
|
||||||
|
{ action: 'read', subject: 'Execution', conditions: ['invalid'] }, // Invalid condition
|
||||||
|
{ action: 'invalid', subject: 'Execution', conditions: [] }, // Invalid action
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = Permission.filter(permissions);
|
||||||
|
|
||||||
|
expect(result).toStrictEqual([
|
||||||
|
{ action: 'read', subject: 'Flow', conditions: ['isCreator'] },
|
||||||
|
{ action: 'delete', subject: 'Connection', conditions: [] },
|
||||||
|
{ action: 'publish', subject: 'Flow', conditions: ['isCreator'] },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findAction', () => {
|
||||||
|
it('should return action from permission catalog', () => {
|
||||||
|
const action = Permission.findAction('create');
|
||||||
|
expect(action.key).toStrictEqual('create');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined for invalid actions', () => {
|
||||||
|
const invalidAction = Permission.findAction('invalidAction');
|
||||||
|
expect(invalidAction).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isSubjectValid', () => {
|
||||||
|
it('should return true for valid subjects', () => {
|
||||||
|
const validAction = permissionCatalog.actions.find(
|
||||||
|
(action) => action.key === 'create'
|
||||||
|
);
|
||||||
|
|
||||||
|
const validSubject = Permission.isSubjectValid('Connection', validAction);
|
||||||
|
expect(validSubject).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false for invalid subjects', () => {
|
||||||
|
const validAction = permissionCatalog.actions.find(
|
||||||
|
(action) => action.key === 'create'
|
||||||
|
);
|
||||||
|
|
||||||
|
const invalidSubject = Permission.isSubjectValid(
|
||||||
|
'Execution',
|
||||||
|
validAction
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(invalidSubject).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('areConditionsValid', () => {
|
||||||
|
it('should return true for valid conditions', () => {
|
||||||
|
const validConditions = Permission.areConditionsValid(['isCreator']);
|
||||||
|
expect(validConditions).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false for invalid conditions', () => {
|
||||||
|
const invalidConditions = Permission.areConditionsValid([
|
||||||
|
'invalidCondition',
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(invalidConditions).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isConditionValid', () => {
|
||||||
|
it('should return true for valid conditions', () => {
|
||||||
|
const validCondition = Permission.isConditionValid('isCreator');
|
||||||
|
expect(validCondition).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false for invalid conditions', () => {
|
||||||
|
const invalidCondition = Permission.isConditionValid('invalidCondition');
|
||||||
|
expect(invalidCondition).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -63,14 +63,14 @@ class Role extends Base {
|
|||||||
await this.$relatedQuery('permissions', trx).delete();
|
await this.$relatedQuery('permissions', trx).delete();
|
||||||
|
|
||||||
if (permissions?.length) {
|
if (permissions?.length) {
|
||||||
const sanitizedPermissions = Permission.sanitize(permissions).map(
|
const validPermissions = Permission.filter(permissions).map(
|
||||||
(permission) => ({
|
(permission) => ({
|
||||||
...permission,
|
...permission,
|
||||||
roleId: this.id,
|
roleId: this.id,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
await Permission.query().insert(sanitizedPermissions);
|
await Permission.query().insert(validPermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.$query(trx).patch({
|
await this.$query(trx).patch({
|
||||||
|
Reference in New Issue
Block a user