mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-27 04:07:05 +00:00
🛂 fix: Re-Check execute_code Authorization on Event-Driven Tool Loads (#13912)
This commit is contained in:
parent
e807c63d5d
commit
edc0aebdb9
2 changed files with 57 additions and 6 deletions
|
|
@ -1451,20 +1451,25 @@ async function loadToolsForExecution({
|
|||
AgentConstants.PROGRAMMATIC_TOOL_CALLING,
|
||||
].filter((name) => toolNames.includes(name));
|
||||
const isPTCRequested = ptcToolNames.length > 0;
|
||||
const isBashToolRequested = toolNames.includes(AgentConstants.BASH_TOOL);
|
||||
const isLegacyExecuteCodeRequested = toolNames.includes(Tools.execute_code);
|
||||
const isCodeExecutionToolRequested = isBashToolRequested || isLegacyExecuteCodeRequested;
|
||||
|
||||
let enabledCapabilities;
|
||||
if (actionsEnabled === undefined || isPTCRequested) {
|
||||
if (actionsEnabled === undefined || isPTCRequested || isCodeExecutionToolRequested) {
|
||||
enabledCapabilities = await resolveAgentCapabilities(req, appConfig, agent?.id);
|
||||
}
|
||||
if (actionsEnabled === undefined) {
|
||||
actionsEnabled = enabledCapabilities.has(AgentCapabilities.actions);
|
||||
}
|
||||
const codeExecutionEnabled =
|
||||
enabledCapabilities?.has(AgentCapabilities.execute_code) === true &&
|
||||
agent?.tools?.includes(Tools.execute_code) === true;
|
||||
|
||||
const isPTC =
|
||||
isPTCRequested &&
|
||||
enabledCapabilities.has(AgentCapabilities.programmatic_tools) &&
|
||||
enabledCapabilities.has(AgentCapabilities.execute_code) &&
|
||||
agent?.tools?.includes(Tools.execute_code) === true;
|
||||
codeExecutionEnabled;
|
||||
|
||||
logger.debug(
|
||||
`[loadToolsForExecution] isToolSearch: ${isToolSearch}, toolRegistry: ${toolRegistry?.size ?? 'undefined'}`,
|
||||
|
|
@ -1498,7 +1503,16 @@ async function loadToolsForExecution({
|
|||
}
|
||||
}
|
||||
|
||||
const isBashTool = toolNames.includes(AgentConstants.BASH_TOOL);
|
||||
const isBashTool =
|
||||
isBashToolRequested &&
|
||||
codeExecutionEnabled &&
|
||||
toolRegistry?.has(AgentConstants.BASH_TOOL) === true;
|
||||
if (isBashToolRequested && !isBashTool) {
|
||||
logger.warn(
|
||||
`[loadToolsForExecution] Skipping unregistered or unauthorized ${AgentConstants.BASH_TOOL}. ` +
|
||||
`User: ${req.user.id} | Agent: ${agent?.id ?? 'unknown'}`,
|
||||
);
|
||||
}
|
||||
if (isBashTool) {
|
||||
try {
|
||||
const bashTool = createBashExecutionTool({
|
||||
|
|
@ -1535,9 +1549,22 @@ async function loadToolsForExecution({
|
|||
}
|
||||
|
||||
const requestedNonSpecialToolNames = toolNames.filter((name) => !specialToolNames.has(name));
|
||||
const allowedNonSpecialToolNames = requestedNonSpecialToolNames.filter((name) => {
|
||||
if (name !== Tools.execute_code) {
|
||||
return true;
|
||||
}
|
||||
const allowed = codeExecutionEnabled && toolRegistry?.has(Tools.execute_code) === true;
|
||||
if (!allowed) {
|
||||
logger.warn(
|
||||
`[loadToolsForExecution] Skipping unregistered or unauthorized ${Tools.execute_code}. ` +
|
||||
`User: ${req.user.id} | Agent: ${agent?.id ?? 'unknown'}`,
|
||||
);
|
||||
}
|
||||
return allowed;
|
||||
});
|
||||
const allToolNamesToLoad = isPTC
|
||||
? [...new Set([...requestedNonSpecialToolNames, ...ptcOrchestratedToolNames])]
|
||||
: requestedNonSpecialToolNames;
|
||||
? [...new Set([...allowedNonSpecialToolNames, ...ptcOrchestratedToolNames])]
|
||||
: allowedNonSpecialToolNames;
|
||||
|
||||
const actionToolNames = [];
|
||||
const regularToolNames = [];
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
const { Constants: AgentConstants } = require('@librechat/agents');
|
||||
const {
|
||||
Tools,
|
||||
Constants,
|
||||
|
|
@ -964,6 +965,29 @@ describe('ToolService - Action Capability Gating', () => {
|
|||
const actionToolName = `get_weather${actionDelimiter}api_example_com`;
|
||||
const regularTool = Tools.web_search;
|
||||
|
||||
it('does not load code execution tools that were not registered for the agent', async () => {
|
||||
const capabilities = [
|
||||
AgentCapabilities.tools,
|
||||
AgentCapabilities.web_search,
|
||||
AgentCapabilities.execute_code,
|
||||
];
|
||||
const req = createMockReq(capabilities);
|
||||
const toolRegistry = new Map([[Tools.web_search, { name: Tools.web_search }]]);
|
||||
mockGetEndpointsConfig.mockResolvedValue(createEndpointsConfig(capabilities));
|
||||
|
||||
const result = await loadToolsForExecution({
|
||||
req,
|
||||
res: {},
|
||||
agent: { id: 'agent_without_code', tools: [Tools.web_search] },
|
||||
toolNames: [AgentConstants.BASH_TOOL, Tools.execute_code],
|
||||
toolRegistry,
|
||||
actionsEnabled: false,
|
||||
});
|
||||
|
||||
expect(result.loadedTools.map((tool) => tool.name)).toEqual([]);
|
||||
expect(mockLoadToolsUtil).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('loads bash PTC under the legacy programmatic tool name when code capabilities are enabled', async () => {
|
||||
const capabilities = [
|
||||
AgentCapabilities.tools,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue