@securecode-ai/mcp 0.5.4 → 0.5.6

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.
Files changed (188) hide show
  1. package/dist/api/types.d.ts +7 -0
  2. package/dist/approval/auditLog.d.ts +1 -1
  3. package/dist/approval/auditLog.js +11 -3
  4. package/dist/approval/auditLog.js.map +1 -1
  5. package/dist/approval/broker.d.ts +7 -2
  6. package/dist/approval/broker.js +239 -110
  7. package/dist/approval/broker.js.map +1 -1
  8. package/dist/approval/policy.d.ts +10 -0
  9. package/dist/approval/policy.js +104 -0
  10. package/dist/approval/policy.js.map +1 -0
  11. package/dist/approval/types.d.ts +11 -2
  12. package/dist/approval/types.js +10 -1
  13. package/dist/approval/types.js.map +1 -1
  14. package/dist/attack/agentScanExecutor.d.ts +35 -1
  15. package/dist/attack/agentScanExecutor.js +405 -76
  16. package/dist/attack/agentScanExecutor.js.map +1 -1
  17. package/dist/attack/agentScanLoop.d.ts +20 -0
  18. package/dist/attack/agentScanLoop.js +1264 -60
  19. package/dist/attack/agentScanLoop.js.map +1 -1
  20. package/dist/attack/agentScanProtocol.d.ts +382 -6
  21. package/dist/attack/agentScanProtocol.js +110 -4
  22. package/dist/attack/agentScanProtocol.js.map +1 -1
  23. package/dist/attack/agentTrace.d.ts +73 -0
  24. package/dist/attack/agentTrace.js +228 -0
  25. package/dist/attack/agentTrace.js.map +1 -0
  26. package/dist/attack/architectureScoutExecutor.d.ts +18 -0
  27. package/dist/attack/architectureScoutExecutor.js +211 -0
  28. package/dist/attack/architectureScoutExecutor.js.map +1 -0
  29. package/dist/attack/architectureScoutLoop.d.ts +36 -0
  30. package/dist/attack/architectureScoutLoop.js +403 -0
  31. package/dist/attack/architectureScoutLoop.js.map +1 -0
  32. package/dist/attack/architectureScoutProtocol.d.ts +209 -0
  33. package/dist/attack/architectureScoutProtocol.js +47 -0
  34. package/dist/attack/architectureScoutProtocol.js.map +1 -0
  35. package/dist/attack/candidateStore.d.ts +95 -0
  36. package/dist/attack/candidateStore.js +231 -0
  37. package/dist/attack/candidateStore.js.map +1 -0
  38. package/dist/attack/evidenceLedger.d.ts +67 -0
  39. package/dist/attack/evidenceLedger.js +192 -0
  40. package/dist/attack/evidenceLedger.js.map +1 -0
  41. package/dist/attack/finishGate.d.ts +62 -0
  42. package/dist/attack/finishGate.js +209 -0
  43. package/dist/attack/finishGate.js.map +1 -0
  44. package/dist/attack/fixCodeMerge.d.ts +27 -0
  45. package/dist/attack/fixCodeMerge.js +42 -0
  46. package/dist/attack/fixCodeMerge.js.map +1 -0
  47. package/dist/attack/fixVerifyLoop.d.ts +55 -0
  48. package/dist/attack/fixVerifyLoop.js +187 -0
  49. package/dist/attack/fixVerifyLoop.js.map +1 -0
  50. package/dist/attack/investigationProfiles.d.ts +36 -0
  51. package/dist/attack/investigationProfiles.js +144 -0
  52. package/dist/attack/investigationProfiles.js.map +1 -0
  53. package/dist/attack/investigationState.d.ts +227 -0
  54. package/dist/attack/investigationState.js +666 -0
  55. package/dist/attack/investigationState.js.map +1 -0
  56. package/dist/attack/mutationOperators.d.ts +22 -0
  57. package/dist/attack/mutationOperators.js +170 -0
  58. package/dist/attack/mutationOperators.js.map +1 -0
  59. package/dist/attack/mutationTest.d.ts +33 -0
  60. package/dist/attack/mutationTest.js +110 -0
  61. package/dist/attack/mutationTest.js.map +1 -0
  62. package/dist/attack/proofGate.d.ts +20 -0
  63. package/dist/attack/proofGate.js +104 -0
  64. package/dist/attack/proofGate.js.map +1 -0
  65. package/dist/attack/proofTypes.d.ts +57 -0
  66. package/dist/attack/proofTypes.js +32 -0
  67. package/dist/attack/proofTypes.js.map +1 -0
  68. package/dist/attack/protocolValidator.d.ts +50 -0
  69. package/dist/attack/protocolValidator.js +427 -0
  70. package/dist/attack/protocolValidator.js.map +1 -0
  71. package/dist/attack/qualityMetrics.d.ts +133 -0
  72. package/dist/attack/qualityMetrics.js +226 -0
  73. package/dist/attack/qualityMetrics.js.map +1 -0
  74. package/dist/attack/scanScheduler.d.ts +52 -0
  75. package/dist/attack/scanScheduler.js +265 -0
  76. package/dist/attack/scanScheduler.js.map +1 -0
  77. package/dist/attack/scanState.d.ts +58 -0
  78. package/dist/attack/scanState.js +102 -0
  79. package/dist/attack/scanState.js.map +1 -0
  80. package/dist/attack/searchIntent.d.ts +16 -0
  81. package/dist/attack/searchIntent.js +57 -0
  82. package/dist/attack/searchIntent.js.map +1 -0
  83. package/dist/attack/verifyLoop.d.ts +43 -0
  84. package/dist/attack/verifyLoop.js +329 -15
  85. package/dist/attack/verifyLoop.js.map +1 -1
  86. package/dist/attack/workItem.d.ts +57 -0
  87. package/dist/attack/workItem.js +225 -0
  88. package/dist/attack/workItem.js.map +1 -0
  89. package/dist/audit/findingReviewQueue.d.ts +109 -0
  90. package/dist/audit/findingReviewQueue.js +335 -0
  91. package/dist/audit/findingReviewQueue.js.map +1 -0
  92. package/dist/audit/scanAuditLog.d.ts +160 -0
  93. package/dist/audit/scanAuditLog.js +404 -0
  94. package/dist/audit/scanAuditLog.js.map +1 -0
  95. package/dist/dependency/dependencyChecker.js +35 -9
  96. package/dist/dependency/dependencyChecker.js.map +1 -1
  97. package/dist/dependency/exploitPriority.d.ts +33 -0
  98. package/dist/dependency/exploitPriority.js +78 -0
  99. package/dist/dependency/exploitPriority.js.map +1 -0
  100. package/dist/dependency/finding.d.ts +16 -0
  101. package/dist/dependency/osvClient.js +2 -0
  102. package/dist/dependency/osvClient.js.map +1 -1
  103. package/dist/dependency/types.d.ts +12 -1
  104. package/dist/mcp/server.js +13 -2
  105. package/dist/mcp/server.js.map +1 -1
  106. package/dist/mcp/tools.d.ts +1 -0
  107. package/dist/mcp/tools.js +127 -6
  108. package/dist/mcp/tools.js.map +1 -1
  109. package/dist/project-map/agentMemory.d.ts +83 -1
  110. package/dist/project-map/agentMemory.js +197 -7
  111. package/dist/project-map/agentMemory.js.map +1 -1
  112. package/dist/project-map/architectureContext.d.ts +202 -0
  113. package/dist/project-map/architectureContext.js +421 -0
  114. package/dist/project-map/architectureContext.js.map +1 -0
  115. package/dist/project-map/blastRadius.d.ts +54 -0
  116. package/dist/project-map/blastRadius.js +196 -0
  117. package/dist/project-map/blastRadius.js.map +1 -0
  118. package/dist/project-map/callGraphExtractor.d.ts +13 -0
  119. package/dist/project-map/callGraphExtractor.js +222 -0
  120. package/dist/project-map/callGraphExtractor.js.map +1 -0
  121. package/dist/project-map/capabilityRegistry.d.ts +46 -0
  122. package/dist/project-map/capabilityRegistry.js +91 -0
  123. package/dist/project-map/capabilityRegistry.js.map +1 -0
  124. package/dist/project-map/findTests.d.ts +29 -0
  125. package/dist/project-map/findTests.js +236 -0
  126. package/dist/project-map/findTests.js.map +1 -0
  127. package/dist/project-map/handlerInventory.d.ts +112 -0
  128. package/dist/project-map/handlerInventory.js +184 -0
  129. package/dist/project-map/handlerInventory.js.map +1 -0
  130. package/dist/project-map/implementationResolver.d.ts +43 -0
  131. package/dist/project-map/implementationResolver.js +217 -0
  132. package/dist/project-map/implementationResolver.js.map +1 -0
  133. package/dist/project-map/mapContext.d.ts +6 -1
  134. package/dist/project-map/mapContext.js +1 -0
  135. package/dist/project-map/mapContext.js.map +1 -1
  136. package/dist/project-map/scanCache.d.ts +57 -3
  137. package/dist/project-map/scanCache.js +61 -2
  138. package/dist/project-map/scanCache.js.map +1 -1
  139. package/dist/project-map/symbolIndex.d.ts +39 -0
  140. package/dist/project-map/symbolIndex.js +385 -0
  141. package/dist/project-map/symbolIndex.js.map +1 -0
  142. package/dist/tooling/agentEvalScoring.d.ts +77 -0
  143. package/dist/tooling/agentEvalScoring.js +140 -0
  144. package/dist/tooling/agentEvalScoring.js.map +1 -0
  145. package/dist/tooling/agentRegression.d.ts +53 -0
  146. package/dist/tooling/agentRegression.js +99 -0
  147. package/dist/tooling/agentRegression.js.map +1 -0
  148. package/dist/tools/agentScan.d.ts +69 -0
  149. package/dist/tools/agentScan.js +702 -43
  150. package/dist/tools/agentScan.js.map +1 -1
  151. package/dist/tools/findingReviewTools.d.ts +22 -0
  152. package/dist/tools/findingReviewTools.js +121 -0
  153. package/dist/tools/findingReviewTools.js.map +1 -0
  154. package/dist/tools/fix.js +1 -1
  155. package/dist/tools/fix.js.map +1 -1
  156. package/dist/tools/map.js +191 -1
  157. package/dist/tools/map.js.map +1 -1
  158. package/dist/tools/runTests.d.ts +2 -0
  159. package/dist/tools/runTests.js +29 -0
  160. package/dist/tools/runTests.js.map +1 -0
  161. package/dist/utils/effectMock.d.ts +1 -0
  162. package/dist/utils/effectMock.js +162 -0
  163. package/dist/utils/effectMock.js.map +1 -0
  164. package/dist/utils/gitContext.d.ts +26 -0
  165. package/dist/utils/gitContext.js +317 -0
  166. package/dist/utils/gitContext.js.map +1 -0
  167. package/dist/utils/localTestRunner.d.ts +57 -2
  168. package/dist/utils/localTestRunner.js +122 -101
  169. package/dist/utils/localTestRunner.js.map +1 -1
  170. package/dist/utils/runtimeDetect.d.ts +12 -2
  171. package/dist/utils/runtimeDetect.js +247 -10
  172. package/dist/utils/runtimeDetect.js.map +1 -1
  173. package/dist/utils/securityConfig.d.ts +17 -0
  174. package/dist/utils/securityConfig.js +192 -0
  175. package/dist/utils/securityConfig.js.map +1 -0
  176. package/dist/utils/testCommandPolicy.d.ts +36 -0
  177. package/dist/utils/testCommandPolicy.js +252 -0
  178. package/dist/utils/testCommandPolicy.js.map +1 -0
  179. package/dist/utils/testRunner.d.ts +56 -0
  180. package/dist/utils/testRunner.js +246 -0
  181. package/dist/utils/testRunner.js.map +1 -0
  182. package/dist/utils/testSafety.d.ts +40 -2
  183. package/dist/utils/testSafety.js +205 -26
  184. package/dist/utils/testSafety.js.map +1 -1
  185. package/dist/utils/verificationSandbox.d.ts +113 -0
  186. package/dist/utils/verificationSandbox.js +656 -0
  187. package/dist/utils/verificationSandbox.js.map +1 -0
  188. package/package.json +1 -1
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ /**
3
+ * Shared test runner — the core service for run_tests (both public MCP tool
4
+ * and agent action). Handles:
5
+ * - Request validation
6
+ * - Human approval (every execution, no exceptions)
7
+ * - Sandbox execution via localTestRunner (generated) or runTestCommand (existing)
8
+ * - Bounded, redacted output
9
+ *
10
+ * Security model:
11
+ * - Approval is required before every execution — no batch grants, no timed grants.
12
+ * - The approval hash binds to mode, command/script hash, runner, timeout, workspace.
13
+ * - No execution occurs if approval is denied or times out.
14
+ * - No host fallback when no sandbox is available.
15
+ */
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.validateRunTestsRequest = validateRunTestsRequest;
51
+ exports.runTests = runTests;
52
+ const crypto = __importStar(require("crypto"));
53
+ const fs = __importStar(require("fs"));
54
+ const path = __importStar(require("path"));
55
+ const broker_1 = require("../approval/broker");
56
+ const localTestRunner_1 = require("./localTestRunner");
57
+ const testCommandPolicy_1 = require("./testCommandPolicy");
58
+ const testSafety_1 = require("./testSafety");
59
+ const MAX_SCRIPT_SIZE = 64 * 1024;
60
+ const MAX_SETUP_SCRIPT_SIZE = 32 * 1024;
61
+ const MAX_OUTPUT = 16 * 1024;
62
+ const DEFAULT_TIMEOUT_MS = 60_000;
63
+ const SAFE_RUNNERS = new Set(['node', 'tsx', 'bun', 'deno', 'python', 'python3']);
64
+ function sha256Prefix(s) {
65
+ return crypto.createHash('sha256').update(s).digest('hex').substring(0, 16);
66
+ }
67
+ function hashWorkspaceFile(workspaceRoot, relPath) {
68
+ try {
69
+ const p = path.join(workspaceRoot, relPath);
70
+ if (!fs.existsSync(p))
71
+ return null;
72
+ const content = fs.readFileSync(p, 'utf8').slice(0, 65536);
73
+ return sha256Prefix(content);
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ }
79
+ function workspaceContentHash(workspaceRoot) {
80
+ const pkg = hashWorkspaceFile(workspaceRoot, 'package.json');
81
+ const lock = hashWorkspaceFile(workspaceRoot, 'package-lock.json')
82
+ || hashWorkspaceFile(workspaceRoot, 'pnpm-lock.yaml')
83
+ || hashWorkspaceFile(workspaceRoot, 'yarn.lock')
84
+ || hashWorkspaceFile(workspaceRoot, 'bun.lock')
85
+ || hashWorkspaceFile(workspaceRoot, 'requirements.txt')
86
+ || hashWorkspaceFile(workspaceRoot, 'pyproject.toml');
87
+ if (!pkg && !lock)
88
+ return null;
89
+ return `${pkg || 'none'}:${lock || 'none'}`;
90
+ }
91
+ function truncateOutput(s) {
92
+ if (s.length <= MAX_OUTPUT)
93
+ return s;
94
+ return s.slice(0, MAX_OUTPUT) + '\n… [truncated]';
95
+ }
96
+ function mapVerdict(verdict) {
97
+ switch (verdict) {
98
+ case 'pass': return 'passed';
99
+ case 'fail': return 'failed';
100
+ case 'error': return 'error';
101
+ case 'timeout': return 'timeout';
102
+ case 'blocked': return 'blocked';
103
+ case 'sandbox-unavailable': return 'sandbox-unavailable';
104
+ default: return 'error';
105
+ }
106
+ }
107
+ function validateRunTestsRequest(req, workspaceRoot) {
108
+ if (!req.mode || (req.mode !== 'existing' && req.mode !== 'generated')) {
109
+ return { ok: false, error: 'mode must be "existing" or "generated"' };
110
+ }
111
+ if (req.mode === 'existing') {
112
+ const result = (0, testCommandPolicy_1.validateTestCommand)({
113
+ packageManager: req.packageManager,
114
+ testFiles: req.testFiles,
115
+ testPattern: req.testPattern,
116
+ timeoutMs: req.timeoutMs,
117
+ }, workspaceRoot);
118
+ if (!result.ok)
119
+ return { ok: false, error: result.error };
120
+ return { ok: true, command: result.command };
121
+ }
122
+ // Generated mode
123
+ if (!req.script || req.script.trim().length === 0) {
124
+ return { ok: false, error: 'generated mode requires "script" (non-empty string)' };
125
+ }
126
+ if (req.script.length > MAX_SCRIPT_SIZE) {
127
+ return { ok: false, error: `script too large (max ${MAX_SCRIPT_SIZE} bytes, got ${req.script.length})` };
128
+ }
129
+ if (!req.runner || !SAFE_RUNNERS.has(req.runner)) {
130
+ return { ok: false, error: `runner must be one of: ${[...SAFE_RUNNERS].join(', ')}. Got: ${req.runner || '(none)'}` };
131
+ }
132
+ if (req.setupScript && req.setupScript.length > MAX_SETUP_SCRIPT_SIZE) {
133
+ return { ok: false, error: `setupScript too large (max ${MAX_SETUP_SCRIPT_SIZE} bytes)` };
134
+ }
135
+ const safety = (0, testSafety_1.checkTestSafety)(req.script, workspaceRoot);
136
+ if (!safety.allowed) {
137
+ return { ok: false, error: `script blocked by safety check: ${safety.reason}` };
138
+ }
139
+ if (req.setupScript) {
140
+ const setupSafety = (0, testSafety_1.checkTestSafety)(req.setupScript, workspaceRoot);
141
+ if (!setupSafety.allowed) {
142
+ return { ok: false, error: `setupScript blocked by safety check: ${setupSafety.reason}` };
143
+ }
144
+ }
145
+ return { ok: true };
146
+ }
147
+ function buildApprovalSummary(req, command) {
148
+ if (req.mode === 'existing' && command) {
149
+ const files = command.selectedFiles.length > 0
150
+ ? `\nFiles: ${command.selectedFiles.join(', ')}`
151
+ : '';
152
+ const pattern = req.testPattern ? `\nPattern: ${req.testPattern}` : '';
153
+ return `Run existing tests in sandbox\nCommand: ${(0, testCommandPolicy_1.formatValidatedCommand)(command)}\nTimeout: ${command.timeoutMs}ms${files}${pattern}`;
154
+ }
155
+ const setupInfo = req.setupScript ? `\nSetup script: ${req.setupScript.length} bytes` : '';
156
+ return `Run generated test script in sandbox\nRunner: ${req.runner}\nScript: ${req.script.length} bytes (hash ${sha256Prefix(req.script)})${setupInfo}\nTimeout: ${req.timeoutMs || DEFAULT_TIMEOUT_MS}ms`;
157
+ }
158
+ function buildOperationParts(req, command, workspaceRoot) {
159
+ const wsHash = workspaceContentHash(workspaceRoot);
160
+ if (req.mode === 'existing' && command) {
161
+ return [
162
+ req.mode,
163
+ command.executable,
164
+ command.args,
165
+ command.selectedFiles,
166
+ req.testPattern,
167
+ command.timeoutMs,
168
+ wsHash,
169
+ ];
170
+ }
171
+ return [
172
+ req.mode,
173
+ req.runner,
174
+ req.script ? sha256Prefix(req.script) : null,
175
+ req.setupScript ? sha256Prefix(req.setupScript) : null,
176
+ req.timeoutMs || DEFAULT_TIMEOUT_MS,
177
+ wsHash,
178
+ ];
179
+ }
180
+ async function runTests(req, workspaceRoot, options) {
181
+ const startTime = Date.now();
182
+ const validation = validateRunTestsRequest(req, workspaceRoot);
183
+ if (!validation.ok) {
184
+ return {
185
+ approved: false,
186
+ mode: req.mode,
187
+ status: 'denied',
188
+ exitCode: -1,
189
+ output: `Validation error: ${validation.error}`,
190
+ durationMs: Date.now() - startTime,
191
+ };
192
+ }
193
+ const command = validation.command;
194
+ const summary = buildApprovalSummary(req, command);
195
+ const operationParts = buildOperationParts(req, command, workspaceRoot);
196
+ const ownsBroker = !options?.broker;
197
+ const broker = options?.broker ?? new broker_1.ApprovalBroker();
198
+ if (ownsBroker)
199
+ await broker.start();
200
+ try {
201
+ const approval = await broker.requestApproval('securecode.run-tests', summary, operationParts, 60_000, 'paid-generation', workspaceRoot);
202
+ if (!approval.approved) {
203
+ return {
204
+ approved: false,
205
+ requestId: approval.requestId,
206
+ mode: req.mode,
207
+ status: 'denied',
208
+ exitCode: -1,
209
+ output: `Test execution ${approval.reason}.`,
210
+ durationMs: Date.now() - startTime,
211
+ };
212
+ }
213
+ let testResult;
214
+ if (req.mode === 'existing' && command) {
215
+ testResult = await (0, localTestRunner_1.runTestCommand)(command.executable, command.args, workspaceRoot, {
216
+ timeoutMs: command.timeoutMs,
217
+ signal: options?.signal,
218
+ sandboxBackend: options?.sandboxBackend,
219
+ });
220
+ }
221
+ else {
222
+ testResult = await (0, localTestRunner_1.runLocalTest)(req.script, req.runner, workspaceRoot, {
223
+ setupScript: req.setupScript || null,
224
+ timeoutMs: req.timeoutMs || DEFAULT_TIMEOUT_MS,
225
+ signal: options?.signal,
226
+ sandboxBackend: options?.sandboxBackend,
227
+ });
228
+ }
229
+ return {
230
+ approved: true,
231
+ requestId: approval.requestId,
232
+ mode: req.mode,
233
+ status: mapVerdict(testResult.verdict),
234
+ exitCode: testResult.exitCode,
235
+ output: truncateOutput(testResult.output),
236
+ backend: testResult.backend,
237
+ command: command ? { executable: command.executable, args: command.args } : undefined,
238
+ durationMs: Date.now() - startTime,
239
+ };
240
+ }
241
+ finally {
242
+ if (ownsBroker)
243
+ await broker.stop();
244
+ }
245
+ }
246
+ //# sourceMappingURL=testRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testRunner.js","sourceRoot":"","sources":["../../src/utils/testRunner.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,42 @@
1
- export declare function checkTestSafety(script: string, _workspaceRoot: string): {
1
+ /**
2
+ * Static test safety analyzer — defense-in-depth, NOT a security boundary.
3
+ *
4
+ * The real boundary is the verification sandbox (`verificationSandbox.ts`):
5
+ * Docker with `--network=none --read-only`, or Deno with `--allow-none`.
6
+ * This module exists to reject obviously dangerous scripts *before* we
7
+ * pay for a sandbox spawn, and as a second layer in case a sandbox backend
8
+ * is somehow misconfigured.
9
+ *
10
+ * Policy: deny-by-default. Only specific known-safe imports and globals
11
+ * are permitted. Anything else is blocked. The previous implementation
12
+ * was allow-by-default with a 4-module blocklist — it let `http`, `https`,
13
+ * `fs`, `dns`, `os`, `tls`, `vm`, `dgram`, `fetch`, `eval`, `new Function`,
14
+ * dynamic `import()`, and `process.env` access all pass. That gap is the
15
+ * reason this module was rewritten.
16
+ *
17
+ * What this analyzer checks (in priority order):
18
+ * 1. Static import / require specifiers — against an allowlist.
19
+ * 2. Dynamic require/import — blocked outright (cannot be statically
20
+ * analyzed).
21
+ * 3. Global function calls that execute strings as code — `eval`,
22
+ * `new Function`, `setTimeout(string)`, `setInterval(string)`,
23
+ * `setImmediate(string)`.
24
+ * 4. Network-related globals and Node built-ins (covered by #1 for
25
+ * imports; here for member-style access like `globalThis.fetch`).
26
+ * 5. Process/env access — `process.env`, `process.argv`, `process.cwd`,
27
+ * `process.execPath`, `process.cwd()`.
28
+ * 6. Reflection tricks that resolve to dangerous globals —
29
+ * `globalThis['eval']`, `globalThis['Function']`, `this['eval']`,
30
+ * bracket access with string literals that match dangerous names.
31
+ *
32
+ * Obfuscation handling: we catch literal bracket access like
33
+ * `globalThis["eval"]` and `process["env"]`. We do NOT attempt to defeat
34
+ * arbitrary runtime-computed string construction (e.g., `String.fromCharCode`
35
+ * to build a name) — that is the sandbox's job. This analyzer only catches
36
+ * what a defender can see statically.
37
+ */
38
+ export interface TestSafetyResult {
2
39
  allowed: boolean;
3
40
  reason: string;
4
- };
41
+ }
42
+ export declare function checkTestSafety(script: string, _workspaceRoot: string): TestSafetyResult;
@@ -1,38 +1,217 @@
1
1
  "use strict";
2
+ /**
3
+ * Static test safety analyzer — defense-in-depth, NOT a security boundary.
4
+ *
5
+ * The real boundary is the verification sandbox (`verificationSandbox.ts`):
6
+ * Docker with `--network=none --read-only`, or Deno with `--allow-none`.
7
+ * This module exists to reject obviously dangerous scripts *before* we
8
+ * pay for a sandbox spawn, and as a second layer in case a sandbox backend
9
+ * is somehow misconfigured.
10
+ *
11
+ * Policy: deny-by-default. Only specific known-safe imports and globals
12
+ * are permitted. Anything else is blocked. The previous implementation
13
+ * was allow-by-default with a 4-module blocklist — it let `http`, `https`,
14
+ * `fs`, `dns`, `os`, `tls`, `vm`, `dgram`, `fetch`, `eval`, `new Function`,
15
+ * dynamic `import()`, and `process.env` access all pass. That gap is the
16
+ * reason this module was rewritten.
17
+ *
18
+ * What this analyzer checks (in priority order):
19
+ * 1. Static import / require specifiers — against an allowlist.
20
+ * 2. Dynamic require/import — blocked outright (cannot be statically
21
+ * analyzed).
22
+ * 3. Global function calls that execute strings as code — `eval`,
23
+ * `new Function`, `setTimeout(string)`, `setInterval(string)`,
24
+ * `setImmediate(string)`.
25
+ * 4. Network-related globals and Node built-ins (covered by #1 for
26
+ * imports; here for member-style access like `globalThis.fetch`).
27
+ * 5. Process/env access — `process.env`, `process.argv`, `process.cwd`,
28
+ * `process.execPath`, `process.cwd()`.
29
+ * 6. Reflection tricks that resolve to dangerous globals —
30
+ * `globalThis['eval']`, `globalThis['Function']`, `this['eval']`,
31
+ * bracket access with string literals that match dangerous names.
32
+ *
33
+ * Obfuscation handling: we catch literal bracket access like
34
+ * `globalThis["eval"]` and `process["env"]`. We do NOT attempt to defeat
35
+ * arbitrary runtime-computed string construction (e.g., `String.fromCharCode`
36
+ * to build a name) — that is the sandbox's job. This analyzer only catches
37
+ * what a defender can see statically.
38
+ */
2
39
  Object.defineProperty(exports, "__esModule", { value: true });
3
40
  exports.checkTestSafety = checkTestSafety;
4
- const BLOCKED_MODULES = new Set(['child_process', 'net', 'cluster', 'worker_threads']);
5
- const BLOCKED_PATTERNS = [
6
- { pattern: /process\.exit\s*\(/g, reason: () => 'process.exit() masks test results — use console.error + throw instead' },
7
- { pattern: /require\s*\(\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*\)/g, reason: () => 'dynamic require with variable is not statically checkable' },
41
+ // ── Import allowlist ────────────────────────────────────────────────────────
42
+ //
43
+ // Allowed import specifiers (after the leading `node:` / `bun:` prefix is
44
+ // stripped for built-ins). Built-ins are kept on a tiny allowlist because
45
+ // even `node:` built-ins like `fs` are dangerous. The sandbox is the real
46
+ // boundary, but we still block here so we don't waste a container start
47
+ // on something obviously bad.
48
+ const ALLOWED_NODE_BUILTINS = new Set([
49
+ 'assert', 'console', 'crypto', 'path', 'util', 'module',
50
+ 'string_decoder', 'url',
51
+ ]);
52
+ const ALLOWED_PREFIXES = [
53
+ './', '../', // relative imports — needed to load the vulnerable module
54
+ 'effect', // the user's framework
55
+ 'bun:', // bun:* built-ins (test framework, etc.)
56
+ '@synara/', // user's workspace packages
8
57
  ];
9
- const ALLOWED_IMPORT_PREFIXES = ['node:', 'effect', 'bun', 'bun:', '@synara/', './', '../'];
10
- const BLOCKED_MODULE_REASONS = {
11
- child_process: 'child_process is blocked — use only for testing command injection with mock spawns',
12
- net: 'net is blocked — use HTTP libraries instead',
13
- cluster: 'cluster is blocked',
14
- worker_threads: 'worker_threads is blocked',
15
- };
58
+ // Modules blocked even if a prefix matches (defense-in-depth).
59
+ const BLOCKED_MODULE_NAMES = new Set([
60
+ 'child_process', 'node:child_process',
61
+ 'net', 'node:net',
62
+ 'http', 'node:http',
63
+ 'https', 'node:https',
64
+ 'http2', 'node:http2',
65
+ 'dgram', 'node:dgram',
66
+ 'dns', 'node:dns',
67
+ 'dns/promises', 'node:dns/promises',
68
+ 'tls', 'node:tls',
69
+ 'fs', 'node:fs',
70
+ 'fs/promises', 'node:fs/promises',
71
+ 'os', 'node:os',
72
+ 'vm', 'node:vm',
73
+ 'worker_threads', 'node:worker_threads',
74
+ 'cluster', 'node:cluster',
75
+ 'repl', 'node:repl',
76
+ 'process', 'node:process',
77
+ 'inspector', 'node:inspector',
78
+ 'perf_hooks', 'node:perf_hooks', // timing side-channels
79
+ ]);
80
+ // ── Dangerous globals & member access ───────────────────────────────────────
81
+ const DANGEROUS_GLOBAL_CALLS = [
82
+ { pattern: /\beval\s*\(/, reason: 'eval() executes arbitrary strings as code' },
83
+ { pattern: /\bnew\s+Function\s*\(/, reason: 'new Function() executes arbitrary strings as code' },
84
+ { pattern: /\bnew\s+AsyncFunction\s*\(/, reason: 'new AsyncFunction() executes arbitrary strings as code' },
85
+ { pattern: /\bnew\s+GeneratorFunction\s*\(/, reason: 'new GeneratorFunction() executes arbitrary strings as code' },
86
+ ];
87
+ // setTimeout/setInterval/setImmediate with a STRING argument is eval-by-proxy.
88
+ const TIMER_STRING_ARG = /\b(setTimeout|setInterval|setImmediate)\s*\(\s*['"`]/;
89
+ const DANGEROUS_PROCESS_ACCESS = [
90
+ { pattern: /\bprocess\.env\b/, reason: 'process.env access can leak host secrets — pass values explicitly' },
91
+ { pattern: /\bprocess\.argv\b/, reason: 'process.argv access can leak host arguments' },
92
+ { pattern: /\bprocess\.execPath\b/, reason: 'process.execPath exposes the host runtime path' },
93
+ { pattern: /\bprocess\.cwd\s*\(/, reason: 'process.cwd() exposes the host filesystem layout' },
94
+ { pattern: /\bprocess\.getuid\s*\(/, reason: 'process.getuid() exposes host user identity' },
95
+ { pattern: /\bprocess\.getgid\s*\(/, reason: 'process.getgid() exposes host group identity' },
96
+ ];
97
+ // Network & fs globals reachable without import (Node 18+ has global fetch).
98
+ const DANGEROUS_GLOBAL_REFERENCES = [
99
+ { pattern: /\bfetch\s*\(/, reason: 'fetch() can exfiltrate data over the network' },
100
+ { pattern: /\bnavigator\b/, reason: 'navigator access is not needed in a unit test' },
101
+ ];
102
+ // Dynamic import (ESM) and dynamic require (CJS) — both are unsafe because
103
+ // the specifier can be computed at runtime.
104
+ const DYNAMIC_IMPORT = /\bimport\s*\(\s*[^"'\s`]/;
105
+ const DYNAMIC_REQUIRE = /\brequire\s*\(\s*(?![`'"])[^)]*\)/;
106
+ const STATIC_REQUIRE = /\brequire\s*\(\s*['"`]([^`'"]+)['"`]\s*\)/g;
107
+ const STATIC_IMPORT_FROM = /\bimport\s+[^;]*?\s+from\s*['"`]([^`'"]+)['"`]/g;
108
+ const STATIC_IMPORT_BARE = /\bimport\s+['"`]([^`'"]+)['"`]/g;
109
+ const STATIC_EXPORT_FROM = /\bexport\s+[^;]*?\s+from\s*['"`]([^`'"]+)['"`]/g;
110
+ // Bracket-access reflection: globalThis["eval"], process["env"], etc.
111
+ // Matches `<identifier|keyword>["<dangerous-name>"]` and `['...']`.
112
+ function buildBracketAccessRegex(name) {
113
+ // Capture a bracket access where the property is a string literal matching
114
+ // the dangerous name. The receiver is any identifier-like token (we
115
+ // accept anything that's not a quote, to keep this simple).
116
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
117
+ return new RegExp(`\\b[^'"\\\`\\s]+\\s*\\[\\s*['"\`\\s]*${escaped}['"\`\\s]*\\]`, 'i');
118
+ }
119
+ const DANGEROUS_BRACKET_NAMES = [
120
+ 'eval', 'Function', 'AsyncFunction', 'GeneratorFunction',
121
+ 'fetch', 'process', 'require', 'import',
122
+ 'child_process', 'net', 'http', 'https', 'fs', 'os', 'vm',
123
+ 'exec', 'execSync', 'spawn', 'spawnSync', 'fork',
124
+ // Dangerous properties of `process` accessed via bracket (process["env"]).
125
+ // Blocking the property name on any receiver is intentional — bracket
126
+ // access to "env" is a known reflection trick and tests shouldn't need it.
127
+ 'env', 'argv', 'execPath', 'mainModule',
128
+ ];
129
+ // ── Main entry ──────────────────────────────────────────────────────────────
16
130
  function checkTestSafety(script, _workspaceRoot) {
17
- for (const { pattern, reason } of BLOCKED_PATTERNS) {
18
- pattern.lastIndex = 0;
131
+ // 1. Dangerous call patterns (eval, Function, etc.)
132
+ for (const { pattern, reason } of DANGEROUS_GLOBAL_CALLS) {
19
133
  if (pattern.test(script)) {
20
- return { allowed: false, reason: reason('') };
134
+ return { allowed: false, reason };
21
135
  }
22
136
  }
23
- const importRegex = /(?:import\s+[^;]+?from\s*|require\s*\(\s*)["']([^"']+)["']/g;
24
- let match;
25
- while ((match = importRegex.exec(script)) !== null) {
26
- const mod = match[1];
27
- if (BLOCKED_MODULES.has(mod)) {
28
- return { allowed: false, reason: BLOCKED_MODULE_REASONS[mod] || mod };
137
+ // 2. Timer-with-string (eval-by-proxy)
138
+ if (TIMER_STRING_ARG.test(script)) {
139
+ return { allowed: false, reason: 'setTimeout/setInterval/setImmediate with a string argument is eval-by-proxy' };
140
+ }
141
+ // 3. process.* access that leaks host state
142
+ for (const { pattern, reason } of DANGEROUS_PROCESS_ACCESS) {
143
+ if (pattern.test(script)) {
144
+ return { allowed: false, reason };
145
+ }
146
+ }
147
+ // 4. Global network refs
148
+ for (const { pattern, reason } of DANGEROUS_GLOBAL_REFERENCES) {
149
+ if (pattern.test(script)) {
150
+ return { allowed: false, reason };
29
151
  }
30
- if (mod.startsWith('node:') || mod.startsWith('./') || mod.startsWith('../'))
31
- continue;
32
- if (mod.startsWith('effect') || mod.startsWith('bun') || mod.startsWith('@synara/'))
33
- continue;
34
- if (ALLOWED_IMPORT_PREFIXES.some(p => mod.startsWith(p)))
35
- continue;
152
+ }
153
+ // 5. Dynamic import / dynamic require — non-static specifiers
154
+ if (DYNAMIC_IMPORT.test(script)) {
155
+ return { allowed: false, reason: 'dynamic import() with a computed specifier cannot be statically analyzed' };
156
+ }
157
+ if (DYNAMIC_REQUIRE.test(script)) {
158
+ return { allowed: false, reason: 'dynamic require with variable is not statically checkable' };
159
+ }
160
+ // 6. Bracket-access reflection (globalThis["eval"], process["env"], etc.)
161
+ for (const name of DANGEROUS_BRACKET_NAMES) {
162
+ const re = buildBracketAccessRegex(name);
163
+ if (re.test(script)) {
164
+ return { allowed: false, reason: `bracket access to "${name}" is blocked — use the safe form directly if needed` };
165
+ }
166
+ }
167
+ // 7. Static import / require specifiers — allowlist
168
+ const checkSpecifier = (mod) => {
169
+ if (BLOCKED_MODULE_NAMES.has(mod)) {
170
+ return { allowed: false, reason: `module "${mod}" is blocked — use the sandbox boundary for fs/net/process access` };
171
+ }
172
+ // node: prefix — strip and check the built-in allowlist.
173
+ if (mod.startsWith('node:')) {
174
+ const name = mod.slice('node:'.length);
175
+ if (!ALLOWED_NODE_BUILTINS.has(name)) {
176
+ return { allowed: false, reason: `node built-in "${mod}" is not on the allowlist (allowed: ${[...ALLOWED_NODE_BUILTINS].join(', ')})` };
177
+ }
178
+ return null;
179
+ }
180
+ // Bare built-in (no node: prefix) — block unless it's on the allowlist.
181
+ // We block bare 'fs', 'net', etc. even though Node resolves them to the
182
+ // same thing as node:fs.
183
+ if (ALLOWED_NODE_BUILTINS.has(mod))
184
+ return null;
185
+ if (mod === 'node')
186
+ return null; // not a real import
187
+ if (ALLOWED_PREFIXES.some(p => mod.startsWith(p)))
188
+ return null;
189
+ // Bare module names that aren't on an allowed prefix and aren't a
190
+ // built-in. These are third-party packages. We allow them — the
191
+ // sandbox will deny network access if they try to fetch anything.
192
+ // But we keep the known-dangerous ones in BLOCKED_MODULE_NAMES above.
193
+ return null;
194
+ };
195
+ const importPatterns = [
196
+ { re: STATIC_IMPORT_FROM, label: 'import' },
197
+ { re: STATIC_IMPORT_BARE, label: 'import' },
198
+ { re: STATIC_EXPORT_FROM, label: 'export' },
199
+ { re: STATIC_REQUIRE, label: 'require' },
200
+ ];
201
+ for (const { re } of importPatterns) {
202
+ re.lastIndex = 0;
203
+ let m;
204
+ while ((m = re.exec(script)) !== null) {
205
+ const mod = m[1];
206
+ const verdict = checkSpecifier(mod);
207
+ if (verdict)
208
+ return verdict;
209
+ }
210
+ }
211
+ // 8. process.exit() — masks test results and prevents the runner from
212
+ // capturing PASS/FAIL markers. (Was blocked before; keep the behavior.)
213
+ if (/\bprocess\.exit\s*\(/.test(script)) {
214
+ return { allowed: false, reason: 'process.exit() masks test results — use console.error + throw instead' };
36
215
  }
37
216
  return { allowed: true, reason: '' };
38
217
  }
@@ -1 +1 @@
1
- {"version":3,"file":"testSafety.js","sourceRoot":"","sources":["../../src/utils/testSafety.ts"],"names":[],"mappings":";;AAgBA,0CAqBC;AArCD,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAEvF,MAAM,gBAAgB,GAAgE;IAClF,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,uEAAuE,EAAE;IACzH,EAAE,OAAO,EAAE,+CAA+C,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,2DAA2D,EAAE;CAC1I,CAAC;AAEF,MAAM,uBAAuB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAE5F,MAAM,sBAAsB,GAA2B;IACnD,aAAa,EAAE,oFAAoF;IACnG,GAAG,EAAE,6CAA6C;IAClD,OAAO,EAAE,oBAAoB;IAC7B,cAAc,EAAE,2BAA2B;CAC9C,CAAC;AAEF,SAAgB,eAAe,CAAC,MAAc,EAAE,cAAsB;IAClE,KAAK,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,gBAAgB,EAAE,CAAC;QACjD,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QACtB,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;QAClD,CAAC;IACL,CAAC;IAED,MAAM,WAAW,GAAG,6DAA6D,CAAC;IAClF,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACjD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QAC1E,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,SAAS;QACvF,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,SAAS;QAC9F,IAAI,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAAE,SAAS;IACvE,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AACzC,CAAC"}
1
+ {"version":3,"file":"testSafety.js","sourceRoot":"","sources":["../../src/utils/testSafety.ts"],"names":[],"mappings":"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"}