isolated-function 0.0.6 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/LICENSE.md +0 -0
  2. package/README.md +163 -30
  3. package/package.json +14 -14
package/LICENSE.md CHANGED
File without changes
package/README.md CHANGED
@@ -1,18 +1,37 @@
1
1
  <h3 align="center">
2
- <img src="https://github.com/Kikobeats/isolated-function/blob/master/logo.png?raw=true" width="200">
2
+ <img
3
+ src="https://github.com/Kikobeats/isolated-function/blob/master/logo.png?raw=true"
4
+ width="200">
3
5
  <br>
4
- <p>isolated-functions</p>
5
- <a target="_blank" rel="noopener noreferrer nofollow"><img src="https://img.shields.io/github/tag/Kikobeats/isolated-function.svg?style=flat-square" style="max-width: 100%;"></a>
6
- <a href="https://coveralls.io/github/Kikobeats/isolated-function" rel="nofollow"><img src="https://img.shields.io/coveralls/Kikobeats/isolated-function.svg?style=flat-square" alt="Coverage Status" style="max-width: 100%;"></a>
7
- <a href="https://www.npmjs.org/package/isolated-function" rel="nofollow"><img src="https://img.shields.io/npm/dm/isolated-function.svg?style=flat-square" alt="NPM Status" style="max-width: 100%;"></a>
6
+ <p>isolated-function</p>
7
+ <a target="_blank" rel="noopener noreferrer nofollow"><img
8
+ src="https://img.shields.io/github/tag/Kikobeats/isolated-function.svg?style=flat-square"
9
+ style="max-width: 100%;"></a>
10
+ <a href="https://coveralls.io/github/Kikobeats/isolated-function"
11
+ rel="nofollow"><img
12
+ src="https://img.shields.io/coveralls/Kikobeats/isolated-function.svg?style=flat-square"
13
+ alt="Coverage Status" style="max-width: 100%;"></a>
14
+ <a href="https://www.npmjs.org/package/isolated-function" rel="nofollow"><img
15
+ src="https://img.shields.io/npm/dm/isolated-function.svg?style=flat-square"
16
+ alt="NPM Status" style="max-width: 100%;"></a>
8
17
  </h3>
9
18
 
10
- ## Highlights
11
-
12
- - Based in [Node.js Permission Model](https://nodejs.org/api/permissions.html#permission-model)
13
- - Auto install npm dependencies.
14
- - Memory limit support.
15
- - Timeout support.
19
+ - [Install](#install)
20
+ - [Quickstart](#quickstart)
21
+ - [Minimal privilege execution](#minimal-privilege-execution)
22
+ - [Auto install dependencies](#auto-install-dependencies)
23
+ - [Execution profiling](#execution-profiling)
24
+ - [Resource limits](#resource-limits)
25
+ - [API](#api)
26
+ - [isolatedFunction(code, \[options\])](#isolatedfunctioncode-options)
27
+ - [code](#code)
28
+ - [options](#options)
29
+ - [timeout](#timeout)
30
+ - [timeout](#timeout-1)
31
+ - [=\> (fn(\[...args\]), teardown())](#-fnargs-teardown)
32
+ - [fn](#fn)
33
+ - [teardown](#teardown)
34
+ - [License](#license)
16
35
 
17
36
  ## Install
18
37
 
@@ -20,55 +39,169 @@
20
39
  npm install isolated-function --save
21
40
  ```
22
41
 
23
- ## Usage
42
+ ## Quickstart
43
+
44
+ **isolated-functions** is a modern solution for running arbitrary code using Node.js.
24
45
 
25
46
  ```js
26
47
  const isolatedFunction = require('isolated-function')
27
48
 
28
- /* This function will run in a sandbox, in a separate process */
29
- const sum = isolatedFunction((y, z) => y + z)
49
+ /* create an isolated-function, with resources limitation */
50
+ const [sum, teardown] = isolatedFunction((y, z) => y + z, {
51
+ memory: 128, // in MB
52
+ timeout: 10000 // in milliseconds
53
+ })
30
54
 
31
- /* Interact with it as usual from your main code */
32
- const result = await sum(3, 2)
55
+ /* interact with the isolated-function */
56
+ const [value, profiling] = await sum(3, 2)
57
+ console.log({ value, profiling })
33
58
 
34
- console.log(result)
59
+ /* close resources associated with the isolated-function initialization */
60
+ await teardown()
35
61
  ```
36
62
 
37
- You can also use `require' for external dependencies:
63
+ The hosted code runs in a separate process with limited permissions, returning the result and profiling the execution.
64
+
65
+ ### Minimal privilege execution
66
+
67
+ The hosted code will be executed with minimal privilege. If you exceed your limit, an error will occur.
38
68
 
39
69
  ```js
40
- const isEmoji = isolatedFunction(emoji => {
70
+ const [fn, teardown] = isolatedFunction(() => {
71
+ const fs = require('fs')
72
+ fs.writeFileSync('/etc/passwd', 'foo')
73
+ })
74
+
75
+ await fn()
76
+ // => PermissionError: Access to 'FileSystemWrite' has been restricted.
77
+ ```
78
+
79
+ Any of the following interaction will throw an error:
80
+
81
+ - Native modules
82
+ - Child process
83
+ - Worker Threads
84
+ - Inspector protocol
85
+ - File system access
86
+ - WASI
87
+
88
+ ### Auto install dependencies
89
+
90
+ The hosted code is parsed for detecting `require`/`import` calls and install these dependencies:
91
+
92
+ ```js
93
+ const [isEmoji, teardown] = isolatedFunction(emoji => {
94
+ /* this dependency only exists inside the isolated function */
41
95
  const isEmoji = require('is-standard-emoji')
42
96
  return isEmoji(emoji)
43
97
  })
44
98
 
45
99
  await isEmoji('🙌') // => true
46
100
  await isEmoji('foo') // => false
101
+ await teardown()
102
+ ```
103
+
104
+ The dependencies, along with the hosted code, are bundled into a single file that will be evaluated at runtime.
105
+
106
+ ### Execution profiling
107
+
108
+ Any hosted code execution has a profiling associated:
109
+
110
+ ```js
111
+ /** make a function to consume ~128MB */
112
+ const [fn, teardown] = isolatedFunction(() => {
113
+ const storage = []
114
+ const oneMegabyte = 1024 * 1024
115
+ while (storage.length < 78) {
116
+ const array = new Uint8Array(oneMegabyte)
117
+ for (let ii = 0; ii < oneMegabyte; ii += 4096) {
118
+ array[ii] = 1
119
+ }
120
+ storage.push(array)
121
+ }
122
+ })
123
+ t.teardown(cleanup)
124
+
125
+ const [value, profiling] = await fn()
126
+ console.log(profiling)
127
+ // {
128
+ // memory: 128204800,
129
+ // duration: 54.98325
130
+ // }
131
+ ```
132
+
133
+ ### Resource limits
134
+
135
+ You can limit a **isolated-function** by memory:
136
+
137
+ ```js
138
+ const [fn, teardown] = isolatedFunction(() => {
139
+ const storage = []
140
+ const oneMegabyte = 1024 * 1024
141
+ while (storage.length < 78) {
142
+ const array = new Uint8Array(oneMegabyte)
143
+ for (let ii = 0; ii < oneMegabyte; ii += 4096) {
144
+ array[ii] = 1
145
+ }
146
+ storage.push(array)
147
+ }
148
+ }, { memory: 64 })
149
+
150
+ await fn()
151
+ // => MemoryError: Out of memory
47
152
  ```
48
153
 
49
- The dependencies are bundled with the source code into a single file that is executed in the sandbox.
154
+ or by execution duration:
50
155
 
51
- It's intentionally not possible to expose any Node.js objects or functions directly to the sandbox (such as `process`, or filesystem). This makes it slightly harder to integrate into a project, but has the benefit of guaranteed isolation.
156
+ ```js
157
+ const [fn, teardown] = isolatedFunction(() => {
158
+ const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
159
+ await delay(duration)
160
+ return 'done'
161
+ }, { timeout: 50 })
162
+
163
+ await fn(100)
164
+ // => TimeoutError: Execution timed out
165
+ ```
52
166
 
53
167
  ## API
54
168
 
55
- ### isolatedFunction(snippet, [options])
169
+ ### isolatedFunction(code, [options])
56
170
 
57
- #### snippet
171
+ #### code
58
172
 
59
- *Required*<br>
60
- Type: `string`
173
+ _Required_<br>
174
+ Type: `function`
61
175
 
62
- The source code to run.
176
+ The hosted function to run.
63
177
 
64
178
  #### options
65
179
 
66
- ##### foo
180
+ ##### timeout
181
+
182
+ Type: `number`
183
+
184
+ Timeout after a specified amount of time, in milliseconds.
185
+
186
+ ##### timeout
187
+
188
+ Type: `number`
189
+
190
+ Set the functino memory limit, in megabytes.
191
+
192
+ ### => (fn([...args]), teardown())
193
+
194
+ #### fn
195
+
196
+ Type: `function`
197
+
198
+ The isolated function to execute. You can pass arguments over it.
199
+
200
+ #### teardown
67
201
 
68
- Type: `boolean`<br>
69
- Default: `false`
202
+ Type: `function`
70
203
 
71
- Lorem ipsum.
204
+ A function to be called to release resources associated with the **isolated-function**.
72
205
 
73
206
  ## License
74
207
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "isolated-function",
3
3
  "description": "Runs untrusted code in a Node.js v8 sandbox.",
4
4
  "homepage": "https://github.com/Kikobeats/isolated-function",
5
- "version": "0.0.6",
5
+ "version": "0.1.0",
6
6
  "main": "src/index.js",
7
7
  "exports": {
8
8
  ".": "./src/index.js"
@@ -62,18 +62,6 @@
62
62
  "files": [
63
63
  "src"
64
64
  ],
65
- "scripts": {
66
- "clean": "rm -rf node_modules",
67
- "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
68
- "coverage": "c8 report --reporter=text-lcov > coverage/lcov.info",
69
- "lint": "standard",
70
- "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)",
71
- "pretest": "npm run lint",
72
- "release": "standard-version -a",
73
- "release:github": "github-generate-release",
74
- "release:tags": "git push --follow-tags origin HEAD:master",
75
- "test": "c8 ava"
76
- },
77
65
  "license": "MIT",
78
66
  "commitlint": {
79
67
  "extends": [
@@ -97,5 +85,17 @@
97
85
  "simple-git-hooks": {
98
86
  "commit-msg": "npx commitlint --edit",
99
87
  "pre-commit": "npx nano-staged"
88
+ },
89
+ "scripts": {
90
+ "clean": "rm -rf node_modules",
91
+ "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
92
+ "coverage": "c8 report --reporter=text-lcov > coverage/lcov.info",
93
+ "lint": "standard",
94
+ "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)",
95
+ "pretest": "npm run lint",
96
+ "release": "standard-version -a",
97
+ "release:github": "github-generate-release",
98
+ "release:tags": "git push --follow-tags origin HEAD:master",
99
+ "test": "c8 ava"
100
100
  }
101
- }
101
+ }