fix(code-executor): shadow console via Function parameter instead of global mutation
- avoids mutating the global console object entirely - passes fakeConsole as a named parameter so the script's lexical console is the intercepted version without any save/restore dance - eliminates concurrency hazard when multiple scripts run concurrently
This commit is contained in:
@@ -43,27 +43,19 @@ export class CodeExecutorService {
|
||||
error: (...args: unknown[]) => scriptLog('error', toStr(args)),
|
||||
};
|
||||
|
||||
const prevLog = console.log;
|
||||
const prevWarn = console.warn;
|
||||
const prevError = console.error;
|
||||
const prevInfo = console.info;
|
||||
console.log = (...args: unknown[]) => scriptLog('log', toStr(args));
|
||||
console.warn = (...args: unknown[]) => scriptLog('warn', toStr(args));
|
||||
console.error = (...args: unknown[]) => scriptLog('error', toStr(args));
|
||||
console.info = (...args: unknown[]) => scriptLog('log', toStr(args));
|
||||
const fakeConsole = {
|
||||
log: (...args: unknown[]) => scriptLog('log', toStr(args)),
|
||||
warn: (...args: unknown[]) => scriptLog('warn', toStr(args)),
|
||||
error: (...args: unknown[]) => scriptLog('error', toStr(args)),
|
||||
info: (...args: unknown[]) => scriptLog('log', toStr(args)),
|
||||
debug: (...args: unknown[]) => scriptLog('log', toStr(args)),
|
||||
};
|
||||
|
||||
// Passing `console` as a named parameter shadows the global in the script scope.
|
||||
// eslint-disable-next-line no-new-func
|
||||
const fn = new Function('page', 'context', 'helpers', `return (async (page, context, helpers) => { ${code} })(page, context, helpers)`);
|
||||
const fn = new Function('page', 'context', 'helpers', 'console', `return (async (page, context, helpers) => { ${code} })(page, context, helpers)`);
|
||||
this.logger.debug('Executing user code');
|
||||
let result: unknown;
|
||||
try {
|
||||
result = await fn(page, context, pageHelpers);
|
||||
} finally {
|
||||
console.log = prevLog;
|
||||
console.warn = prevWarn;
|
||||
console.error = prevError;
|
||||
console.info = prevInfo;
|
||||
}
|
||||
const result = await fn(page, context, pageHelpers, fakeConsole);
|
||||
return { result };
|
||||
} catch (err) {
|
||||
throw new InternalServerErrorException(`Code execution failed: ${(err as Error).message}`, { cause: err });
|
||||
|
||||
Reference in New Issue
Block a user