| const mongoose = require('mongoose'); |
| const { MongoMemoryServer } = require('mongodb-memory-server'); |
| const { |
| SystemRoles, |
| Permissions, |
| roleDefaults, |
| PermissionTypes, |
| } = require('librechat-data-provider'); |
| const { getRoleByName, updateAccessPermissions } = require('~/models/Role'); |
| const getLogStores = require('~/cache/getLogStores'); |
| const { initializeRoles } = require('~/models'); |
| const { Role } = require('~/db/models'); |
|
|
| |
| jest.mock('~/cache/getLogStores', () => |
| jest.fn().mockReturnValue({ |
| get: jest.fn(), |
| set: jest.fn(), |
| del: jest.fn(), |
| }), |
| ); |
|
|
| let mongoServer; |
|
|
| beforeAll(async () => { |
| mongoServer = await MongoMemoryServer.create(); |
| const mongoUri = mongoServer.getUri(); |
| await mongoose.connect(mongoUri); |
| }); |
|
|
| afterAll(async () => { |
| await mongoose.disconnect(); |
| await mongoServer.stop(); |
| }); |
|
|
| beforeEach(async () => { |
| await Role.deleteMany({}); |
| getLogStores.mockClear(); |
| }); |
|
|
| describe('updateAccessPermissions', () => { |
| it('should update permissions when changes are needed', async () => { |
| await new Role({ |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.PROMPTS]: { |
| CREATE: true, |
| USE: true, |
| SHARED_GLOBAL: false, |
| }, |
| }, |
| }).save(); |
|
|
| await updateAccessPermissions(SystemRoles.USER, { |
| [PermissionTypes.PROMPTS]: { |
| CREATE: true, |
| USE: true, |
| SHARED_GLOBAL: true, |
| }, |
| }); |
|
|
| const updatedRole = await getRoleByName(SystemRoles.USER); |
| expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({ |
| CREATE: true, |
| USE: true, |
| SHARED_GLOBAL: true, |
| }); |
| }); |
|
|
| it('should not update permissions when no changes are needed', async () => { |
| await new Role({ |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.PROMPTS]: { |
| CREATE: true, |
| USE: true, |
| SHARED_GLOBAL: false, |
| }, |
| }, |
| }).save(); |
|
|
| await updateAccessPermissions(SystemRoles.USER, { |
| [PermissionTypes.PROMPTS]: { |
| CREATE: true, |
| USE: true, |
| SHARED_GLOBAL: false, |
| }, |
| }); |
|
|
| const updatedRole = await getRoleByName(SystemRoles.USER); |
| expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({ |
| CREATE: true, |
| USE: true, |
| SHARED_GLOBAL: false, |
| }); |
| }); |
|
|
| it('should handle non-existent roles', async () => { |
| await updateAccessPermissions('NON_EXISTENT_ROLE', { |
| [PermissionTypes.PROMPTS]: { CREATE: true }, |
| }); |
| const role = await Role.findOne({ name: 'NON_EXISTENT_ROLE' }); |
| expect(role).toBeNull(); |
| }); |
|
|
| it('should update only specified permissions', async () => { |
| await new Role({ |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.PROMPTS]: { |
| CREATE: true, |
| USE: true, |
| SHARED_GLOBAL: false, |
| }, |
| }, |
| }).save(); |
|
|
| await updateAccessPermissions(SystemRoles.USER, { |
| [PermissionTypes.PROMPTS]: { SHARED_GLOBAL: true }, |
| }); |
|
|
| const updatedRole = await getRoleByName(SystemRoles.USER); |
| expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({ |
| CREATE: true, |
| USE: true, |
| SHARED_GLOBAL: true, |
| }); |
| }); |
|
|
| it('should handle partial updates', async () => { |
| await new Role({ |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.PROMPTS]: { |
| CREATE: true, |
| USE: true, |
| SHARED_GLOBAL: false, |
| }, |
| }, |
| }).save(); |
|
|
| await updateAccessPermissions(SystemRoles.USER, { |
| [PermissionTypes.PROMPTS]: { USE: false }, |
| }); |
|
|
| const updatedRole = await getRoleByName(SystemRoles.USER); |
| expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({ |
| CREATE: true, |
| USE: false, |
| SHARED_GLOBAL: false, |
| }); |
| }); |
|
|
| it('should update multiple permission types at once', async () => { |
| await new Role({ |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.PROMPTS]: { CREATE: true, USE: true, SHARED_GLOBAL: false }, |
| [PermissionTypes.BOOKMARKS]: { USE: true }, |
| }, |
| }).save(); |
|
|
| await updateAccessPermissions(SystemRoles.USER, { |
| [PermissionTypes.PROMPTS]: { USE: false, SHARED_GLOBAL: true }, |
| [PermissionTypes.BOOKMARKS]: { USE: false }, |
| }); |
|
|
| const updatedRole = await getRoleByName(SystemRoles.USER); |
| expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({ |
| CREATE: true, |
| USE: false, |
| SHARED_GLOBAL: true, |
| }); |
| expect(updatedRole.permissions[PermissionTypes.BOOKMARKS]).toEqual({ USE: false }); |
| }); |
|
|
| it('should handle updates for a single permission type', async () => { |
| await new Role({ |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.PROMPTS]: { CREATE: true, USE: true, SHARED_GLOBAL: false }, |
| }, |
| }).save(); |
|
|
| await updateAccessPermissions(SystemRoles.USER, { |
| [PermissionTypes.PROMPTS]: { USE: false, SHARED_GLOBAL: true }, |
| }); |
|
|
| const updatedRole = await getRoleByName(SystemRoles.USER); |
| expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({ |
| CREATE: true, |
| USE: false, |
| SHARED_GLOBAL: true, |
| }); |
| }); |
|
|
| it('should update MULTI_CONVO permissions', async () => { |
| await new Role({ |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.MULTI_CONVO]: { USE: false }, |
| }, |
| }).save(); |
|
|
| await updateAccessPermissions(SystemRoles.USER, { |
| [PermissionTypes.MULTI_CONVO]: { USE: true }, |
| }); |
|
|
| const updatedRole = await getRoleByName(SystemRoles.USER); |
| expect(updatedRole.permissions[PermissionTypes.MULTI_CONVO]).toEqual({ USE: true }); |
| }); |
|
|
| it('should update MULTI_CONVO permissions along with other permission types', async () => { |
| await new Role({ |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.PROMPTS]: { CREATE: true, USE: true, SHARED_GLOBAL: false }, |
| [PermissionTypes.MULTI_CONVO]: { USE: false }, |
| }, |
| }).save(); |
|
|
| await updateAccessPermissions(SystemRoles.USER, { |
| [PermissionTypes.PROMPTS]: { SHARED_GLOBAL: true }, |
| [PermissionTypes.MULTI_CONVO]: { USE: true }, |
| }); |
|
|
| const updatedRole = await getRoleByName(SystemRoles.USER); |
| expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({ |
| CREATE: true, |
| USE: true, |
| SHARED_GLOBAL: true, |
| }); |
| expect(updatedRole.permissions[PermissionTypes.MULTI_CONVO]).toEqual({ USE: true }); |
| }); |
|
|
| it('should not update MULTI_CONVO permissions when no changes are needed', async () => { |
| await new Role({ |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.MULTI_CONVO]: { USE: true }, |
| }, |
| }).save(); |
|
|
| await updateAccessPermissions(SystemRoles.USER, { |
| [PermissionTypes.MULTI_CONVO]: { USE: true }, |
| }); |
|
|
| const updatedRole = await getRoleByName(SystemRoles.USER); |
| expect(updatedRole.permissions[PermissionTypes.MULTI_CONVO]).toEqual({ USE: true }); |
| }); |
| }); |
|
|
| describe('initializeRoles', () => { |
| beforeEach(async () => { |
| await Role.deleteMany({}); |
| }); |
|
|
| it('should create default roles if they do not exist', async () => { |
| await initializeRoles(); |
|
|
| const adminRole = await getRoleByName(SystemRoles.ADMIN); |
| const userRole = await getRoleByName(SystemRoles.USER); |
|
|
| expect(adminRole).toBeTruthy(); |
| expect(userRole).toBeTruthy(); |
|
|
| |
| Object.values(PermissionTypes).forEach((permType) => { |
| expect(adminRole.permissions[permType]).toBeDefined(); |
| expect(userRole.permissions[permType]).toBeDefined(); |
| }); |
|
|
| |
| expect(adminRole.permissions[PermissionTypes.PROMPTS].SHARED_GLOBAL).toBe(true); |
| expect(adminRole.permissions[PermissionTypes.BOOKMARKS].USE).toBe(true); |
| expect(adminRole.permissions[PermissionTypes.AGENTS].CREATE).toBe(true); |
| }); |
|
|
| it('should not modify existing permissions for existing roles', async () => { |
| const customUserRole = { |
| name: SystemRoles.USER, |
| permissions: { |
| [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 getRoleByName(SystemRoles.USER); |
| expect(userRole.permissions[PermissionTypes.PROMPTS]).toEqual( |
| customUserRole.permissions[PermissionTypes.PROMPTS], |
| ); |
| expect(userRole.permissions[PermissionTypes.BOOKMARKS]).toEqual( |
| customUserRole.permissions[PermissionTypes.BOOKMARKS], |
| ); |
| expect(userRole.permissions[PermissionTypes.AGENTS]).toBeDefined(); |
| }); |
|
|
| it('should add new permission types to existing roles', async () => { |
| const partialUserRole = { |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.PROMPTS]: |
| roleDefaults[SystemRoles.USER].permissions[PermissionTypes.PROMPTS], |
| [PermissionTypes.BOOKMARKS]: |
| roleDefaults[SystemRoles.USER].permissions[PermissionTypes.BOOKMARKS], |
| }, |
| }; |
|
|
| await new Role(partialUserRole).save(); |
| await initializeRoles(); |
|
|
| const userRole = await getRoleByName(SystemRoles.USER); |
| expect(userRole.permissions[PermissionTypes.AGENTS]).toBeDefined(); |
| expect(userRole.permissions[PermissionTypes.AGENTS].CREATE).toBeDefined(); |
| expect(userRole.permissions[PermissionTypes.AGENTS].USE).toBeDefined(); |
| expect(userRole.permissions[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 adminPerms = adminRoles[0].toObject().permissions; |
| const userPerms = userRoles[0].toObject().permissions; |
| Object.values(PermissionTypes).forEach((permType) => { |
| expect(adminPerms[permType]).toBeDefined(); |
| expect(userPerms[permType]).toBeDefined(); |
| }); |
| }); |
|
|
| it('should update roles with missing permission types from roleDefaults', async () => { |
| const partialAdminRole = { |
| name: SystemRoles.ADMIN, |
| permissions: { |
| [PermissionTypes.PROMPTS]: { |
| [Permissions.USE]: false, |
| [Permissions.CREATE]: false, |
| [Permissions.SHARED_GLOBAL]: false, |
| }, |
| [PermissionTypes.BOOKMARKS]: |
| roleDefaults[SystemRoles.ADMIN].permissions[PermissionTypes.BOOKMARKS], |
| }, |
| }; |
|
|
| await new Role(partialAdminRole).save(); |
| await initializeRoles(); |
|
|
| const adminRole = await getRoleByName(SystemRoles.ADMIN); |
| expect(adminRole.permissions[PermissionTypes.PROMPTS]).toEqual( |
| partialAdminRole.permissions[PermissionTypes.PROMPTS], |
| ); |
| expect(adminRole.permissions[PermissionTypes.AGENTS]).toBeDefined(); |
| expect(adminRole.permissions[PermissionTypes.AGENTS].CREATE).toBeDefined(); |
| expect(adminRole.permissions[PermissionTypes.AGENTS].USE).toBeDefined(); |
| expect(adminRole.permissions[PermissionTypes.AGENTS].SHARED_GLOBAL).toBeDefined(); |
| }); |
|
|
| it('should include MULTI_CONVO permissions when creating default roles', async () => { |
| await initializeRoles(); |
|
|
| const adminRole = await getRoleByName(SystemRoles.ADMIN); |
| const userRole = await getRoleByName(SystemRoles.USER); |
|
|
| expect(adminRole.permissions[PermissionTypes.MULTI_CONVO]).toBeDefined(); |
| expect(userRole.permissions[PermissionTypes.MULTI_CONVO]).toBeDefined(); |
| expect(adminRole.permissions[PermissionTypes.MULTI_CONVO].USE).toBe( |
| roleDefaults[SystemRoles.ADMIN].permissions[PermissionTypes.MULTI_CONVO].USE, |
| ); |
| expect(userRole.permissions[PermissionTypes.MULTI_CONVO].USE).toBe( |
| roleDefaults[SystemRoles.USER].permissions[PermissionTypes.MULTI_CONVO].USE, |
| ); |
| }); |
|
|
| it('should add MULTI_CONVO permissions to existing roles without them', async () => { |
| const partialUserRole = { |
| name: SystemRoles.USER, |
| permissions: { |
| [PermissionTypes.PROMPTS]: |
| roleDefaults[SystemRoles.USER].permissions[PermissionTypes.PROMPTS], |
| [PermissionTypes.BOOKMARKS]: |
| roleDefaults[SystemRoles.USER].permissions[PermissionTypes.BOOKMARKS], |
| }, |
| }; |
|
|
| await new Role(partialUserRole).save(); |
| await initializeRoles(); |
|
|
| const userRole = await getRoleByName(SystemRoles.USER); |
| expect(userRole.permissions[PermissionTypes.MULTI_CONVO]).toBeDefined(); |
| expect(userRole.permissions[PermissionTypes.MULTI_CONVO].USE).toBeDefined(); |
| }); |
| }); |
|
|