beddel 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.
- package/README.md +297 -0
- package/dist/agents/agentRegistry.d.ts +68 -0
- package/dist/agents/agentRegistry.d.ts.map +1 -0
- package/dist/agents/agentRegistry.js +222 -0
- package/dist/agents/agentRegistry.js.map +1 -0
- package/dist/agents/formatter-agent.d.ts +10 -0
- package/dist/agents/formatter-agent.d.ts.map +1 -0
- package/dist/agents/formatter-agent.js +49 -0
- package/dist/agents/formatter-agent.js.map +1 -0
- package/dist/agents/genkit-agent.d.ts +12 -0
- package/dist/agents/genkit-agent.d.ts.map +1 -0
- package/dist/agents/genkit-agent.js +119 -0
- package/dist/agents/genkit-agent.js.map +1 -0
- package/dist/agents/i18n-messages.d.ts +17 -0
- package/dist/agents/i18n-messages.d.ts.map +1 -0
- package/dist/agents/i18n-messages.js +92 -0
- package/dist/agents/i18n-messages.js.map +1 -0
- package/dist/agents/index.d.ts +10 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +26 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/pipeline.d.ts +15 -0
- package/dist/agents/pipeline.d.ts.map +1 -0
- package/dist/agents/pipeline.js +45 -0
- package/dist/agents/pipeline.js.map +1 -0
- package/dist/agents/schema-factory.d.ts +40 -0
- package/dist/agents/schema-factory.d.ts.map +1 -0
- package/dist/agents/schema-factory.js +121 -0
- package/dist/agents/schema-factory.js.map +1 -0
- package/dist/agents/translation-validators.d.ts +26 -0
- package/dist/agents/translation-validators.d.ts.map +1 -0
- package/dist/agents/translation-validators.js +77 -0
- package/dist/agents/translation-validators.js.map +1 -0
- package/dist/agents/translator-agents.d.ts +184 -0
- package/dist/agents/translator-agents.d.ts.map +1 -0
- package/dist/agents/translator-agents.js +613 -0
- package/dist/agents/translator-agents.js.map +1 -0
- package/dist/agents/types/translation.types.d.ts +100 -0
- package/dist/agents/types/translation.types.d.ts.map +1 -0
- package/dist/agents/types/translation.types.js +3 -0
- package/dist/agents/types/translation.types.js.map +1 -0
- package/dist/agents/validator-agent.d.ts +42 -0
- package/dist/agents/validator-agent.d.ts.map +1 -0
- package/dist/agents/validator-agent.js +122 -0
- package/dist/agents/validator-agent.js.map +1 -0
- package/dist/audit/auditTrail.d.ts +55 -0
- package/dist/audit/auditTrail.d.ts.map +1 -0
- package/dist/audit/auditTrail.js +93 -0
- package/dist/audit/auditTrail.js.map +1 -0
- package/dist/compliance/gdprEngine.d.ts +44 -0
- package/dist/compliance/gdprEngine.d.ts.map +1 -0
- package/dist/compliance/gdprEngine.js +178 -0
- package/dist/compliance/gdprEngine.js.map +1 -0
- package/dist/compliance/lgpdEngine.d.ts +51 -0
- package/dist/compliance/lgpdEngine.d.ts.map +1 -0
- package/dist/compliance/lgpdEngine.js +221 -0
- package/dist/compliance/lgpdEngine.js.map +1 -0
- package/dist/config.d.ts +78 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +77 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +17 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -0
- package/dist/firebase/tenantManager.d.ts +84 -0
- package/dist/firebase/tenantManager.d.ts.map +1 -0
- package/dist/firebase/tenantManager.js +378 -0
- package/dist/firebase/tenantManager.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +118 -0
- package/dist/index.js.map +1 -0
- package/dist/integration/secure-yaml-runtime.d.ts +68 -0
- package/dist/integration/secure-yaml-runtime.d.ts.map +1 -0
- package/dist/integration/secure-yaml-runtime.js +245 -0
- package/dist/integration/secure-yaml-runtime.js.map +1 -0
- package/dist/parser/secure-yaml-parser.d.ts +62 -0
- package/dist/parser/secure-yaml-parser.d.ts.map +1 -0
- package/dist/parser/secure-yaml-parser.js +234 -0
- package/dist/parser/secure-yaml-parser.js.map +1 -0
- package/dist/performance/autoscaling.d.ts +100 -0
- package/dist/performance/autoscaling.d.ts.map +1 -0
- package/dist/performance/autoscaling.js +339 -0
- package/dist/performance/autoscaling.js.map +1 -0
- package/dist/performance/benchmark.d.ts +104 -0
- package/dist/performance/benchmark.d.ts.map +1 -0
- package/dist/performance/benchmark.js +514 -0
- package/dist/performance/benchmark.js.map +1 -0
- package/dist/performance/index.d.ts +14 -0
- package/dist/performance/index.d.ts.map +1 -0
- package/dist/performance/index.js +35 -0
- package/dist/performance/index.js.map +1 -0
- package/dist/performance/monitor.d.ts +126 -0
- package/dist/performance/monitor.d.ts.map +1 -0
- package/dist/performance/monitor.js +324 -0
- package/dist/performance/monitor.js.map +1 -0
- package/dist/performance/streaming.d.ts +82 -0
- package/dist/performance/streaming.d.ts.map +1 -0
- package/dist/performance/streaming.js +287 -0
- package/dist/performance/streaming.js.map +1 -0
- package/dist/runtime/audit.d.ts +240 -0
- package/dist/runtime/audit.d.ts.map +1 -0
- package/dist/runtime/audit.js +641 -0
- package/dist/runtime/audit.js.map +1 -0
- package/dist/runtime/declarativeAgentRuntime.d.ts +123 -0
- package/dist/runtime/declarativeAgentRuntime.d.ts.map +1 -0
- package/dist/runtime/declarativeAgentRuntime.js +576 -0
- package/dist/runtime/declarativeAgentRuntime.js.map +1 -0
- package/dist/runtime/isolatedRuntime.d.ts +119 -0
- package/dist/runtime/isolatedRuntime.d.ts.map +1 -0
- package/dist/runtime/isolatedRuntime.js +425 -0
- package/dist/runtime/isolatedRuntime.js.map +1 -0
- package/dist/runtime/schemaCompiler.d.ts +35 -0
- package/dist/runtime/schemaCompiler.d.ts.map +1 -0
- package/dist/runtime/schemaCompiler.js +151 -0
- package/dist/runtime/schemaCompiler.js.map +1 -0
- package/dist/runtime/simpleRuntime.d.ts +57 -0
- package/dist/runtime/simpleRuntime.d.ts.map +1 -0
- package/dist/runtime/simpleRuntime.js +187 -0
- package/dist/runtime/simpleRuntime.js.map +1 -0
- package/dist/security/dashboard.d.ts +89 -0
- package/dist/security/dashboard.d.ts.map +1 -0
- package/dist/security/dashboard.js +300 -0
- package/dist/security/dashboard.js.map +1 -0
- package/dist/security/hardening.d.ts +130 -0
- package/dist/security/hardening.d.ts.map +1 -0
- package/dist/security/hardening.js +414 -0
- package/dist/security/hardening.js.map +1 -0
- package/dist/security/index.d.ts +128 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +353 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/monitor.d.ts +88 -0
- package/dist/security/monitor.d.ts.map +1 -0
- package/dist/security/monitor.js +356 -0
- package/dist/security/monitor.js.map +1 -0
- package/dist/security/scanner.d.ts +104 -0
- package/dist/security/scanner.d.ts.map +1 -0
- package/dist/security/scanner.js +298 -0
- package/dist/security/scanner.js.map +1 -0
- package/dist/security/score.d.ts +150 -0
- package/dist/security/score.d.ts.map +1 -0
- package/dist/security/score.js +983 -0
- package/dist/security/score.js.map +1 -0
- package/dist/security/test-security.d.ts +22 -0
- package/dist/security/test-security.d.ts.map +1 -0
- package/dist/security/test-security.js +154 -0
- package/dist/security/test-security.js.map +1 -0
- package/dist/security/threatDetector.d.ts +39 -0
- package/dist/security/threatDetector.d.ts.map +1 -0
- package/dist/security/threatDetector.js +354 -0
- package/dist/security/threatDetector.js.map +1 -0
- package/dist/security/validation.d.ts +69 -0
- package/dist/security/validation.d.ts.map +1 -0
- package/dist/security/validation.js +286 -0
- package/dist/security/validation.js.map +1 -0
- package/dist/server/api/clientsRoute.d.ts +9 -0
- package/dist/server/api/clientsRoute.d.ts.map +1 -0
- package/dist/server/api/clientsRoute.js +71 -0
- package/dist/server/api/clientsRoute.js.map +1 -0
- package/dist/server/api/endpointsRoute.d.ts +8 -0
- package/dist/server/api/endpointsRoute.d.ts.map +1 -0
- package/dist/server/api/endpointsRoute.js +76 -0
- package/dist/server/api/endpointsRoute.js.map +1 -0
- package/dist/server/api/graphql.d.ts +9 -0
- package/dist/server/api/graphql.d.ts.map +1 -0
- package/dist/server/api/graphql.js +180 -0
- package/dist/server/api/graphql.js.map +1 -0
- package/dist/server/errors.d.ts +19 -0
- package/dist/server/errors.d.ts.map +1 -0
- package/dist/server/errors.js +42 -0
- package/dist/server/errors.js.map +1 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +24 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/kvStore.d.ts +27 -0
- package/dist/server/kvStore.d.ts.map +1 -0
- package/dist/server/kvStore.js +128 -0
- package/dist/server/kvStore.js.map +1 -0
- package/dist/server/runtimeSecurity.d.ts +28 -0
- package/dist/server/runtimeSecurity.d.ts.map +1 -0
- package/dist/server/runtimeSecurity.js +85 -0
- package/dist/server/runtimeSecurity.js.map +1 -0
- package/dist/server/types.d.ts +53 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +8 -0
- package/dist/server/types.js.map +1 -0
- package/dist/types/executionContext.d.ts +16 -0
- package/dist/types/executionContext.d.ts.map +1 -0
- package/dist/types/executionContext.js +3 -0
- package/dist/types/executionContext.js.map +1 -0
- package/package.json +77 -0
- package/src/agents/agentRegistry.ts +272 -0
- package/src/agents/image-agent.yaml +86 -0
- package/src/agents/joker-agent.yaml +47 -0
- package/src/agents/translator-agent.yaml +80 -0
- package/src/audit/auditTrail.ts +134 -0
- package/src/compliance/gdprEngine.ts +209 -0
- package/src/compliance/lgpdEngine.ts +268 -0
- package/src/config.ts +179 -0
- package/src/errors.ts +35 -0
- package/src/firebase/tenantManager.ts +443 -0
- package/src/index.ts +125 -0
- package/src/integration/secure-yaml-runtime.ts +341 -0
- package/src/parser/secure-yaml-parser.ts +273 -0
- package/src/performance/autoscaling.ts +495 -0
- package/src/performance/benchmark.ts +644 -0
- package/src/performance/index.ts +34 -0
- package/src/performance/monitor.ts +469 -0
- package/src/performance/streaming.ts +317 -0
- package/src/runtime/audit.ts +907 -0
- package/src/runtime/declarativeAgentRuntime.ts +836 -0
- package/src/runtime/isolatedRuntime.ts +572 -0
- package/src/runtime/schemaCompiler.ts +228 -0
- package/src/runtime/simpleRuntime.ts +201 -0
- package/src/security/dashboard.ts +462 -0
- package/src/security/hardening.ts +560 -0
- package/src/security/index.ts +439 -0
- package/src/security/monitor.ts +490 -0
- package/src/security/scanner.ts +368 -0
- package/src/security/score.ts +1138 -0
- package/src/security/threatDetector.ts +481 -0
- package/src/security/validation.ts +365 -0
- package/src/server/api/clientsRoute.ts +92 -0
- package/src/server/api/endpointsRoute.ts +97 -0
- package/src/server/api/graphql.ts +249 -0
- package/src/server/errors.ts +38 -0
- package/src/server/index.ts +6 -0
- package/src/server/kvStore.ts +152 -0
- package/src/server/runtimeSecurity.ts +102 -0
- package/src/server/types.ts +60 -0
- package/src/types/executionContext.ts +16 -0
- package/tools/seed.ts +365 -0
- package/tools/test-endpoints.ts +174 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Isolated Runtime Manager - Isolated VM v5 Implementation
|
|
3
|
+
* Provides ultra-secure isolated execution environment with zero-trust architecture
|
|
4
|
+
*/
|
|
5
|
+
import * as ivm from "isolated-vm";
|
|
6
|
+
import {
|
|
7
|
+
runtimeConfig,
|
|
8
|
+
securityProfiles,
|
|
9
|
+
RuntimeConfig,
|
|
10
|
+
SecurityProfile,
|
|
11
|
+
} from "../config";
|
|
12
|
+
import { EventEmitter } from "events";
|
|
13
|
+
import * as crypto from "crypto";
|
|
14
|
+
import { SecurityScanner } from "../security/scanner";
|
|
15
|
+
|
|
16
|
+
export interface RuntimeContext {
|
|
17
|
+
isolate: ivm.Isolate;
|
|
18
|
+
context: ivm.Context;
|
|
19
|
+
jail: ivm.Reference;
|
|
20
|
+
executionCount: number;
|
|
21
|
+
createdAt: Date;
|
|
22
|
+
lastUsedAt: Date;
|
|
23
|
+
memoryUsage: number;
|
|
24
|
+
securityProfile: SecurityProfile;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ExecutionResult<T = any> {
|
|
28
|
+
success: boolean;
|
|
29
|
+
result?: T;
|
|
30
|
+
error?: Error;
|
|
31
|
+
executionTime: number;
|
|
32
|
+
memoryUsed: number;
|
|
33
|
+
auditHash?: string;
|
|
34
|
+
timestamp: Date;
|
|
35
|
+
securityScore?: number;
|
|
36
|
+
warnings?: string[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ExecutionOptions {
|
|
40
|
+
code: string;
|
|
41
|
+
context?: Record<string, any>;
|
|
42
|
+
securityProfile?: string;
|
|
43
|
+
timeout?: number;
|
|
44
|
+
memoryLimit?: number;
|
|
45
|
+
tenantId?: string;
|
|
46
|
+
auditData?: any;
|
|
47
|
+
scanForSecurity?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class IsolatedRuntimeError extends Error {
|
|
51
|
+
constructor(
|
|
52
|
+
message: string,
|
|
53
|
+
public readonly code: string,
|
|
54
|
+
public readonly context?: any
|
|
55
|
+
) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = "IsolatedRuntimeError";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export class IsolatedRuntimeManager extends EventEmitter {
|
|
62
|
+
private isolates: Map<string, RuntimeContext> = new Map();
|
|
63
|
+
private pool: RuntimeContext[] = [];
|
|
64
|
+
private activeExecutions: Map<string, Promise<ExecutionResult>> = new Map();
|
|
65
|
+
private metrics: Map<string, number[]> = new Map();
|
|
66
|
+
|
|
67
|
+
private readonly maxPoolSize: number;
|
|
68
|
+
private readonly minPoolSize: number;
|
|
69
|
+
private readonly cleanupInterval: NodeJS.Timeout;
|
|
70
|
+
|
|
71
|
+
constructor(private config: RuntimeConfig = runtimeConfig) {
|
|
72
|
+
super();
|
|
73
|
+
this.maxPoolSize = config.maxPoolSize;
|
|
74
|
+
this.minPoolSize = config.minPoolSize;
|
|
75
|
+
|
|
76
|
+
// Initialize pool with minimum isolates
|
|
77
|
+
this.initializePool();
|
|
78
|
+
|
|
79
|
+
// Setup periodic cleanup
|
|
80
|
+
this.cleanupInterval = setInterval(
|
|
81
|
+
() => this.cleanupPool(),
|
|
82
|
+
config.metricsInterval
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Initialize the isolate pool with minimum required isolates
|
|
88
|
+
*/
|
|
89
|
+
private async initializePool(): Promise<void> {
|
|
90
|
+
const profiles = Object.keys(securityProfiles);
|
|
91
|
+
|
|
92
|
+
for (let i = 0; i < this.minPoolSize; i++) {
|
|
93
|
+
const profileName = profiles[i % profiles.length];
|
|
94
|
+
const securityProfile = securityProfiles[profileName];
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const runtimeContext = await this.createIsolate(securityProfile);
|
|
98
|
+
this.pool.push(runtimeContext);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
this.emit(
|
|
101
|
+
"error",
|
|
102
|
+
new IsolatedRuntimeError(
|
|
103
|
+
`Failed to create isolate for profile ${profileName}`,
|
|
104
|
+
"POOL_INIT_ERROR",
|
|
105
|
+
{ error, profileName }
|
|
106
|
+
)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.emit("pool-initialized", {
|
|
112
|
+
poolSize: this.pool.length,
|
|
113
|
+
profiles: profiles,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Create a new isolated context with specified security profile
|
|
119
|
+
*/
|
|
120
|
+
private async createIsolate(
|
|
121
|
+
securityProfile: SecurityProfile
|
|
122
|
+
): Promise<RuntimeContext> {
|
|
123
|
+
const startTime = Date.now();
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
// Create isolate with memory limit
|
|
127
|
+
const isolate = new ivm.Isolate({
|
|
128
|
+
memoryLimit: securityProfile.memoryLimit,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Create context with security restrictions
|
|
132
|
+
const context = await isolate.createContext();
|
|
133
|
+
|
|
134
|
+
// Setup jail environment
|
|
135
|
+
const jail = context.global;
|
|
136
|
+
|
|
137
|
+
// Remove access to dangerous functions
|
|
138
|
+
await jail.set("global", jail.derefInto());
|
|
139
|
+
await jail.set("_globalThis", jail.derefInto());
|
|
140
|
+
await jail.set("require", new ivm.Reference(undefined));
|
|
141
|
+
await jail.set("eval", new ivm.Reference(undefined));
|
|
142
|
+
await jail.set("Function", new ivm.Reference(undefined));
|
|
143
|
+
await jail.set("process", new ivm.Reference(undefined));
|
|
144
|
+
|
|
145
|
+
// Add safe globals
|
|
146
|
+
await jail.set("console", {
|
|
147
|
+
log: (message: string) => this.emit("log", { message, level: "info" }),
|
|
148
|
+
error: (message: string) =>
|
|
149
|
+
this.emit("log", { message, level: "error" }),
|
|
150
|
+
warn: (message: string) => this.emit("log", { message, level: "warn" }),
|
|
151
|
+
info: (message: string) => this.emit("log", { message, level: "info" }),
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Add limited utility functions
|
|
155
|
+
await jail.set("setTimeout", undefined); // Disable timers
|
|
156
|
+
await jail.set("setInterval", undefined);
|
|
157
|
+
await jail.set("clearTimeout", undefined);
|
|
158
|
+
await jail.set("clearInterval", undefined);
|
|
159
|
+
|
|
160
|
+
// Add allowed modules if any
|
|
161
|
+
if (securityProfile.allowedModules.length > 0) {
|
|
162
|
+
const allowedModules: Record<string, any> = {};
|
|
163
|
+
|
|
164
|
+
for (const moduleName of securityProfile.allowedModules) {
|
|
165
|
+
try {
|
|
166
|
+
// Only allow specific safe modules
|
|
167
|
+
if (["lodash", "moment", "uuid"].includes(moduleName)) {
|
|
168
|
+
allowedModules[moduleName] = require(moduleName);
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
// Module not available, continue
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
await jail.set("modules", allowedModules);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const creationTime = Date.now() - startTime;
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
isolate,
|
|
182
|
+
context,
|
|
183
|
+
jail,
|
|
184
|
+
executionCount: 0,
|
|
185
|
+
createdAt: new Date(),
|
|
186
|
+
lastUsedAt: new Date(),
|
|
187
|
+
memoryUsage: 0,
|
|
188
|
+
securityProfile,
|
|
189
|
+
};
|
|
190
|
+
} catch (error) {
|
|
191
|
+
throw new IsolatedRuntimeError(
|
|
192
|
+
"Failed to create isolated context",
|
|
193
|
+
"ISOLATE_CREATION_ERROR",
|
|
194
|
+
{ error, securityProfile, creationTime: Date.now() - startTime }
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Execute code in isolated environment
|
|
201
|
+
*/
|
|
202
|
+
public async execute<T = any>(
|
|
203
|
+
options: ExecutionOptions
|
|
204
|
+
): Promise<ExecutionResult<T>> {
|
|
205
|
+
const startTime = Date.now();
|
|
206
|
+
const executionId = this.generateExecutionId();
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
// Validate input
|
|
210
|
+
this.validateExecutionOptions(options);
|
|
211
|
+
|
|
212
|
+
// Security scan if enabled
|
|
213
|
+
if (options.scanForSecurity !== false) {
|
|
214
|
+
const securityScanner = new SecurityScanner();
|
|
215
|
+
|
|
216
|
+
// Scan the code for security issues
|
|
217
|
+
const scanResult = await securityScanner.scan({
|
|
218
|
+
code: options.code,
|
|
219
|
+
executionId: executionId,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
if (!scanResult.secure) {
|
|
223
|
+
throw new IsolatedRuntimeError(
|
|
224
|
+
`Security scan failed: ${scanResult.warnings.join(", ")}`,
|
|
225
|
+
"SECURITY_SCAN_FAILED",
|
|
226
|
+
{ scanResult }
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Get security profile
|
|
232
|
+
const securityProfile =
|
|
233
|
+
securityProfiles[
|
|
234
|
+
options.securityProfile || this.config.defaultSecurityProfile
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
// Get or create isolate
|
|
238
|
+
const runtimeContext = await this.getOrCreateIsolate(securityProfile);
|
|
239
|
+
|
|
240
|
+
// Execute in isolate
|
|
241
|
+
const result = await this.executeInIsolate<T>(
|
|
242
|
+
runtimeContext,
|
|
243
|
+
options,
|
|
244
|
+
executionId
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
// Update metrics
|
|
248
|
+
const executionTime = Date.now() - startTime;
|
|
249
|
+
this.updateMetrics("executionTime", executionTime);
|
|
250
|
+
this.updateMetrics("successRate", result.success ? 1 : 0);
|
|
251
|
+
|
|
252
|
+
result.executionTime = executionTime;
|
|
253
|
+
|
|
254
|
+
// Generate audit hash if audit enabled
|
|
255
|
+
if (this.config.auditEnabled) {
|
|
256
|
+
result.auditHash = this.generateAuditHash(options, result);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
this.emit("execution-complete", { executionId, result, executionTime });
|
|
260
|
+
|
|
261
|
+
return result;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
const executionTime = Date.now() - startTime;
|
|
264
|
+
|
|
265
|
+
const result: ExecutionResult<T> = {
|
|
266
|
+
success: false,
|
|
267
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
268
|
+
executionTime,
|
|
269
|
+
memoryUsed: 0,
|
|
270
|
+
timestamp: new Date(),
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
this.updateMetrics("executionTime", executionTime);
|
|
274
|
+
this.updateMetrics("successRate", 0);
|
|
275
|
+
|
|
276
|
+
this.emit("execution-error", { executionId, error, executionTime });
|
|
277
|
+
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Execute code in specific isolate context
|
|
284
|
+
*/
|
|
285
|
+
private async executeInIsolate<T>(
|
|
286
|
+
runtimeContext: RuntimeContext,
|
|
287
|
+
options: ExecutionOptions,
|
|
288
|
+
executionId: string
|
|
289
|
+
): Promise<ExecutionResult<T>> {
|
|
290
|
+
const { isolate, context, jail } = runtimeContext;
|
|
291
|
+
const startTime = Date.now();
|
|
292
|
+
|
|
293
|
+
// Update usage stats
|
|
294
|
+
runtimeContext.executionCount++;
|
|
295
|
+
runtimeContext.lastUsedAt = new Date();
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
// Create script with timeout and memory limit
|
|
299
|
+
const script = await isolate.compileScript(options.code, {
|
|
300
|
+
filename: `beddel-runtime-${executionId}.js`,
|
|
301
|
+
produceCachedData: false, // Security: disable code caching
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// Setup execution context
|
|
305
|
+
const executionContext = new ivm.Reference({
|
|
306
|
+
...(options.context || {}),
|
|
307
|
+
executionId,
|
|
308
|
+
timestamp: new Date().toISOString(),
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Execute script
|
|
312
|
+
const result = await script.run(context, {
|
|
313
|
+
timeout: options.timeout || runtimeContext.securityProfile.timeout,
|
|
314
|
+
release: true, // Release memory after execution
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Get memory usage
|
|
318
|
+
const memoryUsed = this.getMemoryUsage(runtimeContext);
|
|
319
|
+
|
|
320
|
+
const executionTime = Date.now() - startTime;
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
success: true,
|
|
324
|
+
result: result as T,
|
|
325
|
+
executionTime,
|
|
326
|
+
memoryUsed,
|
|
327
|
+
timestamp: new Date(),
|
|
328
|
+
};
|
|
329
|
+
} catch (error) {
|
|
330
|
+
const executionTime = Date.now() - startTime;
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
success: false,
|
|
334
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
335
|
+
executionTime,
|
|
336
|
+
memoryUsed: this.getMemoryUsage(runtimeContext),
|
|
337
|
+
timestamp: new Date(),
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Get or create isolate for execution
|
|
344
|
+
*/
|
|
345
|
+
private async getOrCreateIsolate(
|
|
346
|
+
securityProfile: SecurityProfile
|
|
347
|
+
): Promise<RuntimeContext> {
|
|
348
|
+
// Check pool for available isolate
|
|
349
|
+
const availableIsolate = this.pool.find(
|
|
350
|
+
(ctx) => ctx.securityProfile.name === securityProfile.name
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
if (availableIsolate) {
|
|
354
|
+
// Remove from pool and return
|
|
355
|
+
this.pool = this.pool.filter((ctx) => ctx !== availableIsolate);
|
|
356
|
+
return availableIsolate;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Check if we can create new isolate
|
|
360
|
+
const totalIsolates = this.isolates.size + this.pool.length;
|
|
361
|
+
|
|
362
|
+
if (totalIsolates >= this.maxPoolSize) {
|
|
363
|
+
throw new IsolatedRuntimeError(
|
|
364
|
+
`Maximum isolate pool size reached (${this.maxPoolSize})`,
|
|
365
|
+
"POOL_LIMIT_EXCEEDED",
|
|
366
|
+
{ currentPoolSize: totalIsolates, maxPoolSize: this.maxPoolSize }
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Create new isolate
|
|
371
|
+
return await this.createIsolate(securityProfile);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Validate execution options
|
|
376
|
+
*/
|
|
377
|
+
private validateExecutionOptions(options: ExecutionOptions): void {
|
|
378
|
+
if (!options.code || typeof options.code !== "string") {
|
|
379
|
+
throw new IsolatedRuntimeError(
|
|
380
|
+
"Code must be a non-empty string",
|
|
381
|
+
"INVALID_CODE",
|
|
382
|
+
{ codeType: typeof options.code, codeLength: options.code?.length }
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (options.code.length > 1024 * 1024) {
|
|
387
|
+
// 1MB max code size
|
|
388
|
+
throw new IsolatedRuntimeError(
|
|
389
|
+
"Code exceeds maximum size limit (1MB)",
|
|
390
|
+
"CODE_TOO_LARGE",
|
|
391
|
+
{ codeSize: options.code.length }
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const memoryLimit = options.memoryLimit || this.config.memoryLimit;
|
|
396
|
+
if (memoryLimit > 8) {
|
|
397
|
+
// 8MB max
|
|
398
|
+
throw new IsolatedRuntimeError(
|
|
399
|
+
"Memory limit exceeds maximum allowed (8MB)",
|
|
400
|
+
"MEMORY_LIMIT_EXCEEDED",
|
|
401
|
+
{ requestedMemory: memoryLimit, maxMemory: 8 }
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const timeout = options.timeout || runtimeConfig.timeout;
|
|
406
|
+
if (timeout > 30000) {
|
|
407
|
+
// 30s max
|
|
408
|
+
throw new IsolatedRuntimeError(
|
|
409
|
+
"Timeout exceeds maximum allowed (30s)",
|
|
410
|
+
"TIMEOUT_EXCEEDED",
|
|
411
|
+
{ requestedTimeout: timeout, maxTimeout: 30000 }
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Calculate memory usage for isolate
|
|
418
|
+
*/
|
|
419
|
+
private getMemoryUsage(runtimeContext: RuntimeContext): number {
|
|
420
|
+
try {
|
|
421
|
+
const heapStatistics = runtimeContext.isolate.getHeapStatisticsSync();
|
|
422
|
+
return (heapStatistics.used_heap_size || 0) / (1024 * 1024); // MB
|
|
423
|
+
} catch (error) {
|
|
424
|
+
this.emit("error", {
|
|
425
|
+
message: "Failed to get memory usage",
|
|
426
|
+
error,
|
|
427
|
+
context: "getMemoryUsage",
|
|
428
|
+
});
|
|
429
|
+
return 0;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Update metrics tracking
|
|
435
|
+
*/
|
|
436
|
+
private updateMetrics(metric: string, value: number): void {
|
|
437
|
+
if (!this.metrics.has(metric)) {
|
|
438
|
+
this.metrics.set(metric, []);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const values = this.metrics.get(metric)!;
|
|
442
|
+
values.push(value);
|
|
443
|
+
|
|
444
|
+
// Keep only last 1000 values
|
|
445
|
+
if (values.length > 1000) {
|
|
446
|
+
values.shift();
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Generate unique execution ID
|
|
452
|
+
*/
|
|
453
|
+
private generateExecutionId(): string {
|
|
454
|
+
return `exec-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Generate audit hash for execution
|
|
459
|
+
*/
|
|
460
|
+
private generateAuditHash(
|
|
461
|
+
options: ExecutionOptions,
|
|
462
|
+
result: ExecutionResult
|
|
463
|
+
): string {
|
|
464
|
+
const crypto = require("node:crypto");
|
|
465
|
+
const auditData = {
|
|
466
|
+
code: options.code,
|
|
467
|
+
context: options.context,
|
|
468
|
+
result: result.result,
|
|
469
|
+
success: result.success,
|
|
470
|
+
executionTime: result.executionTime,
|
|
471
|
+
memoryUsed: result.memoryUsed,
|
|
472
|
+
timestamp: result.timestamp,
|
|
473
|
+
tenantId: options.tenantId,
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
return crypto
|
|
477
|
+
.createHash(this.config.auditHashAlgorithm)
|
|
478
|
+
.update(JSON.stringify(auditData))
|
|
479
|
+
.digest("hex");
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Cleanup idle isolates
|
|
484
|
+
*/
|
|
485
|
+
private cleanupPool(): void {
|
|
486
|
+
const now = Date.now();
|
|
487
|
+
const idleTimeout = this.config.poolIdleTimeout;
|
|
488
|
+
|
|
489
|
+
// Cleanup pool isolates that have been idle too long
|
|
490
|
+
this.pool = this.pool.filter((isolate) => {
|
|
491
|
+
const idleTime = now - isolate.lastUsedAt.getTime();
|
|
492
|
+
const shouldCleanup =
|
|
493
|
+
idleTime > idleTimeout && this.pool.length > this.minPoolSize;
|
|
494
|
+
|
|
495
|
+
if (shouldCleanup) {
|
|
496
|
+
try {
|
|
497
|
+
isolate.isolate.dispose();
|
|
498
|
+
this.emit("isolate-disposed", {
|
|
499
|
+
isolateId: isolate.createdAt.getTime(),
|
|
500
|
+
idleTime,
|
|
501
|
+
reason: "idle-cleanup",
|
|
502
|
+
});
|
|
503
|
+
} catch (error) {
|
|
504
|
+
this.emit(
|
|
505
|
+
"error",
|
|
506
|
+
new IsolatedRuntimeError(
|
|
507
|
+
"Failed to dispose isolate during cleanup",
|
|
508
|
+
"DISPOSE_ERROR",
|
|
509
|
+
{ error, idleTime }
|
|
510
|
+
)
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return !shouldCleanup;
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Get current metrics
|
|
521
|
+
*/
|
|
522
|
+
public getMetrics(): Record<string, number[]> {
|
|
523
|
+
return Object.fromEntries(this.metrics);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Get pool statistics
|
|
528
|
+
*/
|
|
529
|
+
public getPoolStats(): {
|
|
530
|
+
totalIsolates: number;
|
|
531
|
+
poolSize: number;
|
|
532
|
+
activeExecutions: number;
|
|
533
|
+
minPoolSize: number;
|
|
534
|
+
maxPoolSize: number;
|
|
535
|
+
} {
|
|
536
|
+
return {
|
|
537
|
+
totalIsolates: this.isolates.size + this.pool.length,
|
|
538
|
+
poolSize: this.pool.length,
|
|
539
|
+
activeExecutions: this.activeExecutions.size,
|
|
540
|
+
minPoolSize: this.minPoolSize,
|
|
541
|
+
maxPoolSize: this.maxPoolSize,
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Dispose of all isolates and cleanup resources
|
|
547
|
+
*/
|
|
548
|
+
public async dispose(): Promise<void> {
|
|
549
|
+
clearInterval(this.cleanupInterval);
|
|
550
|
+
|
|
551
|
+
// Dispose all pool isolates
|
|
552
|
+
for (const isolate of this.pool) {
|
|
553
|
+
try {
|
|
554
|
+
isolate.isolate.dispose();
|
|
555
|
+
} catch (error) {
|
|
556
|
+
this.emit("error", {
|
|
557
|
+
message: "Failed to dispose isolate during cleanup",
|
|
558
|
+
error,
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
this.pool = [];
|
|
564
|
+
this.activeExecutions.clear();
|
|
565
|
+
|
|
566
|
+
this.emit("disposed", { cleanupTime: Date.now() });
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Singleton instance
|
|
571
|
+
export const runtimeManager = new IsolatedRuntimeManager();
|
|
572
|
+
export default IsolatedRuntimeManager;
|