Pull the error object out of isolated-vm when a user script throws an error.
This commit is contained in:
parent
b9a975694f
commit
b004ef5448
|
@ -44,7 +44,7 @@ describe("jsRunner (using isolated-vm)", () => {
|
||||||
const output = await processJS(
|
const output = await processJS(
|
||||||
`return this.constructor.constructor("return process.env")()`
|
`return this.constructor.constructor("return process.env")()`
|
||||||
)
|
)
|
||||||
expect(output).toBe("Error while executing JS")
|
expect(output).toBe("ReferenceError: process is not defined")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("helpers", () => {
|
describe("helpers", () => {
|
||||||
|
|
|
@ -17,6 +17,15 @@ class ExecutionTimeoutError extends Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UserScriptError extends Error {
|
||||||
|
constructor(readonly userScriptError: Error) {
|
||||||
|
super(
|
||||||
|
`error while running user-supplied JavaScript: ${userScriptError.message}`,
|
||||||
|
{ cause: userScriptError }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class IsolatedVM implements VM {
|
export class IsolatedVM implements VM {
|
||||||
private isolate: ivm.Isolate
|
private isolate: ivm.Isolate
|
||||||
private vm: ivm.Context
|
private vm: ivm.Context
|
||||||
|
@ -29,6 +38,7 @@ export class IsolatedVM implements VM {
|
||||||
|
|
||||||
private readonly resultKey = "results"
|
private readonly resultKey = "results"
|
||||||
private runResultKey: string
|
private runResultKey: string
|
||||||
|
private runErrorKey: string
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
|
@ -47,6 +57,7 @@ export class IsolatedVM implements VM {
|
||||||
this.jail.setSync("global", this.jail.derefInto())
|
this.jail.setSync("global", this.jail.derefInto())
|
||||||
|
|
||||||
this.runResultKey = crypto.randomUUID()
|
this.runResultKey = crypto.randomUUID()
|
||||||
|
this.runErrorKey = crypto.randomUUID()
|
||||||
this.addToContext({
|
this.addToContext({
|
||||||
[this.resultKey]: { [this.runResultKey]: "" },
|
[this.resultKey]: { [this.runResultKey]: "" },
|
||||||
})
|
})
|
||||||
|
@ -216,7 +227,13 @@ export class IsolatedVM implements VM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
code = `results['${this.runResultKey}']=${this.codeWrapper(code)}`
|
code = `
|
||||||
|
try {
|
||||||
|
results['${this.runResultKey}']=${this.codeWrapper(code)}
|
||||||
|
} catch (e) {
|
||||||
|
results['${this.runErrorKey}']=e
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
const script = this.isolate.compileScriptSync(code)
|
const script = this.isolate.compileScriptSync(code)
|
||||||
|
|
||||||
|
@ -227,6 +244,9 @@ export class IsolatedVM implements VM {
|
||||||
|
|
||||||
// We can't rely on the script run result as it will not work for non-transferable values
|
// We can't rely on the script run result as it will not work for non-transferable values
|
||||||
const result = this.getFromContext(this.resultKey)
|
const result = this.getFromContext(this.resultKey)
|
||||||
|
if (result[this.runErrorKey]) {
|
||||||
|
throw new UserScriptError(result[this.runErrorKey])
|
||||||
|
}
|
||||||
return result[this.runResultKey]
|
return result[this.runResultKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,9 @@ export function processJS(handlebars: string, context: any) {
|
||||||
if (error.name === "ExecutionTimeoutError") {
|
if (error.name === "ExecutionTimeoutError") {
|
||||||
return "Request JS execution limit hit"
|
return "Request JS execution limit hit"
|
||||||
}
|
}
|
||||||
|
if ("userScriptError" in error) {
|
||||||
|
return error.userScriptError.toString()
|
||||||
|
}
|
||||||
return "Error while executing JS"
|
return "Error while executing JS"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue