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:
2026-04-08 17:13:20 +03:00
parent 7527a0b34b
commit c4ca622da5
+10 -18
View File
@@ -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 });