runframe 1.0.4 → 2.2.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/.integrity +24 -0
- package/README.md +309 -48
- package/dist/execution-hooks.d.ts +57 -0
- package/dist/execution-hooks.d.ts.map +1 -0
- package/dist/execution-hooks.js +93 -0
- package/dist/execution-hooks.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/integrity-check.d.ts +38 -0
- package/dist/integrity-check.d.ts.map +1 -0
- package/dist/integrity-check.js +179 -0
- package/dist/integrity-check.js.map +1 -0
- package/dist/module-loader.d.ts +53 -0
- package/dist/module-loader.d.ts.map +1 -0
- package/dist/module-loader.js +105 -0
- package/dist/module-loader.js.map +1 -0
- package/dist/sandbox.d.ts +16 -1
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +67 -4
- package/dist/sandbox.js.map +1 -1
- package/dist/security-audit.d.ts +6 -0
- package/dist/security-audit.d.ts.map +1 -0
- package/dist/security-audit.js +331 -0
- package/dist/security-audit.js.map +1 -0
- package/dist/test-security.d.ts +5 -0
- package/dist/test-security.d.ts.map +1 -0
- package/dist/test-security.js +367 -0
- package/dist/test-security.js.map +1 -0
- package/dist/vm-runtime.d.ts +3 -1
- package/dist/vm-runtime.d.ts.map +1 -1
- package/dist/vm-runtime.js +81 -5
- package/dist/vm-runtime.js.map +1 -1
- package/dist/worker.js +44 -7
- package/dist/worker.js.map +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
/**
|
|
8
|
+
* Calculate SHA-256 hash of a file
|
|
9
|
+
*/
|
|
10
|
+
function hashFile(filePath) {
|
|
11
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
12
|
+
return crypto.createHash('sha256').update(content).digest('hex');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get all TypeScript source files
|
|
16
|
+
*/
|
|
17
|
+
function getSourceFiles(srcDir) {
|
|
18
|
+
const files = [];
|
|
19
|
+
const dirents = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
20
|
+
for (const dirent of dirents) {
|
|
21
|
+
const fullPath = path.join(srcDir, dirent.name);
|
|
22
|
+
if (dirent.isDirectory()) {
|
|
23
|
+
// Skip node_modules, dist, and hidden directories
|
|
24
|
+
if (!dirent.name.startsWith('.') && dirent.name !== 'node_modules' && dirent.name !== 'dist') {
|
|
25
|
+
files.push(...getSourceFiles(fullPath));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else if (dirent.isFile() && dirent.name.endsWith('.ts')) {
|
|
29
|
+
files.push(fullPath);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return files;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generate integrity checksums for all source files
|
|
36
|
+
*/
|
|
37
|
+
export function generateIntegrityChecksum() {
|
|
38
|
+
const srcDir = path.join(__dirname, '..');
|
|
39
|
+
const files = getSourceFiles(srcDir);
|
|
40
|
+
const checksums = {};
|
|
41
|
+
for (const file of files) {
|
|
42
|
+
const relPath = path.relative(srcDir, file);
|
|
43
|
+
checksums[relPath] = hashFile(file);
|
|
44
|
+
}
|
|
45
|
+
return checksums;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Load integrity checksums from file
|
|
49
|
+
*/
|
|
50
|
+
function loadChecksums() {
|
|
51
|
+
const checksumFile = path.join(__dirname, '..', '.integrity');
|
|
52
|
+
if (fs.existsSync(checksumFile)) {
|
|
53
|
+
const content = fs.readFileSync(checksumFile, 'utf-8');
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse(content);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Save integrity checksums to file
|
|
65
|
+
*/
|
|
66
|
+
export function saveIntegrityChecksum() {
|
|
67
|
+
const checksums = generateIntegrityChecksum();
|
|
68
|
+
const checksumFile = path.join(__dirname, '..', '.integrity');
|
|
69
|
+
fs.writeFileSync(checksumFile, JSON.stringify(checksums, null, 2));
|
|
70
|
+
console.log(`✅ Integrity checksums saved to ${checksumFile}`);
|
|
71
|
+
console.log(` Protected ${Object.keys(checksums).length} source files`);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Verify code integrity
|
|
75
|
+
* Throws error if code has been tampered with
|
|
76
|
+
*/
|
|
77
|
+
export function verifyIntegrity() {
|
|
78
|
+
const srcDir = path.join(__dirname, '..');
|
|
79
|
+
const files = getSourceFiles(srcDir);
|
|
80
|
+
const savedChecksums = loadChecksums();
|
|
81
|
+
const result = {
|
|
82
|
+
valid: true,
|
|
83
|
+
files: [],
|
|
84
|
+
timestamp: new Date().toISOString(),
|
|
85
|
+
errors: []
|
|
86
|
+
};
|
|
87
|
+
if (!savedChecksums) {
|
|
88
|
+
result.errors.push('No integrity checksums found. Run saveIntegrityChecksum() first.');
|
|
89
|
+
result.valid = false;
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
for (const file of files) {
|
|
93
|
+
const relPath = path.relative(srcDir, file);
|
|
94
|
+
const currentHash = hashFile(file);
|
|
95
|
+
const expectedHash = savedChecksums[relPath];
|
|
96
|
+
result.files.push({
|
|
97
|
+
path: relPath,
|
|
98
|
+
hash: currentHash,
|
|
99
|
+
expected: expectedHash || 'UNKNOWN',
|
|
100
|
+
match: currentHash === expectedHash
|
|
101
|
+
});
|
|
102
|
+
if (currentHash !== expectedHash) {
|
|
103
|
+
result.valid = false;
|
|
104
|
+
result.errors.push(`❌ TAMPERING DETECTED: ${relPath}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Check for unexpected new files
|
|
108
|
+
for (const savedPath of Object.keys(savedChecksums)) {
|
|
109
|
+
if (!files.some(f => path.relative(srcDir, f) === savedPath)) {
|
|
110
|
+
result.valid = false;
|
|
111
|
+
result.errors.push(`❌ FILE REMOVED: ${savedPath}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Check for missing checksums (new files added)
|
|
115
|
+
for (const file of files) {
|
|
116
|
+
const relPath = path.relative(srcDir, file);
|
|
117
|
+
if (!(relPath in savedChecksums)) {
|
|
118
|
+
result.valid = false;
|
|
119
|
+
result.errors.push(`⚠️ NEW FILE DETECTED: ${relPath} (unverified)`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Verify integrity and throw if compromised
|
|
126
|
+
* Use this at startup to ensure code safety
|
|
127
|
+
*/
|
|
128
|
+
export function enforceIntegrity() {
|
|
129
|
+
const result = verifyIntegrity();
|
|
130
|
+
if (!result.valid) {
|
|
131
|
+
console.error('\n' + '='.repeat(70));
|
|
132
|
+
console.error('🚨 CODE INTEGRITY VERIFICATION FAILED 🚨');
|
|
133
|
+
console.error('='.repeat(70));
|
|
134
|
+
console.error('\nThe sandbox code has been modified or tampered with.');
|
|
135
|
+
console.error('This is a critical security issue.\n');
|
|
136
|
+
for (const error of result.errors) {
|
|
137
|
+
console.error(` ${error}`);
|
|
138
|
+
}
|
|
139
|
+
console.error('\nCompromised files:');
|
|
140
|
+
for (const file of result.files) {
|
|
141
|
+
if (!file.match) {
|
|
142
|
+
console.error(` ${file.path}`);
|
|
143
|
+
console.error(` Expected: ${file.expected.substring(0, 16)}...`);
|
|
144
|
+
console.error(` Found: ${file.hash.substring(0, 16)}...`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
console.error('\n' + '='.repeat(70));
|
|
148
|
+
console.error('ABORTING EXECUTION FOR SECURITY');
|
|
149
|
+
console.error('='.repeat(70) + '\n');
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Print integrity verification report
|
|
155
|
+
*/
|
|
156
|
+
export function printIntegrityReport() {
|
|
157
|
+
const result = verifyIntegrity();
|
|
158
|
+
console.log('\n' + '='.repeat(70));
|
|
159
|
+
console.log('📋 CODE INTEGRITY VERIFICATION REPORT');
|
|
160
|
+
console.log('='.repeat(70) + '\n');
|
|
161
|
+
console.log(`Status: ${result.valid ? '✅ VALID' : '❌ COMPROMISED'}`);
|
|
162
|
+
console.log(`Timestamp: ${result.timestamp}`);
|
|
163
|
+
console.log(`Files Verified: ${result.files.filter(f => f.match).length}/${result.files.length}\n`);
|
|
164
|
+
if (result.errors.length > 0) {
|
|
165
|
+
console.log('Issues Found:');
|
|
166
|
+
for (const error of result.errors) {
|
|
167
|
+
console.log(` ${error}`);
|
|
168
|
+
}
|
|
169
|
+
console.log();
|
|
170
|
+
}
|
|
171
|
+
console.log('Detailed File Hashes:');
|
|
172
|
+
for (const file of result.files) {
|
|
173
|
+
const status = file.match ? '✅' : '❌';
|
|
174
|
+
console.log(` ${status} ${file.path}`);
|
|
175
|
+
console.log(` Hash: ${file.hash.substring(0, 32)}...`);
|
|
176
|
+
}
|
|
177
|
+
console.log('\n' + '='.repeat(70) + '\n');
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=integrity-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrity-check.js","sourceRoot":"","sources":["../src/integrity-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe module loader with whitelist
|
|
3
|
+
* Allows sandboxed code to require only whitelisted modules
|
|
4
|
+
*/
|
|
5
|
+
import crypto from "node:crypto";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import util from "node:util";
|
|
8
|
+
import os from "node:os";
|
|
9
|
+
import url from "node:url";
|
|
10
|
+
/**
|
|
11
|
+
* Whitelisted modules safe for sandboxed code
|
|
12
|
+
*/
|
|
13
|
+
declare const WHITELISTED_MODULES: {
|
|
14
|
+
crypto: {
|
|
15
|
+
module: typeof crypto;
|
|
16
|
+
allowedExports: string[];
|
|
17
|
+
};
|
|
18
|
+
path: {
|
|
19
|
+
module: path.PlatformPath;
|
|
20
|
+
allowedExports: string[];
|
|
21
|
+
};
|
|
22
|
+
util: {
|
|
23
|
+
module: typeof util;
|
|
24
|
+
allowedExports: string[];
|
|
25
|
+
};
|
|
26
|
+
os: {
|
|
27
|
+
module: typeof os;
|
|
28
|
+
allowedExports: string[];
|
|
29
|
+
};
|
|
30
|
+
url: {
|
|
31
|
+
module: typeof url;
|
|
32
|
+
allowedExports: string[];
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export type AllowedModule = keyof typeof WHITELISTED_MODULES;
|
|
36
|
+
export interface ModuleLoaderConfig {
|
|
37
|
+
allowed: AllowedModule[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create a safe require() function with whitelisted modules
|
|
41
|
+
* Prevents access to dangerous modules and exports
|
|
42
|
+
*/
|
|
43
|
+
export declare function createSafeRequire(config: ModuleLoaderConfig): (moduleName: string) => Record<string, unknown>;
|
|
44
|
+
/**
|
|
45
|
+
* Get the list of all available whitelisted modules
|
|
46
|
+
*/
|
|
47
|
+
export declare function getAvailableModules(): AllowedModule[];
|
|
48
|
+
/**
|
|
49
|
+
* Get the whitelisted exports for a module
|
|
50
|
+
*/
|
|
51
|
+
export declare function getModuleExports(moduleName: AllowedModule): string[];
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=module-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-loader.d.ts","sourceRoot":"","sources":["../src/module-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B;;GAEG;AACH,QAAA,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;CAqBxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,mBAAmB,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,IAG9B,YAAY,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiEzE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,EAAE,CAErD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,aAAa,GAAG,MAAM,EAAE,CAEpE"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe module loader with whitelist
|
|
3
|
+
* Allows sandboxed code to require only whitelisted modules
|
|
4
|
+
*/
|
|
5
|
+
import crypto from "node:crypto";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import util from "node:util";
|
|
8
|
+
import os from "node:os";
|
|
9
|
+
import url from "node:url";
|
|
10
|
+
/**
|
|
11
|
+
* Whitelisted modules safe for sandboxed code
|
|
12
|
+
*/
|
|
13
|
+
const WHITELISTED_MODULES = {
|
|
14
|
+
crypto: {
|
|
15
|
+
module: crypto,
|
|
16
|
+
allowedExports: ["createHash", "randomBytes", "subtle"]
|
|
17
|
+
},
|
|
18
|
+
path: {
|
|
19
|
+
module: path,
|
|
20
|
+
allowedExports: ["join", "resolve", "dirname", "basename", "extname", "normalize", "parse"]
|
|
21
|
+
},
|
|
22
|
+
util: {
|
|
23
|
+
module: util,
|
|
24
|
+
allowedExports: ["inspect", "format", "isArray", "isObject", "isString", "isNumber"]
|
|
25
|
+
},
|
|
26
|
+
os: {
|
|
27
|
+
module: os,
|
|
28
|
+
allowedExports: ["platform", "arch", "cpus", "freemem", "totalmem"]
|
|
29
|
+
},
|
|
30
|
+
url: {
|
|
31
|
+
module: url,
|
|
32
|
+
allowedExports: ["parse", "format", "resolve", "fileURLToPath"]
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Create a safe require() function with whitelisted modules
|
|
37
|
+
* Prevents access to dangerous modules and exports
|
|
38
|
+
*/
|
|
39
|
+
export function createSafeRequire(config) {
|
|
40
|
+
const allowed = new Set(config.allowed);
|
|
41
|
+
return function safeRequire(moduleName) {
|
|
42
|
+
if (!allowed.has(moduleName)) {
|
|
43
|
+
throw new Error(`Module "${moduleName}" is not whitelisted. ` +
|
|
44
|
+
`Allowed modules: ${Array.from(allowed).join(", ")}`);
|
|
45
|
+
}
|
|
46
|
+
const whitelisted = WHITELISTED_MODULES[moduleName];
|
|
47
|
+
if (!whitelisted) {
|
|
48
|
+
throw new Error(`Module "${moduleName}" is not available`);
|
|
49
|
+
}
|
|
50
|
+
// Create a proxy that only exposes whitelisted exports
|
|
51
|
+
return new Proxy(whitelisted.module, {
|
|
52
|
+
get(target, prop) {
|
|
53
|
+
if (typeof prop !== "string") {
|
|
54
|
+
throw new Error("Module property access must use string keys");
|
|
55
|
+
}
|
|
56
|
+
// Check if this export is whitelisted
|
|
57
|
+
if (!whitelisted.allowedExports.includes(prop)) {
|
|
58
|
+
throw new Error(`Export "${prop}" from module "${moduleName}" is not whitelisted. ` +
|
|
59
|
+
`Allowed exports: ${whitelisted.allowedExports.join(", ")}`);
|
|
60
|
+
}
|
|
61
|
+
const value = target[prop];
|
|
62
|
+
// Additional safety: prevent access to dangerous functions
|
|
63
|
+
if (typeof value === "function") {
|
|
64
|
+
// Prevent modification of the function
|
|
65
|
+
return Object.freeze(value);
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
},
|
|
69
|
+
set(target, prop) {
|
|
70
|
+
throw new Error(`Cannot modify module "${moduleName}"`);
|
|
71
|
+
},
|
|
72
|
+
has(target, prop) {
|
|
73
|
+
if (typeof prop !== "string") {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return whitelisted.allowedExports.includes(prop);
|
|
77
|
+
},
|
|
78
|
+
ownKeys(target) {
|
|
79
|
+
return whitelisted.allowedExports;
|
|
80
|
+
},
|
|
81
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
82
|
+
if (typeof prop !== "string") {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
if (!whitelisted.allowedExports.includes(prop)) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
return Object.getOwnPropertyDescriptor(target, prop);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get the list of all available whitelisted modules
|
|
95
|
+
*/
|
|
96
|
+
export function getAvailableModules() {
|
|
97
|
+
return Object.keys(WHITELISTED_MODULES);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get the whitelisted exports for a module
|
|
101
|
+
*/
|
|
102
|
+
export function getModuleExports(moduleName) {
|
|
103
|
+
return WHITELISTED_MODULES[moduleName]?.allowedExports ?? [];
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=module-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-loader.js","sourceRoot":"","sources":["../src/module-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B;;GAEG;AACH,MAAM,mBAAmB,GAAG;IAC1B,MAAM,EAAE;QACN,MAAM,EAAE,MAAM;QACd,cAAc,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,QAAQ,CAAC;KACxD;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,IAAI;QACZ,cAAc,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC;KAC5F;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,IAAI;QACZ,cAAc,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC;KACrF;IACD,EAAE,EAAE;QACF,MAAM,EAAE,EAAE;QACV,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,CAAC;KACpE;IACD,GAAG,EAAE;QACH,MAAM,EAAE,GAAG;QACX,cAAc,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,CAAC;KAChE;CACF,CAAC;AAQF;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAA0B;IAC1D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAExC,OAAO,SAAS,WAAW,CAAC,UAAkB;QAC5C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAA2B,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CACb,WAAW,UAAU,wBAAwB;gBAC7C,oBAAoB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrD,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,mBAAmB,CAAC,UAA2B,CAAC,CAAC;QACrE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,WAAW,UAAU,oBAAoB,CAAC,CAAC;QAC7D,CAAC;QAED,uDAAuD;QACvD,OAAO,IAAI,KAAK,CAAC,WAAW,CAAC,MAAiC,EAAE;YAC9D,GAAG,CAAC,MAAM,EAAE,IAAI;gBACd,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC7B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;gBACjE,CAAC;gBAED,sCAAsC;gBACtC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/C,MAAM,IAAI,KAAK,CACb,WAAW,IAAI,kBAAkB,UAAU,wBAAwB;wBACnE,oBAAoB,WAAW,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5D,CAAC;gBACJ,CAAC;gBAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;gBAE3B,2DAA2D;gBAC3D,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;oBAChC,uCAAuC;oBACvC,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC9B,CAAC;gBAED,OAAO,KAAK,CAAC;YACf,CAAC;YAED,GAAG,CAAC,MAAM,EAAE,IAAI;gBACd,MAAM,IAAI,KAAK,CAAC,yBAAyB,UAAU,GAAG,CAAC,CAAC;YAC1D,CAAC;YAED,GAAG,CAAC,MAAM,EAAE,IAAI;gBACd,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC7B,OAAO,KAAK,CAAC;gBACf,CAAC;gBACD,OAAO,WAAW,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACnD,CAAC;YAED,OAAO,CAAC,MAAM;gBACZ,OAAO,WAAW,CAAC,cAAc,CAAC;YACpC,CAAC;YAED,wBAAwB,CAAC,MAAM,EAAE,IAAI;gBACnC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC7B,OAAO,SAAS,CAAC;gBACnB,CAAC;gBACD,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/C,OAAO,SAAS,CAAC;gBACnB,CAAC;gBACD,OAAO,MAAM,CAAC,wBAAwB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACvD,CAAC;SACF,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAoB,CAAC;AAC7D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAyB;IACxD,OAAO,mBAAmB,CAAC,UAAU,CAAC,EAAE,cAAc,IAAI,EAAE,CAAC;AAC/D,CAAC"}
|
package/dist/sandbox.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { CapabilityGrant, DEFAULT_CAPABILITIES } from "./capabilities.js";
|
|
2
2
|
import { ExecutionStats } from "./stats.js";
|
|
3
|
+
import { AllowedModule } from "./module-loader.js";
|
|
4
|
+
import { ExecutionHooks } from "./execution-hooks.js";
|
|
3
5
|
export interface SandboxOptions {
|
|
4
6
|
cpuMs: number;
|
|
5
7
|
memoryMb: number;
|
|
6
8
|
capabilities?: Partial<CapabilityGrant>;
|
|
7
9
|
seed?: number;
|
|
10
|
+
globals?: Record<string, unknown>;
|
|
11
|
+
allowedModules?: AllowedModule[];
|
|
8
12
|
}
|
|
9
13
|
export interface SandboxResult {
|
|
10
14
|
type: "result";
|
|
@@ -17,7 +21,18 @@ export interface SandboxError {
|
|
|
17
21
|
}
|
|
18
22
|
export type SandboxMessage = SandboxResult | SandboxError;
|
|
19
23
|
export declare function createSandbox(options: SandboxOptions): {
|
|
20
|
-
run(code: string): Promise<SandboxMessage>;
|
|
24
|
+
run(code: string, overrideGlobals?: Record<string, unknown>): Promise<SandboxMessage>;
|
|
25
|
+
/**
|
|
26
|
+
* Register a hook handler
|
|
27
|
+
*/
|
|
28
|
+
onBefore(handler: (context: any) => void): void;
|
|
29
|
+
onAfter(handler: (context: any) => void): void;
|
|
30
|
+
onError(handler: (context: any) => void): void;
|
|
31
|
+
onConsole(handler: (context: any) => void): void;
|
|
32
|
+
/**
|
|
33
|
+
* Get hook instance for advanced usage
|
|
34
|
+
*/
|
|
35
|
+
getHooks(): ExecutionHooks;
|
|
21
36
|
};
|
|
22
37
|
export { CapabilityGrant, DEFAULT_CAPABILITIES };
|
|
23
38
|
export { ExecutionStats } from "./stats.js";
|
package/dist/sandbox.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAuB,MAAM,sBAAsB,CAAC;AAK3E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,cAAc,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,YAAY,CAAC;AAE1D,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc;cAIvC,MAAM,oBAAoB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC;IA0FrF;;OAEG;sBACe,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;qBAI9B,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;qBAI7B,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;uBAI3B,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAIhD;;OAEG;gBACS,cAAc;EAI7B;AAED,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/sandbox.js
CHANGED
|
@@ -2,12 +2,21 @@ import { Worker } from "node:worker_threads";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { DEFAULT_CAPABILITIES } from "./capabilities.js";
|
|
5
|
+
import { ExecutionHooks, generateExecutionId } from "./execution-hooks.js";
|
|
5
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
7
|
const __dirname = path.dirname(__filename);
|
|
7
8
|
export function createSandbox(options) {
|
|
9
|
+
const hooks = new ExecutionHooks();
|
|
8
10
|
return {
|
|
9
|
-
run(code) {
|
|
11
|
+
run(code, overrideGlobals) {
|
|
10
12
|
return new Promise((resolve, reject) => {
|
|
13
|
+
const executionId = generateExecutionId();
|
|
14
|
+
// Emit before hook
|
|
15
|
+
hooks.emit("before", {
|
|
16
|
+
code,
|
|
17
|
+
executionId,
|
|
18
|
+
timestamp: Date.now()
|
|
19
|
+
}).catch(console.error);
|
|
11
20
|
const worker = new Worker(path.resolve(__dirname, "worker.js"), {
|
|
12
21
|
workerData: {
|
|
13
22
|
code,
|
|
@@ -16,37 +25,91 @@ export function createSandbox(options) {
|
|
|
16
25
|
memoryMb: options.memoryMb
|
|
17
26
|
},
|
|
18
27
|
capabilities: options.capabilities,
|
|
19
|
-
seed: options.seed
|
|
28
|
+
seed: options.seed,
|
|
29
|
+
globals: { ...options.globals, ...overrideGlobals },
|
|
30
|
+
allowedModules: options.allowedModules ?? [],
|
|
31
|
+
executionId
|
|
20
32
|
}
|
|
21
|
-
// Note: Memory limit is enforced via resource limits, not Node flags
|
|
22
|
-
// Worker threads inherit parent process memory limits
|
|
23
33
|
});
|
|
34
|
+
const startTime = Date.now();
|
|
24
35
|
const timeout = setTimeout(() => {
|
|
25
36
|
worker.terminate();
|
|
37
|
+
hooks.emit("error", {
|
|
38
|
+
code,
|
|
39
|
+
executionId,
|
|
40
|
+
timestamp: Date.now(),
|
|
41
|
+
error: "Sandbox timeout exceeded"
|
|
42
|
+
}).catch(console.error);
|
|
26
43
|
reject(new Error("Sandbox timeout exceeded"));
|
|
27
44
|
}, options.cpuMs);
|
|
28
45
|
worker.once("message", (msg) => {
|
|
29
46
|
clearTimeout(timeout);
|
|
47
|
+
const duration = Date.now() - startTime;
|
|
30
48
|
worker.terminate();
|
|
49
|
+
hooks.emit("after", {
|
|
50
|
+
code,
|
|
51
|
+
executionId,
|
|
52
|
+
timestamp: Date.now(),
|
|
53
|
+
duration
|
|
54
|
+
}).catch(console.error);
|
|
31
55
|
if (msg.type === "result") {
|
|
32
56
|
resolve(msg);
|
|
33
57
|
}
|
|
34
58
|
else {
|
|
59
|
+
hooks.emit("error", {
|
|
60
|
+
code,
|
|
61
|
+
executionId,
|
|
62
|
+
timestamp: Date.now(),
|
|
63
|
+
error: msg.error
|
|
64
|
+
}).catch(console.error);
|
|
35
65
|
reject(new Error(msg.error));
|
|
36
66
|
}
|
|
37
67
|
});
|
|
38
68
|
worker.once("error", (err) => {
|
|
39
69
|
clearTimeout(timeout);
|
|
40
70
|
worker.terminate();
|
|
71
|
+
hooks.emit("error", {
|
|
72
|
+
code,
|
|
73
|
+
executionId,
|
|
74
|
+
timestamp: Date.now(),
|
|
75
|
+
error: err.message
|
|
76
|
+
}).catch(console.error);
|
|
41
77
|
reject(err);
|
|
42
78
|
});
|
|
43
79
|
worker.once("exit", (code) => {
|
|
44
80
|
clearTimeout(timeout);
|
|
45
81
|
if (code !== 0) {
|
|
82
|
+
hooks.emit("error", {
|
|
83
|
+
code: code,
|
|
84
|
+
executionId,
|
|
85
|
+
timestamp: Date.now(),
|
|
86
|
+
error: `Worker exited with code ${code}`
|
|
87
|
+
}).catch(console.error);
|
|
46
88
|
reject(new Error(`Worker exited with code ${code}`));
|
|
47
89
|
}
|
|
48
90
|
});
|
|
49
91
|
});
|
|
92
|
+
},
|
|
93
|
+
/**
|
|
94
|
+
* Register a hook handler
|
|
95
|
+
*/
|
|
96
|
+
onBefore(handler) {
|
|
97
|
+
hooks.register("before", handler);
|
|
98
|
+
},
|
|
99
|
+
onAfter(handler) {
|
|
100
|
+
hooks.register("after", handler);
|
|
101
|
+
},
|
|
102
|
+
onError(handler) {
|
|
103
|
+
hooks.register("error", handler);
|
|
104
|
+
},
|
|
105
|
+
onConsole(handler) {
|
|
106
|
+
hooks.register("console", handler);
|
|
107
|
+
},
|
|
108
|
+
/**
|
|
109
|
+
* Get hook instance for advanced usage
|
|
110
|
+
*/
|
|
111
|
+
getHooks() {
|
|
112
|
+
return hooks;
|
|
50
113
|
}
|
|
51
114
|
};
|
|
52
115
|
}
|
package/dist/sandbox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAmB,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAG1E,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-audit.d.ts","sourceRoot":"","sources":["../src/security-audit.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|