mirror of
https://github.com/simstudioai/sim.git
synced 2026-02-10 22:55:16 -05:00
fix(rce): add 'isolate' to list of trusted deps, fixed custom tools environment resolution (#2387)
* fix(rce): add isolate to list of trusted deps * updated error enchancer in RCE * fixed * fix build * fix failing test * fix build * fix build * remove extraneous comment
This commit is contained in:
@@ -5,6 +5,10 @@ import { executeInE2B } from '@/lib/execution/e2b'
|
||||
import { executeInIsolatedVM } from '@/lib/execution/isolated-vm'
|
||||
import { CodeLanguage, DEFAULT_CODE_LANGUAGE, isValidCodeLanguage } from '@/lib/execution/languages'
|
||||
import { createLogger } from '@/lib/logs/console/logger'
|
||||
import {
|
||||
createEnvVarPattern,
|
||||
createWorkflowVariablePattern,
|
||||
} from '@/executor/utils/reference-validation'
|
||||
export const dynamic = 'force-dynamic'
|
||||
export const runtime = 'nodejs'
|
||||
|
||||
@@ -321,9 +325,9 @@ function createUserFriendlyErrorMessage(
|
||||
): string {
|
||||
let errorMessage = enhanced.message
|
||||
|
||||
// Add line and column information if available
|
||||
// Add line information if available
|
||||
if (enhanced.line !== undefined) {
|
||||
let lineInfo = `Line ${enhanced.line}${enhanced.column !== undefined ? `:${enhanced.column}` : ''}`
|
||||
let lineInfo = `Line ${enhanced.line}`
|
||||
|
||||
// Add the actual line content if available
|
||||
if (enhanced.lineContent) {
|
||||
@@ -337,8 +341,7 @@ function createUserFriendlyErrorMessage(
|
||||
const stackMatch = enhanced.stack.match(/user-function\.js:(\d+)(?::(\d+))?/)
|
||||
if (stackMatch) {
|
||||
const line = Number.parseInt(stackMatch[1], 10)
|
||||
const column = stackMatch[2] ? Number.parseInt(stackMatch[2], 10) : undefined
|
||||
let lineInfo = `Line ${line}${column ? `:${column}` : ''}`
|
||||
let lineInfo = `Line ${line}`
|
||||
|
||||
// Try to get line content if we have userCode
|
||||
if (userCode) {
|
||||
@@ -375,27 +378,6 @@ function createUserFriendlyErrorMessage(
|
||||
}
|
||||
}
|
||||
|
||||
// For syntax errors, provide additional context
|
||||
if (enhanced.name === 'SyntaxError') {
|
||||
if (errorMessage.includes('Invalid or unexpected token')) {
|
||||
errorMessage += ' (Check for missing quotes, brackets, or semicolons)'
|
||||
} else if (errorMessage.includes('Unexpected end of input')) {
|
||||
errorMessage += ' (Check for missing closing brackets or braces)'
|
||||
} else if (errorMessage.includes('Unexpected token')) {
|
||||
// Check if this might be due to incomplete code
|
||||
if (
|
||||
enhanced.lineContent &&
|
||||
((enhanced.lineContent.includes('(') && !enhanced.lineContent.includes(')')) ||
|
||||
(enhanced.lineContent.includes('[') && !enhanced.lineContent.includes(']')) ||
|
||||
(enhanced.lineContent.includes('{') && !enhanced.lineContent.includes('}')))
|
||||
) {
|
||||
errorMessage += ' (Check for missing closing parentheses, brackets, or braces)'
|
||||
} else {
|
||||
errorMessage += ' (Check your syntax)'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errorMessage
|
||||
}
|
||||
|
||||
@@ -409,19 +391,27 @@ function resolveWorkflowVariables(
|
||||
): string {
|
||||
let resolvedCode = code
|
||||
|
||||
const variableMatches = resolvedCode.match(/<variable\.([^>]+)>/g) || []
|
||||
for (const match of variableMatches) {
|
||||
const variableName = match.slice('<variable.'.length, -1).trim()
|
||||
const regex = createWorkflowVariablePattern()
|
||||
let match: RegExpExecArray | null
|
||||
const replacements: Array<{
|
||||
match: string
|
||||
index: number
|
||||
variableName: string
|
||||
variableValue: unknown
|
||||
}> = []
|
||||
|
||||
while ((match = regex.exec(code)) !== null) {
|
||||
const variableName = match[1].trim()
|
||||
|
||||
// Find the variable by name (workflowVariables is indexed by ID, values are variable objects)
|
||||
const foundVariable = Object.entries(workflowVariables).find(
|
||||
([_, variable]) => (variable.name || '').replace(/\s+/g, '') === variableName
|
||||
)
|
||||
|
||||
let variableValue: unknown = ''
|
||||
if (foundVariable) {
|
||||
const variable = foundVariable[1]
|
||||
// Get the typed value - handle different variable types
|
||||
let variableValue = variable.value
|
||||
variableValue = variable.value
|
||||
|
||||
if (variable.value !== undefined && variable.value !== null) {
|
||||
try {
|
||||
@@ -443,22 +433,30 @@ function resolveWorkflowVariables(
|
||||
// Keep original value if JSON parsing fails
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// Fallback to original value on error
|
||||
variableValue = variable.value
|
||||
}
|
||||
}
|
||||
|
||||
// Create a safe variable reference
|
||||
const safeVarName = `__variable_${variableName.replace(/[^a-zA-Z0-9_]/g, '_')}`
|
||||
contextVariables[safeVarName] = variableValue
|
||||
|
||||
// Replace the variable reference with the safe variable name
|
||||
resolvedCode = resolvedCode.replace(new RegExp(escapeRegExp(match), 'g'), safeVarName)
|
||||
} else {
|
||||
// Variable not found - replace with empty string to avoid syntax errors
|
||||
resolvedCode = resolvedCode.replace(new RegExp(escapeRegExp(match), 'g'), '')
|
||||
}
|
||||
|
||||
replacements.push({
|
||||
match: match[0],
|
||||
index: match.index,
|
||||
variableName,
|
||||
variableValue,
|
||||
})
|
||||
}
|
||||
|
||||
// Process replacements in reverse order to maintain correct indices
|
||||
for (let i = replacements.length - 1; i >= 0; i--) {
|
||||
const { match: matchStr, index, variableName, variableValue } = replacements[i]
|
||||
|
||||
// Use variable reference approach
|
||||
const safeVarName = `__variable_${variableName.replace(/[^a-zA-Z0-9_]/g, '_')}`
|
||||
contextVariables[safeVarName] = variableValue
|
||||
resolvedCode =
|
||||
resolvedCode.slice(0, index) + safeVarName + resolvedCode.slice(index + matchStr.length)
|
||||
}
|
||||
|
||||
return resolvedCode
|
||||
@@ -475,18 +473,29 @@ function resolveEnvironmentVariables(
|
||||
): string {
|
||||
let resolvedCode = code
|
||||
|
||||
const envVarMatches = resolvedCode.match(/\{\{([^}]+)\}\}/g) || []
|
||||
for (const match of envVarMatches) {
|
||||
const varName = match.slice(2, -2).trim()
|
||||
// Priority: 1. Environment variables from workflow, 2. Params
|
||||
const varValue = envVars[varName] || params[varName] || ''
|
||||
const regex = createEnvVarPattern()
|
||||
let match: RegExpExecArray | null
|
||||
const replacements: Array<{ match: string; index: number; varName: string; varValue: string }> =
|
||||
[]
|
||||
|
||||
while ((match = regex.exec(code)) !== null) {
|
||||
const varName = match[1].trim()
|
||||
const varValue = envVars[varName] || params[varName] || ''
|
||||
replacements.push({
|
||||
match: match[0],
|
||||
index: match.index,
|
||||
varName,
|
||||
varValue: String(varValue),
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = replacements.length - 1; i >= 0; i--) {
|
||||
const { match: matchStr, index, varName, varValue } = replacements[i]
|
||||
|
||||
// Instead of injecting large JSON directly, create a variable reference
|
||||
const safeVarName = `__var_${varName.replace(/[^a-zA-Z0-9_]/g, '_')}`
|
||||
contextVariables[safeVarName] = varValue
|
||||
|
||||
// Replace the template with a variable reference
|
||||
resolvedCode = resolvedCode.replace(new RegExp(escapeRegExp(match), 'g'), safeVarName)
|
||||
resolvedCode =
|
||||
resolvedCode.slice(0, index) + safeVarName + resolvedCode.slice(index + matchStr.length)
|
||||
}
|
||||
|
||||
return resolvedCode
|
||||
@@ -905,18 +914,22 @@ export async function POST(req: NextRequest) {
|
||||
const executionTime = Date.now() - startTime
|
||||
|
||||
if (isolatedResult.error) {
|
||||
const errorObj = {
|
||||
message: isolatedResult.error.message,
|
||||
name: isolatedResult.error.name,
|
||||
stack: isolatedResult.error.stack,
|
||||
}
|
||||
|
||||
logger.error(`[${requestId}] Function execution failed in isolated-vm`, {
|
||||
error: isolatedResult.error,
|
||||
executionTime,
|
||||
})
|
||||
|
||||
const enhancedError = extractEnhancedError(errorObj, userCodeStartLine, resolvedCode)
|
||||
const ivmError = isolatedResult.error
|
||||
const enhancedError: EnhancedError = {
|
||||
message: ivmError.message,
|
||||
name: ivmError.name,
|
||||
stack: ivmError.stack,
|
||||
originalError: ivmError,
|
||||
line: ivmError.line,
|
||||
column: ivmError.column,
|
||||
lineContent: ivmError.lineContent,
|
||||
}
|
||||
|
||||
const userFriendlyErrorMessage = createUserFriendlyErrorMessage(
|
||||
enhancedError,
|
||||
requestId,
|
||||
@@ -924,13 +937,12 @@ export async function POST(req: NextRequest) {
|
||||
)
|
||||
|
||||
logger.error(`[${requestId}] Enhanced error details`, {
|
||||
originalMessage: errorObj.message,
|
||||
originalMessage: ivmError.message,
|
||||
enhancedMessage: userFriendlyErrorMessage,
|
||||
line: enhancedError.line,
|
||||
column: enhancedError.column,
|
||||
lineContent: enhancedError.lineContent,
|
||||
errorType: enhancedError.name,
|
||||
userCodeStartLine,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
@@ -978,7 +990,6 @@ export async function POST(req: NextRequest) {
|
||||
resolvedCode
|
||||
)
|
||||
|
||||
// Log enhanced error details for debugging
|
||||
logger.error(`[${requestId}] Enhanced error details`, {
|
||||
originalMessage: error.message,
|
||||
enhancedMessage: userFriendlyErrorMessage,
|
||||
@@ -997,7 +1008,6 @@ export async function POST(req: NextRequest) {
|
||||
stdout: cleanStdout(stdout),
|
||||
executionTime,
|
||||
},
|
||||
// Include debug information in development or for debugging
|
||||
debug: {
|
||||
line: enhancedError.line,
|
||||
column: enhancedError.column,
|
||||
|
||||
Reference in New Issue
Block a user