work in progress: replace vm2 and vm with isolated-vm
This commit is contained in:
parent
3e6848fda5
commit
58abca62de
|
@ -124,6 +124,8 @@ HEALTHCHECK --interval=15s --timeout=15s --start-period=45s CMD "/healthcheck.sh
|
|||
|
||||
# must set this just before running
|
||||
ENV NODE_ENV=production
|
||||
# this is required for isolated-vm to work on Node 20+
|
||||
ENV NODE_OPTIONS="--no-node-snapshot"
|
||||
WORKDIR /
|
||||
|
||||
CMD ["./runner.sh"]
|
||||
|
|
|
@ -82,6 +82,8 @@ EXPOSE 4001
|
|||
# due to this causing yarn to stop installing dev dependencies
|
||||
# which are actually needed to get this environment up and running
|
||||
ENV NODE_ENV=production
|
||||
# this is required for isolated-vm to work on Node 20+
|
||||
ENV NODE_OPTIONS="--no-node-snapshot"
|
||||
ENV CLUSTER_MODE=${CLUSTER_MODE}
|
||||
ENV TOP_LEVEL_PATH=/app
|
||||
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
],
|
||||
"ext": "js,ts,json",
|
||||
"ignore": ["src/**/*.spec.ts", "src/**/*.spec.js", "../*/dist/**/*"],
|
||||
"exec": "yarn build && node ./dist/index.js"
|
||||
"exec": "yarn build && node --no-node-snapshot ./dist/index.js"
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
"google-auth-library": "7.12.0",
|
||||
"google-spreadsheet": "3.2.0",
|
||||
"ioredis": "5.3.2",
|
||||
"isolated-vm": "^4.6.0",
|
||||
"jimp": "0.16.1",
|
||||
"joi": "17.6.0",
|
||||
"js-yaml": "4.1.0",
|
||||
|
@ -106,7 +107,6 @@
|
|||
"to-json-schema": "0.2.5",
|
||||
"uuid": "3.3.2",
|
||||
"validate.js": "0.13.1",
|
||||
"vm2": "^3.9.19",
|
||||
"worker-farm": "1.7.0",
|
||||
"xml2js": "0.5.0"
|
||||
},
|
||||
|
|
|
@ -4,11 +4,12 @@ set -e
|
|||
if [[ -n $CI ]]
|
||||
then
|
||||
# Running in ci, where resources are limited
|
||||
export NODE_OPTIONS="--max-old-space-size=4096"
|
||||
export NODE_OPTIONS="--max-old-space-size=4096 --no-node-snapshot"
|
||||
echo "jest --coverage --maxWorkers=2 --forceExit --workerIdleMemoryLimit=2000MB --bail"
|
||||
jest --coverage --maxWorkers=2 --forceExit --workerIdleMemoryLimit=2000MB --bail
|
||||
else
|
||||
# --maxWorkers performs better in development
|
||||
export NODE_OPTIONS="--no-node-snapshot"
|
||||
echo "jest --coverage --maxWorkers=2 --forceExit"
|
||||
jest --coverage --maxWorkers=2 --forceExit
|
||||
fi
|
|
@ -1,4 +1,5 @@
|
|||
import vm from "vm"
|
||||
import ivm from "isolated-vm"
|
||||
import env from "./environment"
|
||||
import { setJSRunner } from "@budibase/string-templates"
|
||||
import { context, timers } from "@budibase/backend-core"
|
||||
|
@ -31,18 +32,31 @@ export function init() {
|
|||
}
|
||||
}
|
||||
|
||||
ctx = {
|
||||
...ctx,
|
||||
alert: undefined,
|
||||
setInterval: undefined,
|
||||
setTimeout: undefined,
|
||||
const isolate = new ivm.Isolate({ memoryLimit: 64 })
|
||||
const vm = isolate.createContextSync()
|
||||
const jail = vm.global
|
||||
jail.setSync("global", jail.derefInto())
|
||||
|
||||
for (let key in ctx) {
|
||||
let value
|
||||
if (["alert", "setInterval", "setTimeout"].includes(key)) {
|
||||
value = undefined
|
||||
} else {
|
||||
value = ctx[key]
|
||||
}
|
||||
jail.setSync(
|
||||
key,
|
||||
new ivm.ExternalCopy(value).copyInto({ release: true })
|
||||
)
|
||||
}
|
||||
vm.createContext(ctx)
|
||||
return track(() =>
|
||||
vm.runInNewContext(js, ctx, {
|
||||
|
||||
const script = isolate.compileScriptSync(js)
|
||||
|
||||
return track(() => {
|
||||
return script.runSync(vm, {
|
||||
timeout: env.JS_PER_EXECUTION_TIME_LIMIT_MS,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,29 +1,64 @@
|
|||
import fetch from "node-fetch"
|
||||
import { VM, VMScript } from "vm2"
|
||||
import ivm, { Context, Script } from "isolated-vm"
|
||||
|
||||
const JS_TIMEOUT_MS = 1000
|
||||
|
||||
class ScriptRunner {
|
||||
vm: VM
|
||||
results: { out: string }
|
||||
script: VMScript
|
||||
vm: IsolatedVM
|
||||
|
||||
constructor(script: string, context: any) {
|
||||
const code = `let fn = () => {\n${script}\n}; results.out = fn();`
|
||||
this.vm = new VM({
|
||||
timeout: JS_TIMEOUT_MS,
|
||||
})
|
||||
this.results = { out: "" }
|
||||
this.vm.setGlobals(context)
|
||||
this.vm.setGlobal("fetch", fetch)
|
||||
this.vm.setGlobal("results", this.results)
|
||||
this.script = new VMScript(code)
|
||||
this.vm = new IsolatedVM({ memoryLimit: 8 })
|
||||
this.vm.context = {
|
||||
data: context.data,
|
||||
params: context.params,
|
||||
results: { out: "" },
|
||||
}
|
||||
this.vm.code = code
|
||||
}
|
||||
|
||||
execute() {
|
||||
this.vm.run(this.script)
|
||||
return this.results.out
|
||||
this.vm.runScript()
|
||||
const results = this.vm.getValue("results")
|
||||
return results.out
|
||||
}
|
||||
}
|
||||
|
||||
class IsolatedVM {
|
||||
isolate: ivm.Isolate
|
||||
vm: ivm.Context
|
||||
jail: ivm.Reference
|
||||
script: any
|
||||
|
||||
constructor({ memoryLimit }: { memoryLimit: number }) {
|
||||
this.isolate = new ivm.Isolate({ memoryLimit })
|
||||
this.vm = this.isolate.createContextSync()
|
||||
this.jail = this.vm.global
|
||||
this.jail.setSync("global", this.jail.derefInto())
|
||||
}
|
||||
|
||||
getValue(key: string) {
|
||||
const ref = this.vm.global.getSync(key, { reference: true })
|
||||
const result = ref.copySync()
|
||||
ref.release()
|
||||
return result
|
||||
}
|
||||
|
||||
set context(context: Record<string, any>) {
|
||||
for (let key in context) {
|
||||
this.jail.setSync(key, this.copyRefToVm(context[key]))
|
||||
}
|
||||
}
|
||||
|
||||
set code(code: string) {
|
||||
this.script = this.isolate.compileScriptSync(code)
|
||||
}
|
||||
|
||||
runScript() {
|
||||
this.script.runSync(this.vm, { timeout: JS_TIMEOUT_MS })
|
||||
}
|
||||
|
||||
copyRefToVm(value: Object): ivm.Copy<Object> {
|
||||
return new ivm.ExternalCopy(value).copyInto({ release: true })
|
||||
}
|
||||
}
|
||||
export default ScriptRunner
|
||||
|
|
|
@ -44,6 +44,8 @@ EXPOSE 4001
|
|||
# due to this causing yarn to stop installing dev dependencies
|
||||
# which are actually needed to get this environment up and running
|
||||
ENV NODE_ENV=production
|
||||
# this is required for isolated-vm to work on Node 20+
|
||||
ENV NODE_OPTIONS="--no-node-snapshot"
|
||||
ENV CLUSTER_MODE=${CLUSTER_MODE}
|
||||
ENV SERVICE=worker-service
|
||||
ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
],
|
||||
"ext": "js,ts,json",
|
||||
"ignore": ["src/**/*.spec.ts", "src/**/*.spec.js", "../*/dist/**/*"],
|
||||
"exec": "yarn build && node dist/index.js"
|
||||
"exec": "yarn build && node --no-node-snapshot dist/index.js"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue