Refactor/Update code execution sandbox implementation across components (#4904)

refactor: Update code execution sandbox implementation across components

- Replaced NodeVM usage with a new createCodeExecutionSandbox function for improved sandbox management.
- Enhanced JavaScript code execution with executeJavaScriptCode function, allowing for better handling of libraries and output streaming.
- Updated multiple components to utilize the new sandboxing approach, ensuring consistent execution environment.
- Added validation for UUIDs and URLs in various tools to enhance input safety.
- Refactored input handling in CustomFunction and IfElseFunction to streamline variable management.
This commit is contained in:
Henry Heng
2025-07-21 00:09:01 +01:00
committed by GitHub
parent 9a06a85a8d
commit dca91b979b
24 changed files with 550 additions and 488 deletions
@@ -1,9 +1,8 @@
import { z } from 'zod'
import { NodeVM } from '@flowiseai/nodevm'
import { RunnableConfig } from '@langchain/core/runnables'
import { StructuredTool, ToolParams } from '@langchain/core/tools'
import { CallbackManagerForToolRun, Callbacks, CallbackManager, parseCallbackConfigArg } from '@langchain/core/callbacks/manager'
import { availableDependencies, defaultAllowBuiltInDep, prepareSandboxVars } from '../../../src/utils'
import { executeJavaScriptCode, createCodeExecutionSandbox } from '../../../src/utils'
import { ICommonObject } from '../../../src/Interface'
class ToolInputParsingException extends Error {
@@ -111,46 +110,23 @@ export class DynamicStructuredTool<
_?: CallbackManagerForToolRun,
flowConfig?: { sessionId?: string; chatId?: string; input?: string; state?: ICommonObject }
): Promise<string> {
let sandbox: any = {
util: undefined,
Symbol: undefined,
child_process: undefined,
fs: undefined,
process: undefined
}
// Create additional sandbox variables for tool arguments
const additionalSandbox: ICommonObject = {}
if (typeof arg === 'object' && Object.keys(arg).length) {
for (const item in arg) {
sandbox[`$${item}`] = arg[item]
additionalSandbox[`$${item}`] = arg[item]
}
}
sandbox['$vars'] = prepareSandboxVars(this.variables)
// Prepare flow object for sandbox
const flow = this.flowObj ? { ...this.flowObj, ...flowConfig } : {}
// inject flow properties
if (this.flowObj) {
sandbox['$flow'] = { ...this.flowObj, ...flowConfig }
}
const sandbox = createCodeExecutionSandbox('', this.variables || [], flow, additionalSandbox)
const builtinDeps = process.env.TOOL_FUNCTION_BUILTIN_DEP
? defaultAllowBuiltInDep.concat(process.env.TOOL_FUNCTION_BUILTIN_DEP.split(','))
: defaultAllowBuiltInDep
const externalDeps = process.env.TOOL_FUNCTION_EXTERNAL_DEP ? process.env.TOOL_FUNCTION_EXTERNAL_DEP.split(',') : []
const deps = availableDependencies.concat(externalDeps)
const options = {
console: 'inherit',
sandbox,
require: {
external: { modules: deps },
builtin: builtinDeps
},
eval: false,
wasm: false,
const response = await executeJavaScriptCode(this.code, sandbox, {
timeout: 10000
} as any
const vm = new NodeVM(options)
const response = await vm.run(`module.exports = async function() {${this.code}}()`, __dirname)
})
return response
}