git-doc-mcp 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/LICENSE +21 -0
- package/README.md +543 -0
- package/dist/audit/index.d.ts +2 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +2 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/logger.d.ts +81 -0
- package/dist/audit/logger.d.ts.map +1 -0
- package/dist/audit/logger.js +179 -0
- package/dist/audit/logger.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +44 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +360 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/index.d.ts +21 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +71 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/http/client.d.ts +39 -0
- package/dist/http/client.d.ts.map +1 -0
- package/dist/http/client.js +114 -0
- package/dist/http/client.js.map +1 -0
- package/dist/http/index.d.ts +7 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +7 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/redirect-utils.d.ts +27 -0
- package/dist/http/redirect-utils.d.ts.map +1 -0
- package/dist/http/redirect-utils.js +73 -0
- package/dist/http/redirect-utils.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest/index.d.ts +7 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +7 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/loader.d.ts +55 -0
- package/dist/manifest/loader.d.ts.map +1 -0
- package/dist/manifest/loader.js +222 -0
- package/dist/manifest/loader.js.map +1 -0
- package/dist/manifest/schema.d.ts +909 -0
- package/dist/manifest/schema.d.ts.map +1 -0
- package/dist/manifest/schema.js +148 -0
- package/dist/manifest/schema.js.map +1 -0
- package/dist/rate-limit/index.d.ts +6 -0
- package/dist/rate-limit/index.d.ts.map +1 -0
- package/dist/rate-limit/index.js +6 -0
- package/dist/rate-limit/index.js.map +1 -0
- package/dist/rate-limit/limiter.d.ts +38 -0
- package/dist/rate-limit/limiter.d.ts.map +1 -0
- package/dist/rate-limit/limiter.js +55 -0
- package/dist/rate-limit/limiter.js.map +1 -0
- package/dist/sandbox/context.d.ts +69 -0
- package/dist/sandbox/context.d.ts.map +1 -0
- package/dist/sandbox/context.js +134 -0
- package/dist/sandbox/context.js.map +1 -0
- package/dist/sandbox/executor.d.ts +50 -0
- package/dist/sandbox/executor.d.ts.map +1 -0
- package/dist/sandbox/executor.js +259 -0
- package/dist/sandbox/executor.js.map +1 -0
- package/dist/sandbox/index.d.ts +8 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +8 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/url-validator.d.ts +40 -0
- package/dist/sandbox/url-validator.d.ts.map +1 -0
- package/dist/sandbox/url-validator.js +178 -0
- package/dist/sandbox/url-validator.js.map +1 -0
- package/dist/secrets/index.d.ts +7 -0
- package/dist/secrets/index.d.ts.map +1 -0
- package/dist/secrets/index.js +7 -0
- package/dist/secrets/index.js.map +1 -0
- package/dist/secrets/manager.d.ts +55 -0
- package/dist/secrets/manager.d.ts.map +1 -0
- package/dist/secrets/manager.js +94 -0
- package/dist/secrets/manager.js.map +1 -0
- package/dist/secrets/patterns.d.ts +33 -0
- package/dist/secrets/patterns.d.ts.map +1 -0
- package/dist/secrets/patterns.js +71 -0
- package/dist/secrets/patterns.js.map +1 -0
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +6 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/mcp.d.ts +60 -0
- package/dist/server/mcp.d.ts.map +1 -0
- package/dist/server/mcp.js +173 -0
- package/dist/server/mcp.js.map +1 -0
- package/dist/worker/index.d.ts +7 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +7 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/process.d.ts +64 -0
- package/dist/worker/process.d.ts.map +1 -0
- package/dist/worker/process.js +222 -0
- package/dist/worker/process.js.map +1 -0
- package/dist/worker/protocol.d.ts +83 -0
- package/dist/worker/protocol.d.ts.map +1 -0
- package/dist/worker/protocol.js +55 -0
- package/dist/worker/protocol.js.map +1 -0
- package/dist/worker/worker-entry.d.ts +30 -0
- package/dist/worker/worker-entry.d.ts.map +1 -0
- package/dist/worker/worker-entry.js +136 -0
- package/dist/worker/worker-entry.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox executor using isolated-vm.
|
|
3
|
+
* @module sandbox/executor
|
|
4
|
+
*/
|
|
5
|
+
import ivm from 'isolated-vm';
|
|
6
|
+
import { createActionContext } from './context.js';
|
|
7
|
+
/**
|
|
8
|
+
* Default sandbox options.
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_SANDBOX_OPTIONS = {
|
|
11
|
+
memoryLimit: 128 * 1024 * 1024, // 128MB
|
|
12
|
+
cpuTimeLimit: 30000, // 30 seconds
|
|
13
|
+
wallTimeLimit: 60000, // 60 seconds
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Result size limits.
|
|
17
|
+
*/
|
|
18
|
+
const MAX_RESULT_SIZE = 1024 * 1024; // 1MB
|
|
19
|
+
const MAX_CONTENT_ITEMS = 100;
|
|
20
|
+
/**
|
|
21
|
+
* Validate and truncate result if too large.
|
|
22
|
+
*/
|
|
23
|
+
export function validateResultSize(result) {
|
|
24
|
+
// Check content item count
|
|
25
|
+
if (result.content.length > MAX_CONTENT_ITEMS) {
|
|
26
|
+
return {
|
|
27
|
+
content: result.content.slice(0, MAX_CONTENT_ITEMS).concat([
|
|
28
|
+
{ type: 'text', text: `[Truncated: ${result.content.length - MAX_CONTENT_ITEMS} more items]` }
|
|
29
|
+
]),
|
|
30
|
+
isError: result.isError,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Check total size
|
|
34
|
+
const serializedSize = JSON.stringify(result).length;
|
|
35
|
+
if (serializedSize > MAX_RESULT_SIZE) {
|
|
36
|
+
// Truncate text content
|
|
37
|
+
const truncatedContent = result.content.map(item => {
|
|
38
|
+
if (item.type === 'text' && item.text.length > 10000) {
|
|
39
|
+
return { type: 'text', text: item.text.slice(0, 10000) + '\n...[truncated]' };
|
|
40
|
+
}
|
|
41
|
+
return item;
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
content: truncatedContent,
|
|
45
|
+
isError: result.isError,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Transform ES module action code to CommonJS-style for isolated-vm.
|
|
52
|
+
*/
|
|
53
|
+
export function transformActionCode(code) {
|
|
54
|
+
// Handle `export default function name(...)` pattern
|
|
55
|
+
// export default async function echo(input, ctx) -> async function __default__(input, ctx)
|
|
56
|
+
let transformed = code.replace(/export\s+default\s+(async\s+)?function\s+\w+\s*\(/g, '$1function __default__(');
|
|
57
|
+
// Handle `export default function(...)` (anonymous) - unlikely but handle it
|
|
58
|
+
transformed = transformed.replace(/export\s+default\s+(async\s+)?function\s*\(/g, '$1function __default__(');
|
|
59
|
+
// Handle `export default (async function...)` expressions
|
|
60
|
+
transformed = transformed.replace(/export\s+default\s+\((async\s+)?function/g, '(__default__ = $1function');
|
|
61
|
+
// Handle `export default { ... }` objects or arrow functions
|
|
62
|
+
// export default async (input, ctx) => { ... }
|
|
63
|
+
if (!transformed.includes('function __default__')) {
|
|
64
|
+
// Check for arrow function export
|
|
65
|
+
const arrowMatch = code.match(/export\s+default\s+(async\s+)?\(([^)]*)\)\s*=>\s*/);
|
|
66
|
+
if (arrowMatch) {
|
|
67
|
+
const isAsync = arrowMatch[1] ? 'async ' : '';
|
|
68
|
+
const params = arrowMatch[2];
|
|
69
|
+
const matchEnd = arrowMatch.index + arrowMatch[0].length;
|
|
70
|
+
const afterArrow = code.slice(matchEnd);
|
|
71
|
+
if (afterArrow.trimStart().startsWith('{')) {
|
|
72
|
+
// Block body: export default async (input) => { ... } → async function __default__(input) { ... }
|
|
73
|
+
transformed = code.replace(/export\s+default\s+(async\s+)?\([^)]*\)\s*=>\s*/, `${isAsync}function __default__(${params}) `);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// Expression body: export default (input) => expr; → function __default__(input) { return expr; }
|
|
77
|
+
const beforeExport = code.slice(0, arrowMatch.index);
|
|
78
|
+
const expr = afterArrow.replace(/;\s*$/, '');
|
|
79
|
+
transformed = beforeExport + `${isAsync}function __default__(${params}) { return ${expr}; }`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Generic export default replacement
|
|
84
|
+
transformed = code.replace(/export\s+default\s+/g, 'const __default__ = ');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Remove other exports (they're not needed for action execution)
|
|
88
|
+
transformed = transformed.replace(/export\s+\{[^}]*\}/g, '');
|
|
89
|
+
transformed = transformed.replace(/export\s+(const|let|var|function|class)\s+/g, '$1 ');
|
|
90
|
+
return transformed;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Execute an action script in an isolated sandbox.
|
|
94
|
+
*
|
|
95
|
+
* The action code should export a default async function:
|
|
96
|
+
* ```javascript
|
|
97
|
+
* export default async function myAction(input, ctx) {
|
|
98
|
+
* return { content: [{ type: 'text', text: 'Result' }] };
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export async function executeAction(actionCode, input, contextOptions, sandboxOptions = {}) {
|
|
103
|
+
const opts = { ...DEFAULT_SANDBOX_OPTIONS, ...sandboxOptions };
|
|
104
|
+
// Create action context
|
|
105
|
+
const actionContext = createActionContext(contextOptions);
|
|
106
|
+
// Create isolated-vm isolate
|
|
107
|
+
const isolate = new ivm.Isolate({
|
|
108
|
+
memoryLimit: opts.memoryLimit,
|
|
109
|
+
});
|
|
110
|
+
try {
|
|
111
|
+
// Transform ES module syntax to CommonJS-style
|
|
112
|
+
const transformedCode = transformActionCode(actionCode);
|
|
113
|
+
// Create context
|
|
114
|
+
const context = await isolate.createContext();
|
|
115
|
+
const global = context.global;
|
|
116
|
+
// Create a deferred result holder
|
|
117
|
+
let resolveResult;
|
|
118
|
+
let rejectResult;
|
|
119
|
+
const resultPromise = new Promise((resolve, reject) => {
|
|
120
|
+
resolveResult = resolve;
|
|
121
|
+
rejectResult = reject;
|
|
122
|
+
});
|
|
123
|
+
// Create log callback
|
|
124
|
+
const logCallback = (level, message) => {
|
|
125
|
+
actionContext.log(level, message);
|
|
126
|
+
};
|
|
127
|
+
// Create fetch wrapper that returns a JSON string (not an object).
|
|
128
|
+
// isolated-vm cannot transfer objects or Promises across the boundary
|
|
129
|
+
// via Reference.apply(), but strings transfer cleanly.
|
|
130
|
+
const fetchCallback = async (url, optionsJson) => {
|
|
131
|
+
try {
|
|
132
|
+
const options = optionsJson ? JSON.parse(optionsJson) : {};
|
|
133
|
+
const response = await actionContext.fetch(url, options);
|
|
134
|
+
const text = await response.text();
|
|
135
|
+
return JSON.stringify({
|
|
136
|
+
ok: response.ok,
|
|
137
|
+
status: response.status,
|
|
138
|
+
statusText: response.statusText,
|
|
139
|
+
text: text,
|
|
140
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
return JSON.stringify({
|
|
145
|
+
ok: false,
|
|
146
|
+
status: 0,
|
|
147
|
+
statusText: 'Error',
|
|
148
|
+
error: error instanceof Error ? error.message : String(error),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
// Create getSecret wrapper (returns null instead of undefined for isolated-vm boundary)
|
|
153
|
+
const getSecretCallback = (name, url) => {
|
|
154
|
+
return actionContext.getSecret(name, url) ?? null;
|
|
155
|
+
};
|
|
156
|
+
// Set up callbacks in the isolate
|
|
157
|
+
// _fetch uses ivm.Reference (not Callback) because it is async.
|
|
158
|
+
// ivm.Callback cannot return Promises across the isolate boundary.
|
|
159
|
+
await global.set('_log', new ivm.Callback(logCallback));
|
|
160
|
+
await global.set('_fetch', new ivm.Reference(fetchCallback));
|
|
161
|
+
await global.set('_resolve', new ivm.Callback((result) => resolveResult(result)));
|
|
162
|
+
await global.set('_reject', new ivm.Callback((error) => rejectResult(new Error(error))));
|
|
163
|
+
await global.set('_input', new ivm.ExternalCopy(input).copyInto());
|
|
164
|
+
await global.set('_getSecret', new ivm.Callback(getSecretCallback));
|
|
165
|
+
await global.set('_manifest', new ivm.ExternalCopy(actionContext.manifest).copyInto());
|
|
166
|
+
// Create the wrapper script with full capture-then-delete pattern (AC17, AC18)
|
|
167
|
+
const wrapperScript = `
|
|
168
|
+
// Capture ALL globals into local const variables BEFORE anything else
|
|
169
|
+
const __fetch__ = _fetch;
|
|
170
|
+
const __log__ = _log;
|
|
171
|
+
const __manifest__ = _manifest;
|
|
172
|
+
const __getSecret__ = _getSecret;
|
|
173
|
+
const __input__ = _input;
|
|
174
|
+
const __resolve__ = _resolve;
|
|
175
|
+
const __reject__ = _reject;
|
|
176
|
+
|
|
177
|
+
// Delete all raw globals immediately
|
|
178
|
+
delete globalThis._fetch;
|
|
179
|
+
delete globalThis._log;
|
|
180
|
+
delete globalThis._resolve;
|
|
181
|
+
delete globalThis._reject;
|
|
182
|
+
delete globalThis._input;
|
|
183
|
+
delete globalThis._manifest;
|
|
184
|
+
delete globalThis._getSecret;
|
|
185
|
+
|
|
186
|
+
// Build ctx from captured locals only
|
|
187
|
+
const ctx = {
|
|
188
|
+
manifest: __manifest__,
|
|
189
|
+
fetch: async (url, options) => {
|
|
190
|
+
// __fetch__ is an ivm.Reference to an async host function.
|
|
191
|
+
// It returns a JSON string; we parse it and add the json() helper.
|
|
192
|
+
const optionsJson = options ? JSON.stringify(options) : undefined;
|
|
193
|
+
const raw = await __fetch__.apply(undefined, [url, optionsJson], { result: { promise: true, copy: true } });
|
|
194
|
+
const res = JSON.parse(raw);
|
|
195
|
+
res.json = function() { return JSON.parse(res.text); };
|
|
196
|
+
return res;
|
|
197
|
+
},
|
|
198
|
+
log: (level, message) => {
|
|
199
|
+
__log__(level, message);
|
|
200
|
+
},
|
|
201
|
+
getSecret: (name, url) => {
|
|
202
|
+
const result = __getSecret__(name, url);
|
|
203
|
+
return result === null ? undefined : result;
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// Transformed action code
|
|
208
|
+
${transformedCode}
|
|
209
|
+
|
|
210
|
+
// Find the action function
|
|
211
|
+
const actionFn = typeof __default__ !== 'undefined' ? __default__ : null;
|
|
212
|
+
|
|
213
|
+
if (typeof actionFn !== 'function') {
|
|
214
|
+
__reject__('Action must export a default async function');
|
|
215
|
+
} else {
|
|
216
|
+
// Execute the action using captured locals
|
|
217
|
+
Promise.resolve()
|
|
218
|
+
.then(() => actionFn(__input__, ctx))
|
|
219
|
+
.then(result => {
|
|
220
|
+
if (!result || !Array.isArray(result.content)) {
|
|
221
|
+
__reject__('Action must return { content: [...] }');
|
|
222
|
+
} else {
|
|
223
|
+
__resolve__(result);
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
.catch(err => {
|
|
227
|
+
__reject__(err.message || String(err));
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
`;
|
|
231
|
+
// Compile and run the script
|
|
232
|
+
const script = await isolate.compileScript(wrapperScript);
|
|
233
|
+
// Run with timeout
|
|
234
|
+
await script.run(context, {
|
|
235
|
+
timeout: opts.cpuTimeLimit,
|
|
236
|
+
});
|
|
237
|
+
// Wait for the result with wall timeout
|
|
238
|
+
const rawResult = await Promise.race([
|
|
239
|
+
resultPromise,
|
|
240
|
+
new Promise((_, reject) => {
|
|
241
|
+
setTimeout(() => reject(new Error('Action timeout')), opts.wallTimeLimit);
|
|
242
|
+
}),
|
|
243
|
+
]);
|
|
244
|
+
// Validate and truncate result if too large
|
|
245
|
+
return validateResultSize(rawResult);
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
249
|
+
return {
|
|
250
|
+
content: [{ type: 'text', text: `Execution error: ${message}` }],
|
|
251
|
+
isError: true,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
finally {
|
|
255
|
+
// Clean up
|
|
256
|
+
isolate.dispose();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/sandbox/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL validation for SSRF protection and redirect handling.
|
|
3
|
+
* @module sandbox/url-validator
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* URL validation options.
|
|
7
|
+
*/
|
|
8
|
+
export interface UrlValidationOptions {
|
|
9
|
+
/** Allowed URL schemes (default: ['https']) */
|
|
10
|
+
allowedSchemes?: string[];
|
|
11
|
+
/** Maximum number of redirects to follow */
|
|
12
|
+
maxRedirects?: number;
|
|
13
|
+
/** Whether to allow localhost (default: false) */
|
|
14
|
+
allowLocalhost?: boolean;
|
|
15
|
+
/** Custom blocked IP ranges */
|
|
16
|
+
blockedIpRanges?: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Check if IP is in CIDR range (supports IPv4 and IPv6).
|
|
20
|
+
*/
|
|
21
|
+
export declare function isIpInCidr(ip: string, cidr: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Validate URL for SSRF protection.
|
|
24
|
+
* @throws Error if URL is invalid or blocked
|
|
25
|
+
*/
|
|
26
|
+
export declare function validateUrl(urlString: string, options?: UrlValidationOptions): Promise<URL>;
|
|
27
|
+
/**
|
|
28
|
+
* Validate a redirect URL.
|
|
29
|
+
* Re-validates all SSRF protections for the redirect target.
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateRedirect(redirectUrl: string, _originalUrl: string, options?: UrlValidationOptions): Promise<URL>;
|
|
32
|
+
/**
|
|
33
|
+
* Check if a URL is HTTPS.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isHttps(url: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Extract hostname from URL.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getHostname(url: string): string | undefined;
|
|
40
|
+
//# sourceMappingURL=url-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-validator.d.ts","sourceRoot":"","sources":["../../src/sandbox/url-validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,+BAA+B;IAC/B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAiDD;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAsC5D;AA8BD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,GAAG,CAAC,CAyCd;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,GAAG,CAAC,CAOd;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAM5C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM3D"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL validation for SSRF protection and redirect handling.
|
|
3
|
+
* @module sandbox/url-validator
|
|
4
|
+
*/
|
|
5
|
+
import * as dns from 'node:dns/promises';
|
|
6
|
+
/**
|
|
7
|
+
* Default validation options.
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_OPTIONS = {
|
|
10
|
+
allowedSchemes: ['https'],
|
|
11
|
+
maxRedirects: 5,
|
|
12
|
+
allowLocalhost: false,
|
|
13
|
+
blockedIpRanges: [],
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Blocked IP ranges for SSRF protection.
|
|
17
|
+
*/
|
|
18
|
+
const BLOCKED_PRIVATE_RANGES = [
|
|
19
|
+
'10.0.0.0/8',
|
|
20
|
+
'172.16.0.0/12',
|
|
21
|
+
'192.168.0.0/16',
|
|
22
|
+
'127.0.0.0/8',
|
|
23
|
+
'169.254.0.0/16',
|
|
24
|
+
'::1/128',
|
|
25
|
+
'fc00::/7',
|
|
26
|
+
'fe80::/10',
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Parse an IPv6 address into a BigInt (128-bit).
|
|
30
|
+
*/
|
|
31
|
+
function parseIpv6ToBigInt(ip) {
|
|
32
|
+
const halves = ip.split('::');
|
|
33
|
+
const left = halves[0] ? halves[0].split(':').filter(s => s !== '') : [];
|
|
34
|
+
const right = halves.length > 1 && halves[1] ? halves[1].split(':').filter(s => s !== '') : [];
|
|
35
|
+
const groups = [];
|
|
36
|
+
for (const g of left)
|
|
37
|
+
groups.push(parseInt(g, 16));
|
|
38
|
+
const fill = 8 - left.length - right.length;
|
|
39
|
+
for (let i = 0; i < fill; i++)
|
|
40
|
+
groups.push(0);
|
|
41
|
+
for (const g of right)
|
|
42
|
+
groups.push(parseInt(g, 16));
|
|
43
|
+
let result = BigInt(0);
|
|
44
|
+
for (const group of groups) {
|
|
45
|
+
result = (result << BigInt(16)) | BigInt(group);
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Check if IP is in CIDR range (supports IPv4 and IPv6).
|
|
51
|
+
*/
|
|
52
|
+
export function isIpInCidr(ip, cidr) {
|
|
53
|
+
const [range, bitsStr] = cidr.split('/');
|
|
54
|
+
if (!range) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const isIpv6 = ip.includes(':');
|
|
58
|
+
const isRangeIpv6 = range.includes(':');
|
|
59
|
+
// Must be same address family
|
|
60
|
+
if (isIpv6 !== isRangeIpv6)
|
|
61
|
+
return false;
|
|
62
|
+
if (isIpv6) {
|
|
63
|
+
const bits = bitsStr !== undefined ? parseInt(bitsStr, 10) : 128;
|
|
64
|
+
const ipNum = parseIpv6ToBigInt(ip);
|
|
65
|
+
const rangeNum = parseIpv6ToBigInt(range);
|
|
66
|
+
const mask = bits === 0 ? BigInt(0) : ((BigInt(1) << BigInt(128)) - BigInt(1)) << BigInt(128 - bits);
|
|
67
|
+
return (ipNum & mask) === (rangeNum & mask);
|
|
68
|
+
}
|
|
69
|
+
// IPv4
|
|
70
|
+
const rangeParts = range.split('.').map(Number);
|
|
71
|
+
const ipParts = ip.split('.').map(Number);
|
|
72
|
+
if (rangeParts.length !== 4 || ipParts.length !== 4) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const bits = bitsStr !== undefined ? parseInt(bitsStr, 10) : 32;
|
|
76
|
+
let maskNum = 0;
|
|
77
|
+
for (let i = 0; i < bits; i++) {
|
|
78
|
+
maskNum |= (1 << (31 - i));
|
|
79
|
+
}
|
|
80
|
+
const rangeNum = ((rangeParts[0] ?? 0) << 24) | ((rangeParts[1] ?? 0) << 16) | ((rangeParts[2] ?? 0) << 8) | (rangeParts[3] ?? 0);
|
|
81
|
+
const ipNum = ((ipParts[0] ?? 0) << 24) | ((ipParts[1] ?? 0) << 16) | ((ipParts[2] ?? 0) << 8) | (ipParts[3] ?? 0);
|
|
82
|
+
return (rangeNum & maskNum) === (ipNum & maskNum);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check if IP is in any blocked range.
|
|
86
|
+
*/
|
|
87
|
+
function isBlockedIp(ip, options) {
|
|
88
|
+
// Check custom blocked ranges
|
|
89
|
+
for (const range of options.blockedIpRanges) {
|
|
90
|
+
if (isIpInCidr(ip, range)) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Check default private ranges
|
|
95
|
+
for (const range of BLOCKED_PRIVATE_RANGES) {
|
|
96
|
+
if (isIpInCidr(ip, range)) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Check localhost
|
|
101
|
+
if (!options.allowLocalhost) {
|
|
102
|
+
if (ip === '127.0.0.1' || ip === '::1' || ip === 'localhost') {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Validate URL for SSRF protection.
|
|
110
|
+
* @throws Error if URL is invalid or blocked
|
|
111
|
+
*/
|
|
112
|
+
export async function validateUrl(urlString, options = {}) {
|
|
113
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
114
|
+
// Parse URL
|
|
115
|
+
let url;
|
|
116
|
+
try {
|
|
117
|
+
url = new URL(urlString);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
throw new Error(`Invalid URL: ${urlString}`);
|
|
121
|
+
}
|
|
122
|
+
// Check scheme
|
|
123
|
+
if (!opts.allowedSchemes.includes(url.protocol.replace(':', ''))) {
|
|
124
|
+
throw new Error(`URL scheme "${url.protocol}" not allowed. Allowed: ${opts.allowedSchemes.join(', ')}. Use --allow-http to allow insecure HTTP connections.`);
|
|
125
|
+
}
|
|
126
|
+
// Resolve hostname to IP for SSRF protection
|
|
127
|
+
const hostname = url.hostname;
|
|
128
|
+
let ips;
|
|
129
|
+
try {
|
|
130
|
+
// Try to resolve as IPv4 first, then IPv6
|
|
131
|
+
const result = await dns.lookup(hostname, { all: true });
|
|
132
|
+
ips = result.map((r) => r.address);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
throw new Error(`Failed to resolve hostname: ${hostname}`);
|
|
136
|
+
}
|
|
137
|
+
// Check all resolved IPs
|
|
138
|
+
for (const ip of ips) {
|
|
139
|
+
if (isBlockedIp(ip, opts)) {
|
|
140
|
+
throw new Error(`Blocked IP address: ${ip} (resolved from ${hostname}). ` +
|
|
141
|
+
`This appears to be a private/internal network address.`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return url;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Validate a redirect URL.
|
|
148
|
+
* Re-validates all SSRF protections for the redirect target.
|
|
149
|
+
*/
|
|
150
|
+
export async function validateRedirect(redirectUrl, _originalUrl, options = {}) {
|
|
151
|
+
// Validate the redirect URL with all SSRF checks
|
|
152
|
+
const url = await validateUrl(redirectUrl, options);
|
|
153
|
+
// Log redirect for audit (caller provides audit logger at a higher level)
|
|
154
|
+
return url;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Check if a URL is HTTPS.
|
|
158
|
+
*/
|
|
159
|
+
export function isHttps(url) {
|
|
160
|
+
try {
|
|
161
|
+
return new URL(url).protocol === 'https:';
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Extract hostname from URL.
|
|
169
|
+
*/
|
|
170
|
+
export function getHostname(url) {
|
|
171
|
+
try {
|
|
172
|
+
return new URL(url).hostname;
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=url-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-validator.js","sourceRoot":"","sources":["../../src/sandbox/url-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/secrets/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/secrets/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret approval and scoping manager.
|
|
3
|
+
* @module secrets/manager
|
|
4
|
+
*/
|
|
5
|
+
import { Secret } from '../manifest/schema.js';
|
|
6
|
+
/**
|
|
7
|
+
* Approved secret with its scope patterns.
|
|
8
|
+
*/
|
|
9
|
+
export interface ApprovedSecret {
|
|
10
|
+
name: string;
|
|
11
|
+
value: string;
|
|
12
|
+
scopes: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Secrets manager handles secret approval and scoped access.
|
|
16
|
+
*/
|
|
17
|
+
export declare class SecretsManager {
|
|
18
|
+
private approvedSecrets;
|
|
19
|
+
/**
|
|
20
|
+
* Approve a secret with its value and scope patterns.
|
|
21
|
+
*/
|
|
22
|
+
approve(secret: Secret, value: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a secret is approved.
|
|
25
|
+
*/
|
|
26
|
+
isApproved(name: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Get a secret value if approved and URL is in scope.
|
|
29
|
+
* @returns The secret value, or undefined if not approved or out of scope
|
|
30
|
+
*/
|
|
31
|
+
getSecret(name: string, url?: string): string | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Get all approved secrets for a specific URL.
|
|
34
|
+
* Only returns secrets whose scopes include the URL.
|
|
35
|
+
*/
|
|
36
|
+
getSecretsForUrl(url: string): Record<string, string>;
|
|
37
|
+
/**
|
|
38
|
+
* Get all approved secrets (without scope validation).
|
|
39
|
+
* Use with caution - for passing to worker process only.
|
|
40
|
+
*/
|
|
41
|
+
getAllSecrets(): Record<string, string>;
|
|
42
|
+
/**
|
|
43
|
+
* Get scope patterns for a secret.
|
|
44
|
+
*/
|
|
45
|
+
getScopes(name: string): string[] | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Clear all approved secrets.
|
|
48
|
+
*/
|
|
49
|
+
clear(): void;
|
|
50
|
+
/**
|
|
51
|
+
* List all approved secret names.
|
|
52
|
+
*/
|
|
53
|
+
listApproved(): string[];
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/secrets/manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAG/C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,eAAe,CAA0C;IAEjE;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ5C;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAkBzD;;;OAGG;IACH,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAerD;;;OAGG;IACH,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAQvC;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS;IAI7C;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,YAAY,IAAI,MAAM,EAAE;CAGzB"}
|