diff --git a/api/server/routes/agents/actions.js b/api/server/routes/agents/actions.js index e6f6fe064f..06a6108df5 100644 --- a/api/server/routes/agents/actions.js +++ b/api/server/routes/agents/actions.js @@ -87,7 +87,7 @@ router.post( const appConfig = await getAppConfig({ role: req.user.role }); const isDomainAllowed = await isActionDomainAllowed( metadata.domain, - appConfig?.registration?.allowedDomains, + appConfig?.actions?.allowedDomains, ); if (!isDomainAllowed) { return res.status(400).json({ message: 'Domain not allowed' }); diff --git a/api/server/routes/assistants/actions.js b/api/server/routes/assistants/actions.js index 01486c8f75..4cab980e19 100644 --- a/api/server/routes/assistants/actions.js +++ b/api/server/routes/assistants/actions.js @@ -34,7 +34,7 @@ router.post('/:assistant_id', async (req, res) => { let metadata = await encryptMetadata(removeNullishValues(_metadata, true)); const isDomainAllowed = await isActionDomainAllowed( metadata.domain, - appConfig?.registration?.allowedDomains, + appConfig?.actions?.allowedDomains, ); if (!isDomainAllowed) { return res.status(400).json({ message: 'Domain not allowed' }); diff --git a/api/server/routes/files/multer.spec.js b/api/server/routes/files/multer.spec.js index 6f48c014e0..8be44b5184 100644 --- a/api/server/routes/files/multer.spec.js +++ b/api/server/routes/files/multer.spec.js @@ -8,21 +8,6 @@ const { createMulterInstance, storage, importFileFilter } = require('./multer'); // Mock only the config service that requires external dependencies jest.mock('~/server/services/Config', () => ({ - getCustomConfig: jest.fn(() => - Promise.resolve({ - fileConfig: { - endpoints: { - openAI: { - supportedMimeTypes: ['image/jpeg', 'image/png', 'application/pdf'], - }, - default: { - supportedMimeTypes: ['image/jpeg', 'image/png', 'text/plain'], - }, - }, - serverFileSizeLimit: 10000000, // 10MB - }, - }), - ), getAppConfig: jest.fn(), })); @@ -546,10 +531,10 @@ describe('Multer Configuration', () => { describe('Real Configuration Testing', () => { it('should handle missing custom config gracefully with real mergeFileConfig', async () => { - const { getCustomConfig } = require('~/server/services/Config'); + const { getAppConfig } = require('~/server/services/Config'); - // Mock getCustomConfig to return undefined - getCustomConfig.mockResolvedValueOnce(undefined); + // Mock getAppConfig to return undefined + getAppConfig.mockResolvedValueOnce(undefined); const multerInstance = await createMulterInstance(); expect(multerInstance).toBeDefined(); diff --git a/api/server/services/ActionService.spec.js b/api/server/services/ActionService.spec.js index f3b4423197..c60aef7ad1 100644 --- a/api/server/services/ActionService.spec.js +++ b/api/server/services/ActionService.spec.js @@ -1,10 +1,7 @@ -const { Constants, EModelEndpoint, actionDomainSeparator } = require('librechat-data-provider'); +const { Constants, actionDomainSeparator } = require('librechat-data-provider'); const { domainParser } = require('./ActionService'); jest.mock('keyv'); -jest.mock('~/server/services/Config', () => ({ - getCustomConfig: jest.fn(), -})); const globalCache = {}; jest.mock('~/cache/getLogStores', () => { @@ -53,26 +50,6 @@ jest.mock('~/cache/getLogStores', () => { }); describe('domainParser', () => { - const req = { - app: { - locals: { - [EModelEndpoint.azureOpenAI]: { - assistants: true, - }, - }, - }, - }; - - const reqNoAzure = { - app: { - locals: { - [EModelEndpoint.azureOpenAI]: { - assistants: false, - }, - }, - }, - }; - const TLD = '.com'; // Non-azure request diff --git a/api/server/services/ToolService.js b/api/server/services/ToolService.js index 382df9bfab..62cc175d73 100644 --- a/api/server/services/ToolService.js +++ b/api/server/services/ToolService.js @@ -366,7 +366,7 @@ async function processRequiredActions(client, requiredActions) { const isDomainAllowed = await isActionDomainAllowed( action.metadata.domain, - appConfig?.registration?.allowedDomains, + appConfig?.actions?.allowedDomains, ); if (!isDomainAllowed) { continue; @@ -635,7 +635,7 @@ async function loadAgentTools({ req, res, agent, tool_resources, openAIApiKey }) // Check if domain is allowed (do this once per action set) const isDomainAllowed = await isActionDomainAllowed( action.metadata.domain, - appConfig?.registration?.allowedDomains, + appConfig?.actions?.allowedDomains, ); if (!isDomainAllowed) { continue; diff --git a/api/server/services/domains.spec.js b/api/server/services/domains.spec.js index b6086174a7..bbf9f38cdb 100644 --- a/api/server/services/domains.spec.js +++ b/api/server/services/domains.spec.js @@ -1,8 +1,8 @@ const { isEmailDomainAllowed, isActionDomainAllowed } = require('~/server/services/domains'); -const { getCustomConfig } = require('~/server/services/Config'); +const { getAppConfig } = require('~/server/services/Config'); jest.mock('~/server/services/Config', () => ({ - getCustomConfig: jest.fn(), + getAppConfig: jest.fn(), })); describe('isEmailDomainAllowed', () => { @@ -24,21 +24,21 @@ describe('isEmailDomainAllowed', () => { it('should return true if customConfig is not available', async () => { const email = 'test@domain1.com'; - getCustomConfig.mockResolvedValue(null); + getAppConfig.mockResolvedValue(null); const result = await isEmailDomainAllowed(email, null); expect(result).toBe(true); }); it('should return true if allowedDomains is not defined in customConfig', async () => { const email = 'test@domain1.com'; - getCustomConfig.mockResolvedValue({}); + getAppConfig.mockResolvedValue({}); const result = await isEmailDomainAllowed(email, undefined); expect(result).toBe(true); }); it('should return true if domain is included in the allowedDomains', async () => { const email = 'user@domain1.com'; - getCustomConfig.mockResolvedValue({ + getAppConfig.mockResolvedValue({ registration: { allowedDomains: ['domain1.com', 'domain2.com'], }, @@ -49,7 +49,7 @@ describe('isEmailDomainAllowed', () => { it('should return false if domain is not included in the allowedDomains', async () => { const email = 'user@domain3.com'; - getCustomConfig.mockResolvedValue({ + getAppConfig.mockResolvedValue({ registration: { allowedDomains: ['domain1.com', 'domain2.com'], }, @@ -80,7 +80,7 @@ describe('isActionDomainAllowed', () => { }); it('should return false for invalid domain formats', async () => { - getCustomConfig.mockResolvedValue({ + getAppConfig.mockResolvedValue({ actions: { allowedDomains: ['http://', 'https://'] }, }); expect(await isActionDomainAllowed('http://', ['http://', 'https://'])).toBe(false); @@ -91,17 +91,17 @@ describe('isActionDomainAllowed', () => { // Configuration Tests describe('configuration handling', () => { it('should return true if customConfig is null', async () => { - getCustomConfig.mockResolvedValue(null); + getAppConfig.mockResolvedValue(null); expect(await isActionDomainAllowed('example.com', null)).toBe(true); }); it('should return true if actions.allowedDomains is not defined', async () => { - getCustomConfig.mockResolvedValue({}); + getAppConfig.mockResolvedValue({}); expect(await isActionDomainAllowed('example.com', undefined)).toBe(true); }); it('should return true if allowedDomains is empty array', async () => { - getCustomConfig.mockResolvedValue({ + getAppConfig.mockResolvedValue({ actions: { allowedDomains: [] }, }); expect(await isActionDomainAllowed('example.com', [])).toBe(true); @@ -119,7 +119,7 @@ describe('isActionDomainAllowed', () => { ]; beforeEach(() => { - getCustomConfig.mockResolvedValue({ + getAppConfig.mockResolvedValue({ actions: { allowedDomains, }, @@ -160,7 +160,7 @@ describe('isActionDomainAllowed', () => { const edgeAllowedDomains = ['example.com', '*.test.com']; beforeEach(() => { - getCustomConfig.mockResolvedValue({ + getAppConfig.mockResolvedValue({ actions: { allowedDomains: edgeAllowedDomains, }, @@ -186,7 +186,7 @@ describe('isActionDomainAllowed', () => { it('should handle invalid entries in allowedDomains', async () => { const invalidAllowedDomains = ['example.com', null, undefined, '', 'test.com']; - getCustomConfig.mockResolvedValue({ + getAppConfig.mockResolvedValue({ actions: { allowedDomains: invalidAllowedDomains, }, diff --git a/packages/api/src/types/config.ts b/packages/api/src/types/config.ts index 6487203b0f..45e512b61a 100644 --- a/packages/api/src/types/config.ts +++ b/packages/api/src/types/config.ts @@ -33,6 +33,8 @@ export interface AppConfig { fileStrategy: FileSources.local | FileSources.s3 | FileSources.firebase | FileSources.azure_blob; /** Registration configurations */ registration?: TCustomConfig['registration']; + /** Actions configurations */ + actions?: TCustomConfig['actions']; /** Admin-filtered tools */ filteredTools?: string[]; /** Admin-included tools */