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)),
|
error: (...args: unknown[]) => scriptLog('error', toStr(args)),
|
||||||
};
|
};
|
||||||
|
|
||||||
const prevLog = console.log;
|
const fakeConsole = {
|
||||||
const prevWarn = console.warn;
|
log: (...args: unknown[]) => scriptLog('log', toStr(args)),
|
||||||
const prevError = console.error;
|
warn: (...args: unknown[]) => scriptLog('warn', toStr(args)),
|
||||||
const prevInfo = console.info;
|
error: (...args: unknown[]) => scriptLog('error', toStr(args)),
|
||||||
console.log = (...args: unknown[]) => scriptLog('log', toStr(args));
|
info: (...args: unknown[]) => scriptLog('log', toStr(args)),
|
||||||
console.warn = (...args: unknown[]) => scriptLog('warn', toStr(args));
|
debug: (...args: unknown[]) => scriptLog('log', toStr(args)),
|
||||||
console.error = (...args: unknown[]) => scriptLog('error', toStr(args));
|
};
|
||||||
console.info = (...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
|
// 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');
|
this.logger.debug('Executing user code');
|
||||||
let result: unknown;
|
const result = await fn(page, context, pageHelpers, fakeConsole);
|
||||||
try {
|
|
||||||
result = await fn(page, context, pageHelpers);
|
|
||||||
} finally {
|
|
||||||
console.log = prevLog;
|
|
||||||
console.warn = prevWarn;
|
|
||||||
console.error = prevError;
|
|
||||||
console.info = prevInfo;
|
|
||||||
}
|
|
||||||
return { result };
|
return { result };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new InternalServerErrorException(`Code execution failed: ${(err as Error).message}`, { cause: err });
|
throw new InternalServerErrorException(`Code execution failed: ${(err as Error).message}`, { cause: err });
|
||||||
|
|||||||
Reference in New Issue
Block a user