mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-10-10 08:04:10 +00:00
🪪 fix: Filter ACL Principal Details (#13524)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
* fix: filter ACL principal details * test: type ACL permission pipeline assertions * test: add ACL permissions e2e coverage
This commit is contained in:
parent
da5876331e
commit
c374d08b64
7 changed files with 694 additions and 13 deletions
|
|
@ -1,12 +1,16 @@
|
|||
const mongoose = require('mongoose');
|
||||
|
||||
const mockLogger = { error: jest.fn(), warn: jest.fn(), info: jest.fn(), debug: jest.fn() };
|
||||
const mockGetTenantId = jest.fn();
|
||||
|
||||
jest.mock('@librechat/data-schemas', () => ({
|
||||
logger: mockLogger,
|
||||
getTenantId: mockGetTenantId,
|
||||
SYSTEM_TENANT_ID: '__SYSTEM__',
|
||||
}));
|
||||
|
||||
const { ResourceType, PrincipalType } = jest.requireActual('librechat-data-provider');
|
||||
const { AccessRoleIds, ResourceType, PrincipalType } =
|
||||
jest.requireActual('librechat-data-provider');
|
||||
|
||||
jest.mock('librechat-data-provider', () => ({
|
||||
...jest.requireActual('librechat-data-provider'),
|
||||
|
|
@ -32,6 +36,7 @@ jest.mock('~/server/services/PermissionService', () => ({
|
|||
const mockRemoveAgentFromUserFavorites = jest.fn();
|
||||
|
||||
jest.mock('~/models', () => ({
|
||||
aggregateAclEntries: jest.fn(),
|
||||
searchPrincipals: jest.fn(),
|
||||
sortPrincipalsByRelevance: jest.fn(),
|
||||
calculateRelevanceScore: jest.fn(),
|
||||
|
|
@ -44,7 +49,11 @@ jest.mock('~/server/services/GraphApiService', () => ({
|
|||
}));
|
||||
|
||||
const db = require('~/models');
|
||||
const { updateResourcePermissions, searchPrincipals } = require('../PermissionsController');
|
||||
const {
|
||||
updateResourcePermissions,
|
||||
searchPrincipals,
|
||||
getResourcePermissions,
|
||||
} = require('../PermissionsController');
|
||||
|
||||
const createMockReq = (overrides = {}) => ({
|
||||
params: { resourceType: ResourceType.AGENT, resourceId: '507f1f77bcf86cd799439011' },
|
||||
|
|
@ -66,6 +75,7 @@ const flushPromises = () => new Promise((resolve) => setImmediate(resolve));
|
|||
describe('PermissionsController', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockGetTenantId.mockReturnValue(undefined);
|
||||
});
|
||||
|
||||
describe('searchPrincipals', () => {
|
||||
|
|
@ -139,6 +149,108 @@ describe('PermissionsController', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getResourcePermissions — principal details', () => {
|
||||
const currentTenantId = 'tenant-a';
|
||||
const otherTenantId = 'tenant-b';
|
||||
const userId = new mongoose.Types.ObjectId();
|
||||
const groupId = new mongoose.Types.ObjectId();
|
||||
|
||||
it('omits joined user and group details outside the current request context', async () => {
|
||||
mockGetTenantId.mockReturnValue(currentTenantId);
|
||||
db.aggregateAclEntries.mockResolvedValue([
|
||||
{
|
||||
principalType: PrincipalType.USER,
|
||||
accessRoleId: AccessRoleIds.AGENT_VIEWER,
|
||||
userInfo: {
|
||||
_id: userId,
|
||||
tenantId: otherTenantId,
|
||||
name: 'Outside User',
|
||||
email: 'outside-user@example.com',
|
||||
avatar: 'outside-user.png',
|
||||
},
|
||||
},
|
||||
{
|
||||
principalType: PrincipalType.GROUP,
|
||||
accessRoleId: AccessRoleIds.AGENT_VIEWER,
|
||||
groupInfo: {
|
||||
_id: groupId,
|
||||
tenantId: otherTenantId,
|
||||
name: 'Outside Group',
|
||||
email: 'outside-group@example.com',
|
||||
avatar: 'outside-group.png',
|
||||
},
|
||||
},
|
||||
{
|
||||
principalType: PrincipalType.PUBLIC,
|
||||
accessRoleId: AccessRoleIds.AGENT_VIEWER,
|
||||
},
|
||||
]);
|
||||
|
||||
const req = createMockReq();
|
||||
const res = createMockRes();
|
||||
|
||||
await getResourcePermissions(req, res);
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(200);
|
||||
expect(res.json).toHaveBeenCalledWith({
|
||||
resourceType: ResourceType.AGENT,
|
||||
resourceId: req.params.resourceId,
|
||||
principals: [],
|
||||
public: true,
|
||||
publicAccessRoleId: AccessRoleIds.AGENT_VIEWER,
|
||||
});
|
||||
expect(JSON.stringify(res.json.mock.calls[0][0])).not.toContain('outside-user@example.com');
|
||||
expect(JSON.stringify(res.json.mock.calls[0][0])).not.toContain('outside-group@example.com');
|
||||
});
|
||||
|
||||
it('includes joined user and group details in the current request context', async () => {
|
||||
mockGetTenantId.mockReturnValue(currentTenantId);
|
||||
db.aggregateAclEntries.mockResolvedValue([
|
||||
{
|
||||
principalType: PrincipalType.USER,
|
||||
accessRoleId: AccessRoleIds.AGENT_VIEWER,
|
||||
userInfo: {
|
||||
_id: userId,
|
||||
tenantId: currentTenantId,
|
||||
name: 'Current User',
|
||||
email: 'current-user@example.com',
|
||||
avatar: 'current-user.png',
|
||||
},
|
||||
},
|
||||
{
|
||||
principalType: PrincipalType.GROUP,
|
||||
accessRoleId: AccessRoleIds.AGENT_VIEWER,
|
||||
groupInfo: {
|
||||
_id: groupId,
|
||||
tenantId: currentTenantId,
|
||||
name: 'Current Group',
|
||||
email: 'current-group@example.com',
|
||||
avatar: 'current-group.png',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const req = createMockReq();
|
||||
const res = createMockRes();
|
||||
|
||||
await getResourcePermissions(req, res);
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(200);
|
||||
expect(res.json.mock.calls[0][0].principals).toEqual([
|
||||
expect.objectContaining({
|
||||
type: PrincipalType.USER,
|
||||
id: userId.toString(),
|
||||
email: 'current-user@example.com',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
type: PrincipalType.GROUP,
|
||||
id: groupId.toString(),
|
||||
email: 'current-group@example.com',
|
||||
}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateResourcePermissions — favorites cleanup', () => {
|
||||
const agentObjectId = new mongoose.Types.ObjectId().toString();
|
||||
const revokedUserId = new mongoose.Types.ObjectId().toString();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue