lavs-runtime 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 +75 -0
- package/dist/function-executor.d.ts +26 -0
- package/dist/function-executor.d.ts.map +1 -0
- package/dist/function-executor.js +116 -0
- package/dist/function-executor.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +37 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +187 -0
- package/dist/loader.js.map +1 -0
- package/dist/permission-checker.d.ts +86 -0
- package/dist/permission-checker.d.ts.map +1 -0
- package/dist/permission-checker.js +172 -0
- package/dist/permission-checker.js.map +1 -0
- package/dist/rate-limiter.d.ts +57 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +84 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/script-executor.d.ts +70 -0
- package/dist/script-executor.d.ts.map +1 -0
- package/dist/script-executor.js +314 -0
- package/dist/script-executor.js.map +1 -0
- package/dist/subscription-manager.d.ts +106 -0
- package/dist/subscription-manager.d.ts.map +1 -0
- package/dist/subscription-manager.js +257 -0
- package/dist/subscription-manager.js.map +1 -0
- package/dist/tool-generator.d.ts +51 -0
- package/dist/tool-generator.d.ts.map +1 -0
- package/dist/tool-generator.js +147 -0
- package/dist/tool-generator.js.map +1 -0
- package/dist/types.d.ts +171 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +38 -0
- package/dist/types.js.map +1 -0
- package/dist/validator.d.ts +94 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +187 -0
- package/dist/validator.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LAVS Permission Checker
|
|
4
|
+
*
|
|
5
|
+
* Enforces permission constraints declared in LAVS manifests.
|
|
6
|
+
*
|
|
7
|
+
* ## Enforcement Model
|
|
8
|
+
*
|
|
9
|
+
* LAVS permissions have two enforcement levels:
|
|
10
|
+
*
|
|
11
|
+
* | Permission | Level | What is checked |
|
|
12
|
+
* |-----------------|----------|------------------------------------------------|
|
|
13
|
+
* | Path traversal | ENFORCED | Handler cwd and command paths are validated |
|
|
14
|
+
* | fileAccess | ADVISORY | Glob pattern matching at dispatch time; |
|
|
15
|
+
* | | | NOT intercepted at OS/syscall level during |
|
|
16
|
+
* | | | script execution. Scripts can still access |
|
|
17
|
+
* | | | files the process has OS-level permission for. |
|
|
18
|
+
* | networkAccess | ADVISORY | Declared for auditing; not enforced at runtime. |
|
|
19
|
+
* | | | Use OS-level isolation (nsjail, Docker) for |
|
|
20
|
+
* | | | strict enforcement. |
|
|
21
|
+
* | maxExecTime | ENFORCED | Handler killed via SIGTERM/SIGKILL on timeout. |
|
|
22
|
+
* | maxMemory | ADVISORY | Not enforced in current runtime. |
|
|
23
|
+
*
|
|
24
|
+
* Future: Consider OS-level sandboxing for fileAccess and networkAccess.
|
|
25
|
+
*/
|
|
26
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
27
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
28
|
+
};
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.PermissionChecker = void 0;
|
|
31
|
+
const path_1 = __importDefault(require("path"));
|
|
32
|
+
const minimatch_1 = require("minimatch");
|
|
33
|
+
const types_1 = require("./types");
|
|
34
|
+
/**
|
|
35
|
+
* LAVS Permission Checker - enforces manifest-declared security constraints
|
|
36
|
+
*/
|
|
37
|
+
class PermissionChecker {
|
|
38
|
+
/**
|
|
39
|
+
* Merge manifest-level and endpoint-level permissions.
|
|
40
|
+
* Endpoint-level permissions take precedence over manifest-level.
|
|
41
|
+
*
|
|
42
|
+
* @param manifestPermissions - Manifest-level permissions (defaults)
|
|
43
|
+
* @param endpointPermissions - Endpoint-level permissions (overrides)
|
|
44
|
+
* @returns Merged permissions object
|
|
45
|
+
*/
|
|
46
|
+
mergePermissions(manifestPermissions, endpointPermissions) {
|
|
47
|
+
if (!manifestPermissions && !endpointPermissions) {
|
|
48
|
+
return {};
|
|
49
|
+
}
|
|
50
|
+
if (!manifestPermissions) {
|
|
51
|
+
return { ...endpointPermissions };
|
|
52
|
+
}
|
|
53
|
+
if (!endpointPermissions) {
|
|
54
|
+
return { ...manifestPermissions };
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
fileAccess: endpointPermissions.fileAccess ?? manifestPermissions.fileAccess,
|
|
58
|
+
networkAccess: endpointPermissions.networkAccess ?? manifestPermissions.networkAccess,
|
|
59
|
+
maxExecutionTime: endpointPermissions.maxExecutionTime ?? manifestPermissions.maxExecutionTime,
|
|
60
|
+
maxMemory: endpointPermissions.maxMemory ?? manifestPermissions.maxMemory,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if a target path is within the allowed base directory.
|
|
65
|
+
* Prevents path traversal attacks (e.g., ../../etc/passwd).
|
|
66
|
+
*
|
|
67
|
+
* @param targetPath - The path to check (absolute or relative)
|
|
68
|
+
* @param allowedBase - The allowed base directory (absolute)
|
|
69
|
+
* @throws LAVSError with code PermissionDenied if path is outside allowed base
|
|
70
|
+
*/
|
|
71
|
+
checkPathTraversal(targetPath, allowedBase) {
|
|
72
|
+
const resolvedTarget = path_1.default.resolve(allowedBase, targetPath);
|
|
73
|
+
const normalizedBase = path_1.default.resolve(allowedBase);
|
|
74
|
+
// Ensure resolved target is within or equal to the allowed base
|
|
75
|
+
if (!resolvedTarget.startsWith(normalizedBase + path_1.default.sep) && resolvedTarget !== normalizedBase) {
|
|
76
|
+
throw new types_1.LAVSError(types_1.LAVSErrorCode.PermissionDenied, `Path traversal detected: '${targetPath}' resolves outside allowed directory '${allowedBase}'`, { resolvedPath: resolvedTarget, allowedBase: normalizedBase });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if a handler's working directory is within the allowed base.
|
|
81
|
+
*
|
|
82
|
+
* @param handler - Script handler with optional cwd
|
|
83
|
+
* @param agentDir - Agent directory (the allowed base)
|
|
84
|
+
* @throws LAVSError with code PermissionDenied if cwd is outside agent directory
|
|
85
|
+
*/
|
|
86
|
+
checkHandlerCwd(handler, agentDir) {
|
|
87
|
+
if (!handler.cwd) {
|
|
88
|
+
return; // No custom cwd, will use agentDir as default
|
|
89
|
+
}
|
|
90
|
+
this.checkPathTraversal(handler.cwd, agentDir);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if file access patterns allow a given path.
|
|
94
|
+
* Uses glob matching against permissions.fileAccess patterns.
|
|
95
|
+
*
|
|
96
|
+
* @param filePath - The file path to check (relative to agent dir)
|
|
97
|
+
* @param permissions - Permission constraints including fileAccess patterns
|
|
98
|
+
* @returns true if access is allowed, false otherwise
|
|
99
|
+
*/
|
|
100
|
+
checkFileAccess(filePath, permissions) {
|
|
101
|
+
// No fileAccess restrictions - allow all
|
|
102
|
+
if (!permissions.fileAccess || permissions.fileAccess.length === 0) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
// Normalize the file path
|
|
106
|
+
const normalizedPath = filePath.startsWith('./') ? filePath : `./${filePath}`;
|
|
107
|
+
// First check deny patterns (negative patterns take precedence)
|
|
108
|
+
for (const pattern of permissions.fileAccess) {
|
|
109
|
+
if (pattern.startsWith('!')) {
|
|
110
|
+
if ((0, minimatch_1.minimatch)(normalizedPath, pattern.slice(1))) {
|
|
111
|
+
return false; // Explicitly denied
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Then check allow patterns
|
|
116
|
+
for (const pattern of permissions.fileAccess) {
|
|
117
|
+
if (!pattern.startsWith('!')) {
|
|
118
|
+
if ((0, minimatch_1.minimatch)(normalizedPath, pattern)) {
|
|
119
|
+
return true; // Allowed
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// No positive pattern matched - deny by default
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get the effective execution timeout for a handler.
|
|
128
|
+
* Priority: handler.timeout > permissions.maxExecutionTime > default (30000ms)
|
|
129
|
+
*
|
|
130
|
+
* @param handler - Script handler with optional timeout
|
|
131
|
+
* @param permissions - Permission constraints with optional maxExecutionTime
|
|
132
|
+
* @param defaultTimeout - Default timeout in milliseconds (default: 30000)
|
|
133
|
+
* @returns Effective timeout in milliseconds
|
|
134
|
+
*/
|
|
135
|
+
getEffectiveTimeout(handler, permissions, defaultTimeout = 30000) {
|
|
136
|
+
// Handler-level timeout takes precedence
|
|
137
|
+
if (handler.timeout != null && handler.timeout > 0) {
|
|
138
|
+
// But cannot exceed permission-level max
|
|
139
|
+
if (permissions.maxExecutionTime != null && permissions.maxExecutionTime > 0) {
|
|
140
|
+
return Math.min(handler.timeout, permissions.maxExecutionTime);
|
|
141
|
+
}
|
|
142
|
+
return handler.timeout;
|
|
143
|
+
}
|
|
144
|
+
// Permission-level timeout
|
|
145
|
+
if (permissions.maxExecutionTime != null && permissions.maxExecutionTime > 0) {
|
|
146
|
+
return permissions.maxExecutionTime;
|
|
147
|
+
}
|
|
148
|
+
return defaultTimeout;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Run all permission checks for a script handler execution.
|
|
152
|
+
* This is a convenience method that combines multiple checks.
|
|
153
|
+
*
|
|
154
|
+
* @param handler - Script handler configuration
|
|
155
|
+
* @param permissions - Merged permissions
|
|
156
|
+
* @param agentDir - Agent base directory
|
|
157
|
+
* @throws LAVSError if any permission check fails
|
|
158
|
+
*/
|
|
159
|
+
assertAllowed(handler, permissions, agentDir) {
|
|
160
|
+
// 1. Check handler cwd for path traversal
|
|
161
|
+
this.checkHandlerCwd(handler, agentDir);
|
|
162
|
+
// 2. Check script command path if it looks like a file path
|
|
163
|
+
if (handler.command && (handler.command.includes('/') || handler.command.includes('\\'))) {
|
|
164
|
+
// Only check relative paths (absolute paths are resolved by loader)
|
|
165
|
+
if (!path_1.default.isAbsolute(handler.command)) {
|
|
166
|
+
this.checkPathTraversal(handler.command, agentDir);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.PermissionChecker = PermissionChecker;
|
|
172
|
+
//# sourceMappingURL=permission-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-checker.js","sourceRoot":"","sources":["../src/permission-checker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LAVS Rate Limiter
|
|
3
|
+
*
|
|
4
|
+
* Simple in-memory rate limiter for LAVS endpoint calls.
|
|
5
|
+
* Uses a sliding window counter algorithm.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Rate limit configuration
|
|
9
|
+
*/
|
|
10
|
+
export interface RateLimitConfig {
|
|
11
|
+
/** Maximum number of requests allowed in the window */
|
|
12
|
+
maxRequests: number;
|
|
13
|
+
/** Time window in milliseconds */
|
|
14
|
+
windowMs: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Rate limit check result
|
|
18
|
+
*/
|
|
19
|
+
export interface RateLimitResult {
|
|
20
|
+
allowed: boolean;
|
|
21
|
+
remaining: number;
|
|
22
|
+
resetAt: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* LAVS Rate Limiter - prevents excessive endpoint calls
|
|
26
|
+
*/
|
|
27
|
+
export declare class LAVSRateLimiter {
|
|
28
|
+
private windows;
|
|
29
|
+
private defaultConfig;
|
|
30
|
+
/**
|
|
31
|
+
* Create a rate limiter with default configuration
|
|
32
|
+
* @param config - Default rate limit config (default: 60 requests per minute)
|
|
33
|
+
*/
|
|
34
|
+
constructor(config?: Partial<RateLimitConfig>);
|
|
35
|
+
/**
|
|
36
|
+
* Check if a request is allowed under the rate limit.
|
|
37
|
+
*
|
|
38
|
+
* @param key - Rate limit key (e.g., `${agentId}:${endpointId}`)
|
|
39
|
+
* @param config - Optional per-key override config
|
|
40
|
+
* @returns Rate limit check result
|
|
41
|
+
*/
|
|
42
|
+
check(key: string, config?: Partial<RateLimitConfig>): RateLimitResult;
|
|
43
|
+
/**
|
|
44
|
+
* Reset rate limit for a key
|
|
45
|
+
*/
|
|
46
|
+
reset(key: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Clear all rate limit entries
|
|
49
|
+
*/
|
|
50
|
+
clearAll(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Clean up expired windows to prevent memory leaks.
|
|
53
|
+
* Should be called periodically.
|
|
54
|
+
*/
|
|
55
|
+
cleanup(): void;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,aAAa,CAAkB;IAEvC;;;OAGG;gBACS,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IAO7C;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe;IA+BtE;;OAEG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB;;OAEG;IACH,QAAQ,IAAI,IAAI;IAIhB;;;OAGG;IACH,OAAO,IAAI,IAAI;CAQhB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LAVS Rate Limiter
|
|
4
|
+
*
|
|
5
|
+
* Simple in-memory rate limiter for LAVS endpoint calls.
|
|
6
|
+
* Uses a sliding window counter algorithm.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.LAVSRateLimiter = void 0;
|
|
10
|
+
/**
|
|
11
|
+
* LAVS Rate Limiter - prevents excessive endpoint calls
|
|
12
|
+
*/
|
|
13
|
+
class LAVSRateLimiter {
|
|
14
|
+
windows = new Map();
|
|
15
|
+
defaultConfig;
|
|
16
|
+
/**
|
|
17
|
+
* Create a rate limiter with default configuration
|
|
18
|
+
* @param config - Default rate limit config (default: 60 requests per minute)
|
|
19
|
+
*/
|
|
20
|
+
constructor(config) {
|
|
21
|
+
this.defaultConfig = {
|
|
22
|
+
maxRequests: config?.maxRequests ?? 60,
|
|
23
|
+
windowMs: config?.windowMs ?? 60000,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Check if a request is allowed under the rate limit.
|
|
28
|
+
*
|
|
29
|
+
* @param key - Rate limit key (e.g., `${agentId}:${endpointId}`)
|
|
30
|
+
* @param config - Optional per-key override config
|
|
31
|
+
* @returns Rate limit check result
|
|
32
|
+
*/
|
|
33
|
+
check(key, config) {
|
|
34
|
+
const { maxRequests, windowMs } = { ...this.defaultConfig, ...config };
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
let entry = this.windows.get(key);
|
|
37
|
+
// If no entry or window expired, start a new window
|
|
38
|
+
if (!entry || (now - entry.windowStart) >= windowMs) {
|
|
39
|
+
entry = { count: 0, windowStart: now };
|
|
40
|
+
this.windows.set(key, entry);
|
|
41
|
+
}
|
|
42
|
+
// Check if within limit
|
|
43
|
+
if (entry.count >= maxRequests) {
|
|
44
|
+
return {
|
|
45
|
+
allowed: false,
|
|
46
|
+
remaining: 0,
|
|
47
|
+
resetAt: entry.windowStart + windowMs,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// Increment counter
|
|
51
|
+
entry.count++;
|
|
52
|
+
return {
|
|
53
|
+
allowed: true,
|
|
54
|
+
remaining: maxRequests - entry.count,
|
|
55
|
+
resetAt: entry.windowStart + windowMs,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Reset rate limit for a key
|
|
60
|
+
*/
|
|
61
|
+
reset(key) {
|
|
62
|
+
this.windows.delete(key);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Clear all rate limit entries
|
|
66
|
+
*/
|
|
67
|
+
clearAll() {
|
|
68
|
+
this.windows.clear();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Clean up expired windows to prevent memory leaks.
|
|
72
|
+
* Should be called periodically.
|
|
73
|
+
*/
|
|
74
|
+
cleanup() {
|
|
75
|
+
const now = Date.now();
|
|
76
|
+
for (const [key, entry] of this.windows.entries()) {
|
|
77
|
+
if ((now - entry.windowStart) >= this.defaultConfig.windowMs * 2) {
|
|
78
|
+
this.windows.delete(key);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.LAVSRateLimiter = LAVSRateLimiter;
|
|
84
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AA0BH;;GAEG;AACH,MAAa,eAAe;IAClB,OAAO,GAA6B,IAAI,GAAG,EAAE,CAAC;IAC9C,aAAa,CAAkB;IAEvC;;;OAGG;IACH,YAAY,MAAiC;QAC3C,IAAI,CAAC,aAAa,GAAG;YACnB,WAAW,EAAE,MAAM,EAAE,WAAW,IAAI,EAAE;YACtC,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,KAAK;SACpC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,GAAW,EAAE,MAAiC;QAClD,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,aAAa,EAAE,GAAG,MAAM,EAAE,CAAC;QACvE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAElC,oDAAoD;QACpD,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,QAAQ,EAAE,CAAC;YACpD,KAAK,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC;YACvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;QAED,wBAAwB;QACxB,IAAI,KAAK,CAAC,KAAK,IAAI,WAAW,EAAE,CAAC;YAC/B,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,SAAS,EAAE,CAAC;gBACZ,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,QAAQ;aACtC,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,KAAK,CAAC,KAAK,EAAE,CAAC;QAEd,OAAO;YACL,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,WAAW,GAAG,KAAK,CAAC,KAAK;YACpC,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,QAAQ;SACtC,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAW;QACf,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAClD,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;gBACjE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA/ED,0CA+EC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LAVS Script Executor
|
|
3
|
+
*
|
|
4
|
+
* Executes script handlers with proper input/output handling and security.
|
|
5
|
+
*/
|
|
6
|
+
import { ScriptHandler, ExecutionContext } from './types';
|
|
7
|
+
export declare class ScriptExecutor {
|
|
8
|
+
/**
|
|
9
|
+
* Execute a script handler
|
|
10
|
+
* @param handler - Script handler configuration
|
|
11
|
+
* @param input - Input data to pass to script
|
|
12
|
+
* @param context - Execution context with permissions
|
|
13
|
+
* @returns Script output (parsed as JSON)
|
|
14
|
+
*/
|
|
15
|
+
execute(handler: ScriptHandler, input: any, context: ExecutionContext): Promise<any>;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve argument templates with input values
|
|
18
|
+
* Replaces {{path.to.value}} with actual values from input
|
|
19
|
+
*/
|
|
20
|
+
private resolveArgs;
|
|
21
|
+
/**
|
|
22
|
+
* Get value from nested object by dot path
|
|
23
|
+
* e.g., "user.name" from { user: { name: "Alice" } } => "Alice"
|
|
24
|
+
* Protects against prototype pollution by blocking __proto__, constructor, prototype keys.
|
|
25
|
+
*/
|
|
26
|
+
private getValueByPath;
|
|
27
|
+
/**
|
|
28
|
+
* Build environment variables for script execution
|
|
29
|
+
*/
|
|
30
|
+
buildEnvironment(handler: ScriptHandler, input: any, context: ExecutionContext): Record<string, string>;
|
|
31
|
+
/**
|
|
32
|
+
* Sensitive environment variable patterns (case-insensitive match).
|
|
33
|
+
* These keywords in variable names indicate potentially sensitive data.
|
|
34
|
+
*/
|
|
35
|
+
private static readonly SENSITIVE_PATTERNS;
|
|
36
|
+
/**
|
|
37
|
+
* Whitelist of variable names that are safe even if they match sensitive patterns.
|
|
38
|
+
* For example, LAVS variables or NODE_ENV.
|
|
39
|
+
*/
|
|
40
|
+
private static readonly SAFE_OVERRIDES;
|
|
41
|
+
/**
|
|
42
|
+
* Filter out environment variables that match sensitive patterns.
|
|
43
|
+
* Variables explicitly declared in handler.env are preserved (they are
|
|
44
|
+
* intentionally set by the manifest author), but inherited vars from
|
|
45
|
+
* process.env that match sensitive patterns are removed.
|
|
46
|
+
*
|
|
47
|
+
* @param env - Environment variables to filter
|
|
48
|
+
* @returns Filtered environment variables
|
|
49
|
+
*/
|
|
50
|
+
filterSensitiveVars(env: Record<string, string>): Record<string, string>;
|
|
51
|
+
/**
|
|
52
|
+
* Get base environment variables (filtered for security)
|
|
53
|
+
* Only include safe variables, exclude sensitive ones
|
|
54
|
+
*/
|
|
55
|
+
getBaseEnvironment(): Record<string, string>;
|
|
56
|
+
/**
|
|
57
|
+
* Convert input object to environment variables
|
|
58
|
+
* Flattens nested objects with underscore notation
|
|
59
|
+
*/
|
|
60
|
+
private inputToEnv;
|
|
61
|
+
/**
|
|
62
|
+
* Capture stdout/stderr from process and wait for completion
|
|
63
|
+
*/
|
|
64
|
+
private captureOutput;
|
|
65
|
+
/**
|
|
66
|
+
* Parse script output as JSON
|
|
67
|
+
*/
|
|
68
|
+
private parseOutput;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=script-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script-executor.d.ts","sourceRoot":"","sources":["../src/script-executor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,aAAa,EACb,gBAAgB,EAGjB,MAAM,SAAS,CAAC;AAEjB,qBAAa,cAAc;IACzB;;;;;;OAMG;IACG,OAAO,CACX,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,GAAG,EACV,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,GAAG,CAAC;IAmFf;;;OAGG;IACH,OAAO,CAAC,WAAW;IAWnB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAiBtB;;OAEG;IACH,gBAAgB,CACd,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,GAAG,EACV,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAsBzB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAWxC;IAEF;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAKnC;IAEH;;;;;;;;OAQG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAwBxE;;;OAGG;IACH,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IA0B5C;;;OAGG;IACH,OAAO,CAAC,UAAU;IAoBlB;;OAEG;YACW,aAAa;IAoD3B;;OAEG;IACH,OAAO,CAAC,WAAW;CAkCpB"}
|