isolated-function 0.0.5 → 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 +167 -31
  3. package/package.json +14 -14
package/LICENSE.md CHANGED
File without changes
package/README.md CHANGED
@@ -1,15 +1,37 @@
1
- # isolated-function
2
-
3
- ![Last version](https://img.shields.io/github/tag/Kikobeats/isolated-function.svg?style=flat-square)
4
- [![Coverage Status](https://img.shields.io/coveralls/Kikobeats/isolated-function.svg?style=flat-square)](https://coveralls.io/github/Kikobeats/isolated-function)
5
- [![NPM Status](https://img.shields.io/npm/dm/isolated-function.svg?style=flat-square)](https://www.npmjs.org/package/isolated-function)
6
-
7
- **Highlights**
8
-
9
- - Based in [Node.js Permission Model](https://nodejs.org/api/permissions.html#permission-model)
10
- - Auto install npm dependencies.
11
- - Memory limit support.
12
- - Timeout support.
1
+ <h3 align="center">
2
+ <img
3
+ src="https://github.com/Kikobeats/isolated-function/blob/master/logo.png?raw=true"
4
+ width="200">
5
+ <br>
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>
17
+ </h3>
18
+
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)
13
35
 
14
36
  ## Install
15
37
 
@@ -17,55 +39,169 @@
17
39
  npm install isolated-function --save
18
40
  ```
19
41
 
20
- ## Usage
42
+ ## Quickstart
43
+
44
+ **isolated-functions** is a modern solution for running arbitrary code using Node.js.
21
45
 
22
46
  ```js
23
47
  const isolatedFunction = require('isolated-function')
24
48
 
25
- /* This function will run in a sandbox, in a separate process */
26
- 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
+ })
54
+
55
+ /* interact with the isolated-function */
56
+ const [value, profiling] = await sum(3, 2)
57
+ console.log({ value, profiling })
58
+
59
+ /* close resources associated with the isolated-function initialization */
60
+ await teardown()
61
+ ```
62
+
63
+ The hosted code runs in a separate process with limited permissions, returning the result and profiling the execution.
64
+
65
+ ### Minimal privilege execution
27
66
 
28
- /* Interact with it as usual from your main code */
29
- const result = await sum(3, 2)
67
+ The hosted code will be executed with minimal privilege. If you exceed your limit, an error will occur.
30
68
 
31
- console.log(result)
69
+ ```js
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.
32
77
  ```
33
78
 
34
- You can also use `require' for external dependencies:
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:
35
91
 
36
92
  ```js
37
- const isEmoji = isolatedFunction(emoji => {
93
+ const [isEmoji, teardown] = isolatedFunction(emoji => {
94
+ /* this dependency only exists inside the isolated function */
38
95
  const isEmoji = require('is-standard-emoji')
39
96
  return isEmoji(emoji)
40
97
  })
41
98
 
42
99
  await isEmoji('🙌') // => true
43
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
44
152
  ```
45
153
 
46
- The dependencies are bundled with the source code into a single file that is executed in the sandbox.
154
+ or by execution duration:
47
155
 
48
- 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
+ ```
49
166
 
50
167
  ## API
51
168
 
52
- ### isolatedFunction(snippet, [options])
169
+ ### isolatedFunction(code, [options])
53
170
 
54
- #### snippet
171
+ #### code
55
172
 
56
- *Required*<br>
57
- Type: `string`
173
+ _Required_<br>
174
+ Type: `function`
58
175
 
59
- The source code to run.
176
+ The hosted function to run.
60
177
 
61
178
  #### options
62
179
 
63
- ##### 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
64
201
 
65
- Type: `boolean`<br>
66
- Default: `false`
202
+ Type: `function`
67
203
 
68
- Lorem ipsum.
204
+ A function to be called to release resources associated with the **isolated-function**.
69
205
 
70
206
  ## License
71
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.5",
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
+ }