@globocom/backstage-functions-sandbox
Advanced tools
Comparing version 0.5.3 to 0.6.0-next.0
module.exports = require('./lib/Sandbox'); | ||
module.exports.executeFunctionInSandbox = require('./lib/ForkSandbox').executeFunctionInSandbox; | ||
module.exports.PrefixLog = require('./lib/PrefixLog'); | ||
module.exports.MemoryStream = require('./lib/MemoryStream'); |
@@ -67,5 +67,6 @@ const vm = require('vm'); | ||
this.config = config || {}; | ||
this.activeTimers = [] | ||
} | ||
createEmptyContext(backstageOptions, prefix = null, extraEnv = null, console = null) { | ||
createEmptyContext(backstageOptions, prefix = null, extraEnv = null, console = null, objsList={}) { | ||
const exports = {}; | ||
@@ -98,3 +99,12 @@ | ||
this.context.Buffer = Buffer; | ||
this.context.setTimeout = setTimeout; | ||
this.context.setTimeout = (func, delay) => { | ||
const timeoutId = setTimeout(func, delay); | ||
objsList.timerList.push(timeoutId) | ||
return timeoutId | ||
} | ||
this.context.setInterval = (func, interval) => { | ||
const intervalId = setInterval(func, interval); | ||
objsList.intervalList.push(intervalId) | ||
return intervalId | ||
} | ||
this.context.clearTimeout = clearTimeout; | ||
@@ -120,3 +130,4 @@ this.context.exports = exports; | ||
const script = new vm.Script(text, { filename, displayErrors: false, lineOffset: -1 }); | ||
const context = this.createEmptyContext({}, prefix || filename, null, console); | ||
let objsCounter = { intervalList: [], timerList: []} | ||
const context = this.createEmptyContext({}, prefix || filename, null, console, objsCounter); | ||
script.runInContext(context, { timeout: this.syncTimeout }); | ||
@@ -143,2 +154,17 @@ } catch (e) { | ||
hasPendingObjects(objsList) { | ||
return (objsList.timerList.length > 0) || (objsList.intervalList.length > 0); | ||
} | ||
finishPendingObjects(objsList) { | ||
if (!objsList) return; | ||
if (objsList.timerList) { | ||
objsList.timerList.forEach((timeoutId) => clearTimeout(timeoutId)); | ||
} | ||
if (objsList.intervalList) { | ||
objsList.intervalList.forEach((intervalId) => clearInterval(intervalId)); | ||
} | ||
} | ||
runScript(script, req, { prefix, env, console, span } = {}) { | ||
@@ -166,2 +192,3 @@ return new Promise((accept, reject) => { | ||
const sandboxRes = new Response({ callback }); | ||
let objsList = { intervalList: [], timerList: []} | ||
const context = this.createEmptyContext({ | ||
@@ -171,6 +198,7 @@ request: sandboxReq, | ||
span, | ||
}, prefix, env, console); | ||
}, prefix, env, console, objsList); | ||
const vmDomain = domain.create(); | ||
vmDomain.on('error', (err) => { | ||
this.finishPendingObjects(objsList) | ||
callback(err); | ||
@@ -180,2 +208,3 @@ }); | ||
vmDomain.run(() => { | ||
const result = script.runInContext(context, { | ||
@@ -190,2 +219,3 @@ timeout: this.syncTimeout, | ||
.then((body) => { | ||
this.finishPendingObjects(objsList) | ||
sandboxRes.send(body); | ||
@@ -196,3 +226,5 @@ }) | ||
}); | ||
return | ||
} | ||
this.finishPendingObjects(objsList) | ||
}); | ||
@@ -199,0 +231,0 @@ }); |
{ | ||
"name": "@globocom/backstage-functions-sandbox", | ||
"version": "0.5.3", | ||
"version": "0.6.0-next.0", | ||
"description": "Sandbox for Backstage functions", | ||
@@ -30,2 +30,3 @@ "main": "index.js", | ||
"dependencies": { | ||
"node-fetch": "^2.5.0", | ||
"once": "^1.4.0", | ||
@@ -32,0 +33,0 @@ "stack-trace": "^0.0.9" |
@@ -35,2 +35,3 @@ [![Build Status](https://travis-ci.org/globocom/functions-sandbox.png?branch=master)](https://travis-ci.org/globocom/functions-sandbox) | ||
// express.Request compatible | ||
@@ -50,2 +51,46 @@ const req = { | ||
## Example of usage (with child_process) | ||
```javascript | ||
const { executeFunctionInSandbox } = require('backstage-functions-sandbox/lib/ForkSandbox'); | ||
const myCode = ` | ||
async function main(req, res) { | ||
const result = req.body.x * req.body.y; | ||
const name = Backstage.env.MY_VAR; | ||
// you could call await here | ||
return { name, result }; | ||
} | ||
`; | ||
const req = { | ||
headers: {}, | ||
query: {}, | ||
body: { x: 10, y: 10} | ||
}; | ||
const taskId = `${namespace}/${id}-${Date.now()}`; //or can be any uniq id | ||
executeFunctionInSandbox(taskId, { | ||
env: { | ||
MY_VAR: 'TRUE', // environment variable will be available on Backstage.env.MY_VAR | ||
}, | ||
globalModules: [ 'path' ], // put all available modules that will allow to import | ||
asyncTimeout: 10000, | ||
syncTimeout: 300, | ||
preCode: code, // not required to compile using sandbox.Compilecode | ||
req, | ||
namespace: "foo", | ||
functionName: "bar", | ||
options, | ||
}) | ||
/* can return result using callback or using async await */ | ||
.then(result => { | ||
console.log(result) | ||
}) | ||
.catch(err => { | ||
console.log(err) | ||
}) | ||
``` | ||
## Configuration | ||
@@ -52,0 +97,0 @@ |
@@ -69,3 +69,3 @@ const expect = require('chai').expect; | ||
it('should return context with setTimeout', () => { | ||
expect(context.setTimeout).to.equal(setTimeout); | ||
expect(context.setTimeout).to.exist; | ||
}); | ||
@@ -141,3 +141,3 @@ | ||
expect(result.error).to.be.eql('SyntaxError: Unexpected token }'); | ||
expect(result.error).to.be.eql('SyntaxError: Unexpected token \'}\''); | ||
expect(result.stack).to.be.eql(''); | ||
@@ -301,26 +301,2 @@ }); | ||
describe('when code has an error in anonymous function', () => { | ||
it('should resolve promise as rejected', (done) => { | ||
const filename = 'test.js'; | ||
const code = ` | ||
function main(req, res) { | ||
setTimeout(() => { | ||
throw new Error('An error'); | ||
}, 10); | ||
} | ||
`; | ||
const script = testSandbox.compileCode(filename, code); | ||
testSandbox | ||
.runScript(script, {}) | ||
.then(() => { | ||
done(new Error('It is expected an error')); | ||
}, (error) => { | ||
expect(error.message).to.be.eql('An error'); | ||
done(); | ||
}) | ||
.catch(err => done(err)); | ||
}); | ||
}); | ||
describe('when code has an not declared variable', () => { | ||
@@ -327,0 +303,0 @@ it('should resolve promise as rejected by "strict mode"', (done) => { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
279021
30
1228
135
3
6
2
+ Addednode-fetch@^2.5.0
+ Addednode-fetch@2.7.0(transitive)
+ Addedtr46@0.0.3(transitive)
+ Addedwebidl-conversions@3.0.1(transitive)
+ Addedwhatwg-url@5.0.0(transitive)