Skip to content

Commit

Permalink
Merge branch 'release/5.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
codenirvana committed Jun 19, 2024
2 parents feaa39b + 582bb77 commit 1054908
Show file tree
Hide file tree
Showing 27 changed files with 10,498 additions and 1,020 deletions.
293 changes: 149 additions & 144 deletions .eslintrc

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ on:
schedule:
- cron: '0 12 * * 0'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint:
name: Lint
Expand All @@ -19,10 +23,10 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3

- name: Use Node.js 16.x
- name: Use Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: 16.x
node-version: 18.x
cache: 'npm'

- name: Install
Expand All @@ -39,10 +43,10 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3

- name: Use Node.js 16.x
- name: Use Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: 16.x
node-version: 18.x
cache: 'npm'

- name: Install
Expand All @@ -60,11 +64,11 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [10, 12]
node-version: [16, 18]
os: [ubuntu-latest, windows-latest]
include:
- coverage: true
node-version: 16
node-version: 20
os: ubuntu-latest

steps:
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
5.0.0:
date: 2024-06-19
breaking changes:
- GH-1004 Dropped support for Node < v16
new features:
- GH-999 Improved isolation for executing scripts
- GH-1000 Added support for top-level await in scripts
chores:
- GH-999 Bumped `uvm` dependency
- GH-1004 Updated ESLint rules
- Bumped `xml2js` to `v0.6.2`

4.7.1:
date: 2024-04-03
fixed bugs:
Expand Down
1 change: 0 additions & 1 deletion lib/postman-sandbox-fleet.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ const _ = require('lodash'),
*
* @property {String} [bootCode] Code to be executed inside a UVM on boot
* @property {Number} [timeout] -
* @property {Number} [dispatchTimeout] -
* @property {Boolean} [debug] - Enable console logs inside UVM
*/

Expand Down
100 changes: 49 additions & 51 deletions lib/postman-sandbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,60 +9,46 @@ const _ = require('lodash'),
EXECUTION_TIMEOUT_ERROR_MESSAGE = 'sandbox not responding',
BRIDGE_DISCONNECTING_ERROR_MESSAGE = 'sandbox: execution interrupted, bridge disconnecting.';

let MAIN_MODULE = null,
ACTIVE_INSTANCES = 0;

class PostmanSandbox extends UniversalVM {
constructor () {
super();

this._executing = {};
this._initialized = false;
this.isReady = false;
this.hasTimedOut = false;
}

initialize (initOptions, connectOptions, callback) {
// ensure options is an object and is shallow cloned
initOptions = _.assign({}, initOptions);
connectOptions = _.assign({}, connectOptions);

this.debug = Boolean(connectOptions.debug);

// Modify mainModule to prevent access to the Module object
if (!MAIN_MODULE && typeof process === 'object' && process.mainModule) {
MAIN_MODULE = process.mainModule;
process.mainModule = {
..._.pick(process.mainModule, ['id', 'path', 'paths', 'filename', 'loaded']),
exports: {},
children: [],
parent: null
};
}
this.initOptions = _.assign({}, initOptions);
this.connectOptions = _.assign({}, connectOptions);

this.debug = Boolean(this.connectOptions.debug);

// set the dispatch timeout of UVM based on what is set in options unless original options sends the same
_.isFinite(connectOptions.timeout) &&
(connectOptions.dispatchTimeout = this.executionTimeout = connectOptions.timeout);
_.isFinite(this.connectOptions.timeout) && (this.executionTimeout = this.connectOptions.timeout);

super.connect(connectOptions, (err, context) => {
super.connect(this.connectOptions, (err, context) => {
if (err) { return callback(err); }

this.once('initialize', (err) => {
this._initialized = !err;
ACTIVE_INSTANCES++;
this.isReady = true;
this.hasTimedOut = false;

this.on(CONSOLE_EVENT_NAME, (cursor, level, args) => {
if (connectOptions.serializeLogs) {
if (this.connectOptions.serializeLogs) {
return this.emit('console', cursor, level, args);
}

this.emit('console', cursor, level, ...teleportJS.parse(args));
});

// eslint-disable-next-line callback-return
// eslint-disable-next-line n/callback-return
callback(err, context);
context = null;
});

this.dispatch('initialize', initOptions);
this.dispatch('initialize', this.initOptions);
});
}

Expand Down Expand Up @@ -111,7 +97,18 @@ class PostmanSandbox extends UniversalVM {
executionTimeout = _.get(options, 'timeout', this.executionTimeout),
cursor = _.clone(_.get(options, 'cursor', {})), // clone the cursor as it travels through IPC for mutation
resolvedPackages = _.get(options, 'resolvedPackages'),
debugMode = _.has(options, 'debug') ? options.debug : this.debug;
debugMode = _.has(options, 'debug') ? options.debug : this.debug,

// send the code to the sandbox to be intercepted and executed
dispatchExecute = () => {
this.dispatch('execute', id, target, _.get(options, 'context', {}), {
cursor: cursor,
debug: debugMode,
timeout: executionTimeout,
resolvedPackages: resolvedPackages,
legacy: _.get(options, 'legacy')
});
};

let waiting;

Expand All @@ -122,38 +119,46 @@ class PostmanSandbox extends UniversalVM {
// force trigger of the `execution.${id}` event so that the normal error flow is taken
this._executing[id] = _.isFinite(executionTimeout) ? (waiting = setTimeout(() => {
waiting = null;
this.emit.bind(executionEventName, new Error(EXECUTION_TIMEOUT_ERROR_MESSAGE));
this.hasTimedOut = true;
this.emit(executionEventName, new Error(EXECUTION_TIMEOUT_ERROR_MESSAGE));
}, executionTimeout + TO_WAIT_BUFFER)) : null;

// @todo decide how the results will return in a more managed fashion
// listen to this once, so that subsequent calls are simply dropped. especially during timeout and other
// errors
this.once(executionEventName, (err, result) => {
waiting && (waiting = clearTimeout(waiting)); // clear timeout interrupt
if (Object.hasOwnProperty.call(this._executing, id)) { // clear any pending timeouts
if (Object.hasOwn(this._executing, id)) { // clear any pending timeouts
this._executing[id] && clearTimeout(this._executing[id]);
delete this._executing[id];
}

this.emit('execution', err, id, result);

// Dispose the current context to
// interrupt the execution when timed out
waiting === null && this.dispose();

callback(err, result);
});

// send the code to the sandbox to be intercepted and executed
this.dispatch('execute', id, target, _.get(options, 'context', {}), {
cursor: cursor,
debug: debugMode,
timeout: executionTimeout,
resolvedPackages: resolvedPackages,
legacy: _.get(options, 'legacy')
});
}
if (this.isReady || !this.hasTimedOut) {
dispatchExecute();

dispose () {
if (!this._initialized) {
return;
}

// Re-initialize the sandbox if it is not already.This can
// happen if a previous execution was interrupted due to a timeout.
this.initialize(this.initOptions, this.connectOptions, (err) => {
if (err) { return callback(err); }
dispatchExecute();
});
}

dispose (callback) {
this.isReady = false;

_.forEach(this._executing, (irq, id) => {
irq && clearTimeout(irq);

Expand All @@ -166,16 +171,9 @@ class PostmanSandbox extends UniversalVM {
});

this.removeAllListeners(CONSOLE_EVENT_NAME);
this.disconnect();

this._initialized = false;
ACTIVE_INSTANCES--;

// reset the mainModule to its original value
if (ACTIVE_INSTANCES === 0 && MAIN_MODULE) {
process.mainModule = MAIN_MODULE;
MAIN_MODULE = null;
}
this.disconnect(() => {
typeof callback === 'function' && callback();
});
}
}

Expand Down
Loading

0 comments on commit 1054908

Please sign in to comment.