@n8n/expression-runtime 0.2.0 → 0.3.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.
- package/ARCHITECTURE.md +5 -6
- package/LICENSE_EE.md +27 -0
- package/README.md +8 -8
- package/dist/bridge/isolated-vm-bridge.d.ts +132 -0
- package/dist/bridge/isolated-vm-bridge.d.ts.map +1 -0
- package/dist/bridge/isolated-vm-bridge.js +427 -0
- package/dist/bridge/isolated-vm-bridge.js.map +1 -0
- package/dist/build.tsbuildinfo +1 -1
- package/dist/bundle/runtime.esm.js +45 -0
- package/dist/bundle/runtime.esm.js.map +7 -0
- package/dist/bundle/runtime.iife.js +45 -0
- package/dist/bundle/runtime.iife.js.map +7 -0
- package/dist/extensions/array-extensions.d.ts +34 -0
- package/dist/extensions/array-extensions.d.ts.map +1 -0
- package/dist/extensions/array-extensions.js +610 -0
- package/dist/extensions/array-extensions.js.map +1 -0
- package/dist/extensions/boolean-extensions.d.ts +6 -0
- package/dist/extensions/boolean-extensions.d.ts.map +1 -0
- package/dist/extensions/boolean-extensions.js +33 -0
- package/dist/extensions/boolean-extensions.js.map +1 -0
- package/dist/extensions/date-extensions.d.ts +3 -0
- package/dist/extensions/date-extensions.d.ts.map +1 -0
- package/dist/extensions/date-extensions.js +515 -0
- package/dist/extensions/date-extensions.js.map +1 -0
- package/dist/extensions/expression-extension-error.d.ts +7 -0
- package/dist/extensions/expression-extension-error.d.ts.map +1 -0
- package/dist/extensions/expression-extension-error.js +11 -0
- package/dist/extensions/expression-extension-error.js.map +1 -0
- package/dist/extensions/extend.d.ts +12 -0
- package/dist/extensions/extend.d.ts.map +1 -0
- package/dist/extensions/extend.js +134 -0
- package/dist/extensions/extend.js.map +1 -0
- package/dist/extensions/extensions.d.ts +43 -0
- package/dist/extensions/extensions.d.ts.map +1 -0
- package/dist/extensions/extensions.js +2 -0
- package/dist/extensions/extensions.js.map +1 -0
- package/dist/extensions/number-extensions.d.ts +27 -0
- package/dist/extensions/number-extensions.d.ts.map +1 -0
- package/dist/extensions/number-extensions.js +221 -0
- package/dist/extensions/number-extensions.js.map +1 -0
- package/dist/extensions/object-extensions.d.ts +46 -0
- package/dist/extensions/object-extensions.d.ts.map +1 -0
- package/dist/extensions/object-extensions.js +277 -0
- package/dist/extensions/object-extensions.js.map +1 -0
- package/dist/extensions/string-extensions.d.ts +38 -0
- package/dist/extensions/string-extensions.d.ts.map +1 -0
- package/dist/extensions/string-extensions.js +735 -0
- package/dist/extensions/string-extensions.js.map +1 -0
- package/dist/extensions/utils.d.ts +4 -0
- package/dist/extensions/utils.d.ts.map +1 -0
- package/dist/extensions/utils.js +27 -0
- package/dist/extensions/utils.js.map +1 -0
- package/dist/runtime/index.d.ts +17 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +23 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/lazy-proxy.d.ts +18 -0
- package/dist/runtime/lazy-proxy.d.ts.map +1 -0
- package/dist/runtime/lazy-proxy.js +150 -0
- package/dist/runtime/lazy-proxy.js.map +1 -0
- package/dist/runtime/reset.d.ts +16 -0
- package/dist/runtime/reset.d.ts.map +1 -0
- package/dist/runtime/reset.js +124 -0
- package/dist/runtime/reset.js.map +1 -0
- package/dist/runtime/safe-globals.d.ts +21 -0
- package/dist/runtime/safe-globals.d.ts.map +1 -0
- package/dist/runtime/safe-globals.js +110 -0
- package/dist/runtime/safe-globals.js.map +1 -0
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/runtime.d.ts +0 -102
- package/dist/types/runtime.d.ts.map +1 -1
- package/dist/types/runtime.js +0 -6
- package/dist/types/runtime.js.map +1 -1
- package/package.json +15 -3
package/ARCHITECTURE.md
CHANGED
|
@@ -306,7 +306,7 @@ packages/@n8n/expression-runtime/
|
|
|
306
306
|
|
|
307
307
|
**Future-Proofing**: Frontend will use Web Workers. Backend uses isolated-vm. Abstract bridge allows adding new environments without changing other layers.
|
|
308
308
|
|
|
309
|
-
**Testing**:
|
|
309
|
+
**Testing**: Integration tests use `IsolatedVmBridge` directly (see `src/__tests__/integration.test.ts`).
|
|
310
310
|
|
|
311
311
|
## Known Limitations
|
|
312
312
|
|
|
@@ -361,16 +361,15 @@ The runtime has **no access** to:
|
|
|
361
361
|
- ❌ Cookies
|
|
362
362
|
|
|
363
363
|
The runtime **can only**:
|
|
364
|
-
- ✅ Call `
|
|
364
|
+
- ✅ Call back to host via `ivm.Reference` callbacks to fetch workflow data
|
|
365
365
|
- ✅ Access lodash and Luxon libraries
|
|
366
366
|
- ✅ Execute pure JavaScript code
|
|
367
367
|
|
|
368
368
|
## Testing Strategy
|
|
369
369
|
|
|
370
|
-
**
|
|
371
|
-
- Use
|
|
372
|
-
- Test lazy loading, helpers, error handling
|
|
373
|
-
- No native dependencies required
|
|
370
|
+
**Integration Tests** (vitest):
|
|
371
|
+
- Use `IsolatedVmBridge` with real `isolated-vm`
|
|
372
|
+
- Test lazy loading, helpers, error handling, security wrappers
|
|
374
373
|
|
|
375
374
|
**Bridge Tests** (vitest):
|
|
376
375
|
- Test each bridge implementation
|
package/LICENSE_EE.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# The n8n Enterprise License (the “Enterprise License”)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022-present n8n GmbH.
|
|
4
|
+
|
|
5
|
+
With regard to the n8n Software:
|
|
6
|
+
|
|
7
|
+
This software and associated documentation files (the "Software") may only be used in production, if
|
|
8
|
+
you (and any entity that you represent) hold a valid n8n Enterprise license corresponding to your
|
|
9
|
+
usage. Subject to the foregoing sentence, you are free to modify this Software and publish patches
|
|
10
|
+
to the Software. You agree that n8n and/or its licensors (as applicable) retain all right, title and
|
|
11
|
+
interest in and to all such modifications and/or patches, and all such modifications and/or patches
|
|
12
|
+
may only be used, copied, modified, displayed, distributed, or otherwise exploited with a valid n8n
|
|
13
|
+
Enterprise license for the corresponding usage. Notwithstanding the foregoing, you may copy and
|
|
14
|
+
modify the Software for development and testing purposes, without requiring a subscription. You
|
|
15
|
+
agree that n8n and/or its licensors (as applicable) retain all right, title and interest in and to
|
|
16
|
+
all such modifications. You are not granted any other rights beyond what is expressly stated herein.
|
|
17
|
+
Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense, and/or
|
|
18
|
+
sell the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
|
21
|
+
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
22
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
|
23
|
+
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
24
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
25
|
+
|
|
26
|
+
For all third party components incorporated into the n8n Software, those components are licensed
|
|
27
|
+
under the original license provided by the owner of the applicable component.
|
package/README.md
CHANGED
|
@@ -7,12 +7,12 @@ Secure, isolated expression evaluation runtime for n8n workflows.
|
|
|
7
7
|
**In progress — landing as a series of incremental PRs.**
|
|
8
8
|
|
|
9
9
|
Implemented so far:
|
|
10
|
-
- ✅ TypeScript interfaces and architecture design
|
|
11
|
-
- ✅ Core architecture documentation
|
|
10
|
+
- ✅ TypeScript interfaces and architecture design (PR 1)
|
|
11
|
+
- ✅ Core architecture documentation (PR 1)
|
|
12
|
+
- ✅ Runtime bundle: extension functions, deep lazy proxy system (PR 2)
|
|
13
|
+
- ✅ `IsolatedVmBridge`: V8 isolate management via `isolated-vm` (PR 3)
|
|
12
14
|
|
|
13
15
|
Coming in later PRs:
|
|
14
|
-
- 🚧 Runtime bundle: extension functions, deep lazy proxy system (PR 2)
|
|
15
|
-
- 🚧 `IsolatedVmBridge`: V8 isolate management via `isolated-vm` (PR 3)
|
|
16
16
|
- 🚧 `ExpressionEvaluator`: tournament integration, expression code caching (PR 4)
|
|
17
17
|
- 🚧 Integration tests (PR 4)
|
|
18
18
|
- 🚧 Workflow integration behind `N8N_EXPRESSION_ENGINE=vm` flag (PR 5)
|
|
@@ -165,7 +165,7 @@ interface RuntimeBridge {
|
|
|
165
165
|
|
|
166
166
|
### Bridge Implementations
|
|
167
167
|
|
|
168
|
-
- **IsolatedVmBridge**:
|
|
168
|
+
- **IsolatedVmBridge**: ✅ For Node.js backend (isolated-vm with V8 isolates)
|
|
169
169
|
- Memory isolation with hard 128MB limit
|
|
170
170
|
- Timeout enforcement (5s default)
|
|
171
171
|
- Deep lazy proxy system for workflow data
|
|
@@ -185,9 +185,9 @@ interface EvaluatorConfig {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
interface BridgeConfig {
|
|
188
|
-
memoryLimit?: number; // Default: 128 MB
|
|
189
|
-
timeout?: number; // Default: 5000 ms
|
|
190
|
-
debug?: boolean; // Default: false
|
|
188
|
+
memoryLimit?: number; // Default: 128 MB
|
|
189
|
+
timeout?: number; // Default: 5000 ms
|
|
190
|
+
debug?: boolean; // Default: false
|
|
191
191
|
}
|
|
192
192
|
```
|
|
193
193
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { RuntimeBridge, BridgeConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* IsolatedVmBridge - Runtime bridge using isolated-vm for secure expression evaluation.
|
|
4
|
+
*
|
|
5
|
+
* This bridge creates a V8 isolate with:
|
|
6
|
+
* - Hard memory limit (128MB default)
|
|
7
|
+
* - No access to Node.js APIs
|
|
8
|
+
* - Timeout enforcement
|
|
9
|
+
* - Complete isolation from host process
|
|
10
|
+
*
|
|
11
|
+
* Context reuse pattern: Create isolate/context once, reset state between evaluations.
|
|
12
|
+
*/
|
|
13
|
+
export declare class IsolatedVmBridge implements RuntimeBridge {
|
|
14
|
+
private isolate;
|
|
15
|
+
private context?;
|
|
16
|
+
private initialized;
|
|
17
|
+
private disposed;
|
|
18
|
+
private config;
|
|
19
|
+
private scriptCache;
|
|
20
|
+
private valueAtPathRef?;
|
|
21
|
+
private arrayElementRef?;
|
|
22
|
+
private callFunctionRef?;
|
|
23
|
+
constructor(config?: BridgeConfig);
|
|
24
|
+
/**
|
|
25
|
+
* Initialize the isolate and create execution context.
|
|
26
|
+
*
|
|
27
|
+
* Steps:
|
|
28
|
+
* 1. Create context
|
|
29
|
+
* 2. Set up basic globals (global reference)
|
|
30
|
+
* 3. Load runtime bundle (DateTime, extend, proxy system)
|
|
31
|
+
* 4. Verify proxy system
|
|
32
|
+
*
|
|
33
|
+
* Must be called before execute().
|
|
34
|
+
*/
|
|
35
|
+
initialize(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Load runtime bundle into the isolate.
|
|
38
|
+
*
|
|
39
|
+
* The runtime bundle includes:
|
|
40
|
+
* - DateTime, extend, extendOptional (expression engine globals)
|
|
41
|
+
* - SafeObject and SafeError wrappers
|
|
42
|
+
* - createDeepLazyProxy function
|
|
43
|
+
* - __data object initialization
|
|
44
|
+
*
|
|
45
|
+
* @private
|
|
46
|
+
* @throws {Error} If context not initialized or bundle loading fails
|
|
47
|
+
*/
|
|
48
|
+
private loadVendorLibraries;
|
|
49
|
+
/**
|
|
50
|
+
* Verify the proxy system loaded correctly.
|
|
51
|
+
*
|
|
52
|
+
* The proxy system is loaded as part of the runtime bundle in loadVendorLibraries().
|
|
53
|
+
* This method verifies all required components are available.
|
|
54
|
+
*
|
|
55
|
+
* @private
|
|
56
|
+
* @throws {Error} If context not initialized or proxy system verification fails
|
|
57
|
+
*/
|
|
58
|
+
private verifyProxySystem;
|
|
59
|
+
/**
|
|
60
|
+
* Inject the E() error handler into the isolate context.
|
|
61
|
+
*
|
|
62
|
+
* Tournament wraps expressions with try-catch that calls E(error, this).
|
|
63
|
+
* This handler:
|
|
64
|
+
* - Re-throws security violations from __sanitize
|
|
65
|
+
* - Swallows TypeErrors (failed attack attempts return undefined)
|
|
66
|
+
* - Re-throws all other errors
|
|
67
|
+
*
|
|
68
|
+
* @private
|
|
69
|
+
* @throws {Error} If context not initialized
|
|
70
|
+
*/
|
|
71
|
+
private injectErrorHandler;
|
|
72
|
+
/**
|
|
73
|
+
* Reset data proxies in the isolate context.
|
|
74
|
+
*
|
|
75
|
+
* This method should be called before each execute() to:
|
|
76
|
+
* 1. Clear proxy caches from previous evaluations
|
|
77
|
+
* 2. Initialize fresh workflow data references
|
|
78
|
+
* 3. Expose workflow properties to globalThis
|
|
79
|
+
*
|
|
80
|
+
* The reset function runs in the isolate and calls back to the host
|
|
81
|
+
* via ivm.Reference callbacks to fetch workflow data.
|
|
82
|
+
*
|
|
83
|
+
* @private
|
|
84
|
+
* @throws {Error} If context not initialized or reset fails
|
|
85
|
+
*/
|
|
86
|
+
private resetDataProxies;
|
|
87
|
+
/**
|
|
88
|
+
* Register callback functions for cross-isolate communication.
|
|
89
|
+
*
|
|
90
|
+
* Creates three ivm.Reference callbacks that the runtime bundle uses
|
|
91
|
+
* to fetch data from the host process:
|
|
92
|
+
*
|
|
93
|
+
* - __getValueAtPath: Returns metadata or primitive for a property path
|
|
94
|
+
* - __getArrayElement: Returns individual array elements
|
|
95
|
+
* - __callFunctionAtPath: Executes functions in host context
|
|
96
|
+
*
|
|
97
|
+
* These callbacks are called synchronously from isolate proxy traps.
|
|
98
|
+
*
|
|
99
|
+
* @param data - Current workflow data to use for callback responses
|
|
100
|
+
* @private
|
|
101
|
+
*/
|
|
102
|
+
private registerCallbacks;
|
|
103
|
+
/**
|
|
104
|
+
* Execute JavaScript code in the isolated context.
|
|
105
|
+
*
|
|
106
|
+
* Flow:
|
|
107
|
+
* 1. Register callbacks as ivm.Reference for cross-isolate communication
|
|
108
|
+
* 2. Call resetDataProxies() to initialize workflow data proxies
|
|
109
|
+
* 3. Compile script (with caching for performance)
|
|
110
|
+
* 4. Execute with timeout enforcement
|
|
111
|
+
* 5. Return result (copied from isolate)
|
|
112
|
+
*
|
|
113
|
+
* @param code - JavaScript expression to evaluate
|
|
114
|
+
* @param data - Workflow data (e.g., { $json: {...}, $runIndex: 0 })
|
|
115
|
+
* @returns Result of the expression
|
|
116
|
+
* @throws {Error} If bridge not initialized or execution fails
|
|
117
|
+
*/
|
|
118
|
+
execute(code: string, data: Record<string, unknown>): unknown;
|
|
119
|
+
/**
|
|
120
|
+
* Dispose of the isolate and free resources.
|
|
121
|
+
*
|
|
122
|
+
* After disposal, the bridge cannot be used again.
|
|
123
|
+
*/
|
|
124
|
+
dispose(): Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* Check if the bridge has been disposed.
|
|
127
|
+
*
|
|
128
|
+
* @returns true if disposed, false otherwise
|
|
129
|
+
*/
|
|
130
|
+
isDisposed(): boolean;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=isolated-vm-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isolated-vm-bridge.d.ts","sourceRoot":"","sources":["../../src/bridge/isolated-vm-bridge.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAM5D;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,YAAW,aAAa;IACrD,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,OAAO,CAAC,CAAc;IAC9B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAyB;IAIvC,OAAO,CAAC,WAAW,CAAiC;IAIpD,OAAO,CAAC,cAAc,CAAC,CAAgB;IACvC,OAAO,CAAC,eAAe,CAAC,CAAgB;IACxC,OAAO,CAAC,eAAe,CAAC,CAAgB;gBAE5B,MAAM,GAAE,YAAiB;IAYrC;;;;;;;;;;OAUG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgCjC;;;;;;;;;;;OAWG;YACW,mBAAmB;IAsCjC;;;;;;;;OAQG;YACW,iBAAiB;IA+B/B;;;;;;;;;;;OAWG;YACW,kBAAkB;IA0BhC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,gBAAgB;IAmBxB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,iBAAiB;IA8HzB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IA6C7D;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB9B;;;;OAIG;IACH,UAAU,IAAI,OAAO;CAGrB"}
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import ivm from 'isolated-vm';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
// Get __dirname equivalent for ES modules
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
/**
|
|
9
|
+
* IsolatedVmBridge - Runtime bridge using isolated-vm for secure expression evaluation.
|
|
10
|
+
*
|
|
11
|
+
* This bridge creates a V8 isolate with:
|
|
12
|
+
* - Hard memory limit (128MB default)
|
|
13
|
+
* - No access to Node.js APIs
|
|
14
|
+
* - Timeout enforcement
|
|
15
|
+
* - Complete isolation from host process
|
|
16
|
+
*
|
|
17
|
+
* Context reuse pattern: Create isolate/context once, reset state between evaluations.
|
|
18
|
+
*/
|
|
19
|
+
export class IsolatedVmBridge {
|
|
20
|
+
isolate;
|
|
21
|
+
context;
|
|
22
|
+
initialized = false;
|
|
23
|
+
disposed = false;
|
|
24
|
+
config;
|
|
25
|
+
// Script compilation cache for performance
|
|
26
|
+
// Maps expression code -> compiled ivm.Script
|
|
27
|
+
scriptCache = new Map();
|
|
28
|
+
// Active ivm.Reference callbacks — released before each re-registration
|
|
29
|
+
// to prevent reference accumulation across execute() calls
|
|
30
|
+
valueAtPathRef;
|
|
31
|
+
arrayElementRef;
|
|
32
|
+
callFunctionRef;
|
|
33
|
+
constructor(config = {}) {
|
|
34
|
+
this.config = {
|
|
35
|
+
memoryLimit: config.memoryLimit ?? 128,
|
|
36
|
+
timeout: config.timeout ?? 5000,
|
|
37
|
+
debug: config.debug ?? false,
|
|
38
|
+
};
|
|
39
|
+
// Create isolate with memory limit
|
|
40
|
+
// Note: memoryLimit is in MB
|
|
41
|
+
this.isolate = new ivm.Isolate({ memoryLimit: this.config.memoryLimit });
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Initialize the isolate and create execution context.
|
|
45
|
+
*
|
|
46
|
+
* Steps:
|
|
47
|
+
* 1. Create context
|
|
48
|
+
* 2. Set up basic globals (global reference)
|
|
49
|
+
* 3. Load runtime bundle (DateTime, extend, proxy system)
|
|
50
|
+
* 4. Verify proxy system
|
|
51
|
+
*
|
|
52
|
+
* Must be called before execute().
|
|
53
|
+
*/
|
|
54
|
+
async initialize() {
|
|
55
|
+
if (this.initialized) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Create context in the isolate
|
|
59
|
+
this.context = await this.isolate.createContext();
|
|
60
|
+
// Set up basic globals
|
|
61
|
+
// jail is a reference to the context's global object
|
|
62
|
+
const jail = this.context.global;
|
|
63
|
+
// Set 'global' to reference itself (pattern from POC)
|
|
64
|
+
// This allows code in isolate to access 'global.something'
|
|
65
|
+
await jail.set('global', jail.derefInto());
|
|
66
|
+
// Load runtime bundle (DateTime, extend, SafeObject, proxy system)
|
|
67
|
+
await this.loadVendorLibraries();
|
|
68
|
+
// Verify proxy system loaded correctly
|
|
69
|
+
await this.verifyProxySystem();
|
|
70
|
+
// Inject E() error handler needed by tournament-generated try-catch code
|
|
71
|
+
await this.injectErrorHandler();
|
|
72
|
+
this.initialized = true;
|
|
73
|
+
if (this.config.debug) {
|
|
74
|
+
console.log('[IsolatedVmBridge] Initialized successfully');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Load runtime bundle into the isolate.
|
|
79
|
+
*
|
|
80
|
+
* The runtime bundle includes:
|
|
81
|
+
* - DateTime, extend, extendOptional (expression engine globals)
|
|
82
|
+
* - SafeObject and SafeError wrappers
|
|
83
|
+
* - createDeepLazyProxy function
|
|
84
|
+
* - __data object initialization
|
|
85
|
+
*
|
|
86
|
+
* @private
|
|
87
|
+
* @throws {Error} If context not initialized or bundle loading fails
|
|
88
|
+
*/
|
|
89
|
+
async loadVendorLibraries() {
|
|
90
|
+
if (!this.context) {
|
|
91
|
+
throw new Error('Context not initialized');
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
// Load runtime bundle (includes vendor libraries + proxy system)
|
|
95
|
+
// Path: dist/bundle/runtime.iife.js
|
|
96
|
+
const runtimeBundlePath = path.join(__dirname, '../../dist/bundle/runtime.iife.js');
|
|
97
|
+
const runtimeBundle = await readFile(runtimeBundlePath, 'utf-8');
|
|
98
|
+
// Evaluate bundle in isolate context
|
|
99
|
+
// This makes all exported globals available (DateTime, extend, extendOptional, SafeObject, SafeError, createDeepLazyProxy, resetDataProxies, __data)
|
|
100
|
+
await this.context.eval(runtimeBundle);
|
|
101
|
+
if (this.config.debug) {
|
|
102
|
+
console.log('[IsolatedVmBridge] Runtime bundle loaded from:', runtimeBundlePath);
|
|
103
|
+
}
|
|
104
|
+
// Verify vendor libraries loaded correctly
|
|
105
|
+
const hasDateTime = await this.context.eval('typeof DateTime !== "undefined"');
|
|
106
|
+
const hasExtend = await this.context.eval('typeof extend !== "undefined"');
|
|
107
|
+
if (!hasDateTime || !hasExtend) {
|
|
108
|
+
throw new Error(`Library verification failed: DateTime=${hasDateTime}, extend=${hasExtend}`);
|
|
109
|
+
}
|
|
110
|
+
if (this.config.debug) {
|
|
111
|
+
console.log('[IsolatedVmBridge] Vendor libraries verified successfully');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
116
|
+
throw new Error(`Failed to load runtime bundle: ${errorMessage}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Verify the proxy system loaded correctly.
|
|
121
|
+
*
|
|
122
|
+
* The proxy system is loaded as part of the runtime bundle in loadVendorLibraries().
|
|
123
|
+
* This method verifies all required components are available.
|
|
124
|
+
*
|
|
125
|
+
* @private
|
|
126
|
+
* @throws {Error} If context not initialized or proxy system verification fails
|
|
127
|
+
*/
|
|
128
|
+
async verifyProxySystem() {
|
|
129
|
+
if (!this.context) {
|
|
130
|
+
throw new Error('Context not initialized');
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
// Verify proxy system components loaded correctly
|
|
134
|
+
const hasProxyCreator = await this.context.eval('typeof createDeepLazyProxy !== "undefined"');
|
|
135
|
+
const hasData = await this.context.eval('typeof __data !== "undefined"');
|
|
136
|
+
const hasSafeObject = await this.context.eval('typeof SafeObject !== "undefined"');
|
|
137
|
+
const hasSafeError = await this.context.eval('typeof SafeError !== "undefined"');
|
|
138
|
+
const hasResetFunction = await this.context.eval('typeof resetDataProxies !== "undefined"');
|
|
139
|
+
if (!hasProxyCreator || !hasData || !hasSafeObject || !hasSafeError || !hasResetFunction) {
|
|
140
|
+
throw new Error(`Proxy system verification failed: ` +
|
|
141
|
+
`createDeepLazyProxy=${hasProxyCreator}, __data=${hasData}, ` +
|
|
142
|
+
`SafeObject=${hasSafeObject}, SafeError=${hasSafeError}, ` +
|
|
143
|
+
`resetDataProxies=${hasResetFunction}`);
|
|
144
|
+
}
|
|
145
|
+
if (this.config.debug) {
|
|
146
|
+
console.log('[IsolatedVmBridge] Proxy system verified successfully');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
151
|
+
throw new Error(`Failed to verify proxy system: ${errorMessage}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Inject the E() error handler into the isolate context.
|
|
156
|
+
*
|
|
157
|
+
* Tournament wraps expressions with try-catch that calls E(error, this).
|
|
158
|
+
* This handler:
|
|
159
|
+
* - Re-throws security violations from __sanitize
|
|
160
|
+
* - Swallows TypeErrors (failed attack attempts return undefined)
|
|
161
|
+
* - Re-throws all other errors
|
|
162
|
+
*
|
|
163
|
+
* @private
|
|
164
|
+
* @throws {Error} If context not initialized
|
|
165
|
+
*/
|
|
166
|
+
async injectErrorHandler() {
|
|
167
|
+
if (!this.context) {
|
|
168
|
+
throw new Error('Context not initialized');
|
|
169
|
+
}
|
|
170
|
+
await this.context.eval(`
|
|
171
|
+
if (typeof E === 'undefined') {
|
|
172
|
+
globalThis.E = function(error, _context) {
|
|
173
|
+
// Re-throw security violations from __sanitize
|
|
174
|
+
if (error && error.message && error.message.includes('due to security concerns')) {
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
// Swallow TypeErrors (failed attack attempts return undefined)
|
|
178
|
+
if (error instanceof TypeError) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
throw error;
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
`);
|
|
185
|
+
if (this.config.debug) {
|
|
186
|
+
console.log('[IsolatedVmBridge] Error handler injected successfully');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Reset data proxies in the isolate context.
|
|
191
|
+
*
|
|
192
|
+
* This method should be called before each execute() to:
|
|
193
|
+
* 1. Clear proxy caches from previous evaluations
|
|
194
|
+
* 2. Initialize fresh workflow data references
|
|
195
|
+
* 3. Expose workflow properties to globalThis
|
|
196
|
+
*
|
|
197
|
+
* The reset function runs in the isolate and calls back to the host
|
|
198
|
+
* via ivm.Reference callbacks to fetch workflow data.
|
|
199
|
+
*
|
|
200
|
+
* @private
|
|
201
|
+
* @throws {Error} If context not initialized or reset fails
|
|
202
|
+
*/
|
|
203
|
+
resetDataProxies() {
|
|
204
|
+
if (!this.context) {
|
|
205
|
+
throw new Error('Context not initialized');
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
// Call the resetDataProxies function in the isolate
|
|
209
|
+
// This function is loaded as part of the runtime bundle
|
|
210
|
+
this.context.evalSync('resetDataProxies()');
|
|
211
|
+
if (this.config.debug) {
|
|
212
|
+
console.log('[IsolatedVmBridge] Data proxies reset successfully');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
217
|
+
throw new Error(`Failed to reset data proxies: ${errorMessage}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Register callback functions for cross-isolate communication.
|
|
222
|
+
*
|
|
223
|
+
* Creates three ivm.Reference callbacks that the runtime bundle uses
|
|
224
|
+
* to fetch data from the host process:
|
|
225
|
+
*
|
|
226
|
+
* - __getValueAtPath: Returns metadata or primitive for a property path
|
|
227
|
+
* - __getArrayElement: Returns individual array elements
|
|
228
|
+
* - __callFunctionAtPath: Executes functions in host context
|
|
229
|
+
*
|
|
230
|
+
* These callbacks are called synchronously from isolate proxy traps.
|
|
231
|
+
*
|
|
232
|
+
* @param data - Current workflow data to use for callback responses
|
|
233
|
+
* @private
|
|
234
|
+
*/
|
|
235
|
+
registerCallbacks(data) {
|
|
236
|
+
if (!this.context) {
|
|
237
|
+
throw new Error('Context not initialized');
|
|
238
|
+
}
|
|
239
|
+
// Callback 1: Get value/metadata at path
|
|
240
|
+
// Used by createDeepLazyProxy when accessing properties
|
|
241
|
+
const getValueAtPath = new ivm.Reference((path) => {
|
|
242
|
+
// Navigate to value
|
|
243
|
+
let value = data;
|
|
244
|
+
for (const key of path) {
|
|
245
|
+
value = value?.[key];
|
|
246
|
+
if (value === undefined || value === null) {
|
|
247
|
+
return value;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Handle functions - return metadata marker
|
|
251
|
+
if (typeof value === 'function') {
|
|
252
|
+
const fnString = value.toString();
|
|
253
|
+
// Block native functions for security
|
|
254
|
+
if (fnString.includes('[native code]')) {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
return { __isFunction: true, __name: path[path.length - 1] };
|
|
258
|
+
}
|
|
259
|
+
// Handle arrays - always lazy, only transfer length
|
|
260
|
+
if (Array.isArray(value)) {
|
|
261
|
+
return {
|
|
262
|
+
__isArray: true,
|
|
263
|
+
__length: value.length,
|
|
264
|
+
__data: null,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
// Handle objects - return metadata with keys
|
|
268
|
+
if (value !== null && typeof value === 'object') {
|
|
269
|
+
return {
|
|
270
|
+
__isObject: true,
|
|
271
|
+
__keys: Object.keys(value),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
// Primitive value
|
|
275
|
+
return value;
|
|
276
|
+
});
|
|
277
|
+
// Callback 2: Get array element at index
|
|
278
|
+
// Used by array proxy when accessing numeric indices
|
|
279
|
+
const getArrayElement = new ivm.Reference((path, index) => {
|
|
280
|
+
// Navigate to array
|
|
281
|
+
let arr = data;
|
|
282
|
+
for (const key of path) {
|
|
283
|
+
arr = arr?.[key];
|
|
284
|
+
}
|
|
285
|
+
if (!Array.isArray(arr)) {
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
const element = arr[index];
|
|
289
|
+
// If element is object/array, return metadata
|
|
290
|
+
if (element !== null && typeof element === 'object') {
|
|
291
|
+
if (Array.isArray(element)) {
|
|
292
|
+
return {
|
|
293
|
+
__isArray: true,
|
|
294
|
+
__length: element.length,
|
|
295
|
+
__data: null,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
__isObject: true,
|
|
300
|
+
__keys: Object.keys(element),
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
// Primitive element
|
|
304
|
+
return element;
|
|
305
|
+
});
|
|
306
|
+
// Callback 3: Call function at path with arguments
|
|
307
|
+
// Used when expressions invoke functions from workflow data
|
|
308
|
+
const callFunctionAtPath = new ivm.Reference((path, ...args) => {
|
|
309
|
+
// Navigate to function, tracking parent to preserve `this` context
|
|
310
|
+
let fn = data;
|
|
311
|
+
let parent = undefined;
|
|
312
|
+
for (const key of path) {
|
|
313
|
+
parent = fn;
|
|
314
|
+
fn = fn?.[key];
|
|
315
|
+
}
|
|
316
|
+
if (typeof fn !== 'function') {
|
|
317
|
+
throw new Error(`${path.join('.')} is not a function`);
|
|
318
|
+
}
|
|
319
|
+
// Block native functions for security (same check as getValueAtPath)
|
|
320
|
+
if (fn.toString().includes('[native code]')) {
|
|
321
|
+
throw new Error(`${path.join('.')} is a native function and cannot be called`);
|
|
322
|
+
}
|
|
323
|
+
// Execute function with parent as `this` to preserve method context
|
|
324
|
+
return fn.call(parent, ...args);
|
|
325
|
+
});
|
|
326
|
+
// Release previous references before replacing to avoid accumulation
|
|
327
|
+
this.valueAtPathRef?.release();
|
|
328
|
+
this.arrayElementRef?.release();
|
|
329
|
+
this.callFunctionRef?.release();
|
|
330
|
+
// Store references so they can be released on the next call or on dispose()
|
|
331
|
+
this.valueAtPathRef = getValueAtPath;
|
|
332
|
+
this.arrayElementRef = getArrayElement;
|
|
333
|
+
this.callFunctionRef = callFunctionAtPath;
|
|
334
|
+
// Register all callbacks in isolate global context
|
|
335
|
+
this.context.global.setSync('__getValueAtPath', getValueAtPath);
|
|
336
|
+
this.context.global.setSync('__getArrayElement', getArrayElement);
|
|
337
|
+
this.context.global.setSync('__callFunctionAtPath', callFunctionAtPath);
|
|
338
|
+
if (this.config.debug) {
|
|
339
|
+
console.log('[IsolatedVmBridge] Callbacks registered successfully');
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Execute JavaScript code in the isolated context.
|
|
344
|
+
*
|
|
345
|
+
* Flow:
|
|
346
|
+
* 1. Register callbacks as ivm.Reference for cross-isolate communication
|
|
347
|
+
* 2. Call resetDataProxies() to initialize workflow data proxies
|
|
348
|
+
* 3. Compile script (with caching for performance)
|
|
349
|
+
* 4. Execute with timeout enforcement
|
|
350
|
+
* 5. Return result (copied from isolate)
|
|
351
|
+
*
|
|
352
|
+
* @param code - JavaScript expression to evaluate
|
|
353
|
+
* @param data - Workflow data (e.g., { $json: {...}, $runIndex: 0 })
|
|
354
|
+
* @returns Result of the expression
|
|
355
|
+
* @throws {Error} If bridge not initialized or execution fails
|
|
356
|
+
*/
|
|
357
|
+
execute(code, data) {
|
|
358
|
+
if (!this.initialized || !this.context) {
|
|
359
|
+
throw new Error('Bridge not initialized. Call initialize() first.');
|
|
360
|
+
}
|
|
361
|
+
try {
|
|
362
|
+
// Step 1: Register callbacks with current data context
|
|
363
|
+
this.registerCallbacks(data);
|
|
364
|
+
// Step 2: Reset proxies for this evaluation
|
|
365
|
+
// This initializes $json, $binary, etc. as lazy proxies
|
|
366
|
+
this.resetDataProxies();
|
|
367
|
+
// Step 3: Wrap transformed code so 'this' === __data in the isolate.
|
|
368
|
+
// Tournament generates: this.$json.email, this.$items(), etc.
|
|
369
|
+
// __data has $json, $items, etc. as lazy proxies (set in resetDataProxies).
|
|
370
|
+
const wrappedCode = `(function() {\n${code}\n}).call(__data)`;
|
|
371
|
+
let script = this.scriptCache.get(code);
|
|
372
|
+
if (!script) {
|
|
373
|
+
script = this.isolate.compileScriptSync(wrappedCode);
|
|
374
|
+
this.scriptCache.set(code, script);
|
|
375
|
+
if (this.config.debug) {
|
|
376
|
+
console.log('[IsolatedVmBridge] Script compiled and cached');
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Step 4: Execute with timeout and copy result back
|
|
380
|
+
const result = script.runSync(this.context, {
|
|
381
|
+
timeout: this.config.timeout,
|
|
382
|
+
copy: true,
|
|
383
|
+
});
|
|
384
|
+
if (this.config.debug) {
|
|
385
|
+
console.log('[IsolatedVmBridge] Expression executed successfully');
|
|
386
|
+
}
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
391
|
+
throw new Error(`Expression evaluation failed: ${errorMessage}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Dispose of the isolate and free resources.
|
|
396
|
+
*
|
|
397
|
+
* After disposal, the bridge cannot be used again.
|
|
398
|
+
*/
|
|
399
|
+
async dispose() {
|
|
400
|
+
if (this.disposed) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
// Dispose isolate (this also disposes all contexts, references, etc.)
|
|
404
|
+
if (!this.isolate.isDisposed) {
|
|
405
|
+
this.isolate.dispose();
|
|
406
|
+
}
|
|
407
|
+
// Release callback references
|
|
408
|
+
this.valueAtPathRef?.release();
|
|
409
|
+
this.arrayElementRef?.release();
|
|
410
|
+
this.callFunctionRef?.release();
|
|
411
|
+
this.disposed = true;
|
|
412
|
+
this.initialized = false;
|
|
413
|
+
this.scriptCache.clear();
|
|
414
|
+
if (this.config.debug) {
|
|
415
|
+
console.log('[IsolatedVmBridge] Disposed');
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Check if the bridge has been disposed.
|
|
420
|
+
*
|
|
421
|
+
* @returns true if disposed, false otherwise
|
|
422
|
+
*/
|
|
423
|
+
isDisposed() {
|
|
424
|
+
return this.disposed;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=isolated-vm-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isolated-vm-bridge.js","sourceRoot":"","sources":["../../src/bridge/isolated-vm-bridge.ts"],"names":[],"mappings":"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"}
|