fix: role initialization

This commit is contained in:
Danny Avila 2024-09-04 00:15:36 -04:00
parent 350d709763
commit b71d773f01
No known key found for this signature in database
GPG key ID: 2DD9CC89B9B50364
3 changed files with 143 additions and 10 deletions

View file

@ -132,6 +132,7 @@ async function updateAccessPermissions(roleName, permissionsUpdate) {
/** /**
* Initialize default roles in the system. * Initialize default roles in the system.
* Creates the default roles (ADMIN, USER) if they don't exist in the database. * Creates the default roles (ADMIN, USER) if they don't exist in the database.
* Updates existing roles with new permission types if they're missing.
* *
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
@ -139,14 +140,27 @@ const initializeRoles = async function () {
const defaultRoles = [SystemRoles.ADMIN, SystemRoles.USER]; const defaultRoles = [SystemRoles.ADMIN, SystemRoles.USER];
for (const roleName of defaultRoles) { for (const roleName of defaultRoles) {
let role = await Role.findOne({ name: roleName }).select('name').lean(); let role = await Role.findOne({ name: roleName });
if (!role) { if (!role) {
// Create new role if it doesn't exist
role = new Role(roleDefaults[roleName]); role = new Role(roleDefaults[roleName]);
} else {
// Add missing permission types
let isUpdated = false;
for (const permType of Object.values(PermissionTypes)) {
if (!role[permType]) {
role[permType] = roleDefaults[roleName][permType];
isUpdated = true;
}
}
if (isUpdated) {
await role.save(); await role.save();
} }
} }
await role.save();
}
}; };
module.exports = { module.exports = {
getRoleByName, getRoleByName,
initializeRoles, initializeRoles,

View file

@ -1,9 +1,14 @@
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const { MongoMemoryServer } = require('mongodb-memory-server'); const { MongoMemoryServer } = require('mongodb-memory-server');
const { SystemRoles, PermissionTypes } = require('librechat-data-provider'); const {
const Role = require('~/models/schema/roleSchema'); SystemRoles,
const { updateAccessPermissions } = require('~/models/Role'); PermissionTypes,
roleDefaults,
Permissions,
} = require('librechat-data-provider');
const { updateAccessPermissions, initializeRoles } = require('~/models/Role');
const getLogStores = require('~/cache/getLogStores'); const getLogStores = require('~/cache/getLogStores');
const Role = require('~/models/schema/roleSchema');
// Mock the cache // Mock the cache
jest.mock('~/cache/getLogStores', () => { jest.mock('~/cache/getLogStores', () => {
@ -195,3 +200,117 @@ describe('updateAccessPermissions', () => {
}); });
}); });
}); });
describe('initializeRoles', () => {
beforeEach(async () => {
await Role.deleteMany({});
});
it('should create default roles if they do not exist', async () => {
await initializeRoles();
const adminRole = await Role.findOne({ name: SystemRoles.ADMIN }).lean();
const userRole = await Role.findOne({ name: SystemRoles.USER }).lean();
expect(adminRole).toBeTruthy();
expect(userRole).toBeTruthy();
// Check if all permission types exist
Object.values(PermissionTypes).forEach((permType) => {
expect(adminRole[permType]).toBeDefined();
expect(userRole[permType]).toBeDefined();
});
// Check if permissions match defaults (example for ADMIN role)
expect(adminRole[PermissionTypes.PROMPTS].SHARED_GLOBAL).toBe(true);
expect(adminRole[PermissionTypes.BOOKMARKS].USE).toBe(true);
expect(adminRole[PermissionTypes.AGENTS].CREATE).toBe(true);
});
it('should not modify existing permissions for existing roles', async () => {
const customUserRole = {
name: SystemRoles.USER,
[PermissionTypes.PROMPTS]: {
[Permissions.USE]: false,
[Permissions.CREATE]: true,
[Permissions.SHARED_GLOBAL]: true,
},
[PermissionTypes.BOOKMARKS]: {
[Permissions.USE]: false,
},
};
await new Role(customUserRole).save();
await initializeRoles();
const userRole = await Role.findOne({ name: SystemRoles.USER }).lean();
expect(userRole[PermissionTypes.PROMPTS]).toEqual(customUserRole[PermissionTypes.PROMPTS]);
expect(userRole[PermissionTypes.BOOKMARKS]).toEqual(customUserRole[PermissionTypes.BOOKMARKS]);
expect(userRole[PermissionTypes.AGENTS]).toBeDefined();
});
it('should add new permission types to existing roles', async () => {
const partialUserRole = {
name: SystemRoles.USER,
[PermissionTypes.PROMPTS]: roleDefaults[SystemRoles.USER][PermissionTypes.PROMPTS],
[PermissionTypes.BOOKMARKS]: roleDefaults[SystemRoles.USER][PermissionTypes.BOOKMARKS],
};
await new Role(partialUserRole).save();
await initializeRoles();
const userRole = await Role.findOne({ name: SystemRoles.USER }).lean();
expect(userRole[PermissionTypes.AGENTS]).toBeDefined();
expect(userRole[PermissionTypes.AGENTS].CREATE).toBeDefined();
expect(userRole[PermissionTypes.AGENTS].USE).toBeDefined();
expect(userRole[PermissionTypes.AGENTS].SHARED_GLOBAL).toBeDefined();
});
it('should handle multiple runs without duplicating or modifying data', async () => {
await initializeRoles();
await initializeRoles();
const adminRoles = await Role.find({ name: SystemRoles.ADMIN });
const userRoles = await Role.find({ name: SystemRoles.USER });
expect(adminRoles).toHaveLength(1);
expect(userRoles).toHaveLength(1);
const adminRole = adminRoles[0].toObject();
const userRole = userRoles[0].toObject();
// Check if all permission types exist
Object.values(PermissionTypes).forEach((permType) => {
expect(adminRole[permType]).toBeDefined();
expect(userRole[permType]).toBeDefined();
});
});
it('should update roles with missing permission types from roleDefaults', async () => {
const partialAdminRole = {
name: SystemRoles.ADMIN,
[PermissionTypes.PROMPTS]: {
[Permissions.USE]: false,
[Permissions.CREATE]: false,
[Permissions.SHARED_GLOBAL]: false,
},
[PermissionTypes.BOOKMARKS]: roleDefaults[SystemRoles.ADMIN][PermissionTypes.BOOKMARKS],
};
await new Role(partialAdminRole).save();
await initializeRoles();
const adminRole = await Role.findOne({ name: SystemRoles.ADMIN }).lean();
expect(adminRole[PermissionTypes.PROMPTS]).toEqual(partialAdminRole[PermissionTypes.PROMPTS]);
expect(adminRole[PermissionTypes.AGENTS]).toBeDefined();
expect(adminRole[PermissionTypes.AGENTS].CREATE).toBeDefined();
expect(adminRole[PermissionTypes.AGENTS].USE).toBeDefined();
expect(adminRole[PermissionTypes.AGENTS].SHARED_GLOBAL).toBeDefined();
});
});

View file

@ -46,7 +46,7 @@ export const promptPermissionsSchema = z.object({
[Permissions.SHARED_GLOBAL]: z.boolean().default(false), [Permissions.SHARED_GLOBAL]: z.boolean().default(false),
[Permissions.USE]: z.boolean().default(true), [Permissions.USE]: z.boolean().default(true),
[Permissions.CREATE]: z.boolean().default(true), [Permissions.CREATE]: z.boolean().default(true),
[Permissions.SHARE]: z.boolean().default(false), // [Permissions.SHARE]: z.boolean().default(false),
}); });
export const bookmarkPermissionsSchema = z.object({ export const bookmarkPermissionsSchema = z.object({
@ -57,7 +57,7 @@ export const agentPermissionsSchema = z.object({
[Permissions.SHARED_GLOBAL]: z.boolean().default(false), [Permissions.SHARED_GLOBAL]: z.boolean().default(false),
[Permissions.USE]: z.boolean().default(true), [Permissions.USE]: z.boolean().default(true),
[Permissions.CREATE]: z.boolean().default(true), [Permissions.CREATE]: z.boolean().default(true),
[Permissions.SHARE]: z.boolean().default(false), // [Permissions.SHARE]: z.boolean().default(false),
}); });
export const roleSchema = z.object({ export const roleSchema = z.object({
@ -79,7 +79,7 @@ const defaultRolesSchema = z.object({
[Permissions.SHARED_GLOBAL]: z.boolean().default(true), [Permissions.SHARED_GLOBAL]: z.boolean().default(true),
[Permissions.USE]: z.boolean().default(true), [Permissions.USE]: z.boolean().default(true),
[Permissions.CREATE]: z.boolean().default(true), [Permissions.CREATE]: z.boolean().default(true),
[Permissions.SHARE]: z.boolean().default(true), // [Permissions.SHARE]: z.boolean().default(true),
}), }),
[PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema.extend({ [PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema.extend({
[Permissions.USE]: z.boolean().default(true), [Permissions.USE]: z.boolean().default(true),
@ -88,7 +88,7 @@ const defaultRolesSchema = z.object({
[Permissions.SHARED_GLOBAL]: z.boolean().default(true), [Permissions.SHARED_GLOBAL]: z.boolean().default(true),
[Permissions.USE]: z.boolean().default(true), [Permissions.USE]: z.boolean().default(true),
[Permissions.CREATE]: z.boolean().default(true), [Permissions.CREATE]: z.boolean().default(true),
[Permissions.SHARE]: z.boolean().default(true), // [Permissions.SHARE]: z.boolean().default(true),
}), }),
}), }),
[SystemRoles.USER]: roleSchema.extend({ [SystemRoles.USER]: roleSchema.extend({