@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.
- package/dist/api/types.d.ts +7 -0
- package/dist/approval/auditLog.d.ts +1 -1
- package/dist/approval/auditLog.js +11 -3
- package/dist/approval/auditLog.js.map +1 -1
- package/dist/approval/broker.d.ts +7 -2
- package/dist/approval/broker.js +239 -110
- package/dist/approval/broker.js.map +1 -1
- package/dist/approval/policy.d.ts +10 -0
- package/dist/approval/policy.js +104 -0
- package/dist/approval/policy.js.map +1 -0
- package/dist/approval/types.d.ts +11 -2
- package/dist/approval/types.js +10 -1
- package/dist/approval/types.js.map +1 -1
- package/dist/attack/agentScanExecutor.d.ts +35 -1
- package/dist/attack/agentScanExecutor.js +405 -76
- package/dist/attack/agentScanExecutor.js.map +1 -1
- package/dist/attack/agentScanLoop.d.ts +20 -0
- package/dist/attack/agentScanLoop.js +1264 -60
- package/dist/attack/agentScanLoop.js.map +1 -1
- package/dist/attack/agentScanProtocol.d.ts +382 -6
- package/dist/attack/agentScanProtocol.js +110 -4
- package/dist/attack/agentScanProtocol.js.map +1 -1
- package/dist/attack/agentTrace.d.ts +73 -0
- package/dist/attack/agentTrace.js +228 -0
- package/dist/attack/agentTrace.js.map +1 -0
- package/dist/attack/architectureScoutExecutor.d.ts +18 -0
- package/dist/attack/architectureScoutExecutor.js +211 -0
- package/dist/attack/architectureScoutExecutor.js.map +1 -0
- package/dist/attack/architectureScoutLoop.d.ts +36 -0
- package/dist/attack/architectureScoutLoop.js +403 -0
- package/dist/attack/architectureScoutLoop.js.map +1 -0
- package/dist/attack/architectureScoutProtocol.d.ts +209 -0
- package/dist/attack/architectureScoutProtocol.js +47 -0
- package/dist/attack/architectureScoutProtocol.js.map +1 -0
- package/dist/attack/candidateStore.d.ts +95 -0
- package/dist/attack/candidateStore.js +231 -0
- package/dist/attack/candidateStore.js.map +1 -0
- package/dist/attack/evidenceLedger.d.ts +67 -0
- package/dist/attack/evidenceLedger.js +192 -0
- package/dist/attack/evidenceLedger.js.map +1 -0
- package/dist/attack/finishGate.d.ts +62 -0
- package/dist/attack/finishGate.js +209 -0
- package/dist/attack/finishGate.js.map +1 -0
- package/dist/attack/fixCodeMerge.d.ts +27 -0
- package/dist/attack/fixCodeMerge.js +42 -0
- package/dist/attack/fixCodeMerge.js.map +1 -0
- package/dist/attack/fixVerifyLoop.d.ts +55 -0
- package/dist/attack/fixVerifyLoop.js +187 -0
- package/dist/attack/fixVerifyLoop.js.map +1 -0
- package/dist/attack/investigationProfiles.d.ts +36 -0
- package/dist/attack/investigationProfiles.js +144 -0
- package/dist/attack/investigationProfiles.js.map +1 -0
- package/dist/attack/investigationState.d.ts +227 -0
- package/dist/attack/investigationState.js +666 -0
- package/dist/attack/investigationState.js.map +1 -0
- package/dist/attack/mutationOperators.d.ts +22 -0
- package/dist/attack/mutationOperators.js +170 -0
- package/dist/attack/mutationOperators.js.map +1 -0
- package/dist/attack/mutationTest.d.ts +33 -0
- package/dist/attack/mutationTest.js +110 -0
- package/dist/attack/mutationTest.js.map +1 -0
- package/dist/attack/proofGate.d.ts +20 -0
- package/dist/attack/proofGate.js +104 -0
- package/dist/attack/proofGate.js.map +1 -0
- package/dist/attack/proofTypes.d.ts +57 -0
- package/dist/attack/proofTypes.js +32 -0
- package/dist/attack/proofTypes.js.map +1 -0
- package/dist/attack/protocolValidator.d.ts +50 -0
- package/dist/attack/protocolValidator.js +427 -0
- package/dist/attack/protocolValidator.js.map +1 -0
- package/dist/attack/qualityMetrics.d.ts +133 -0
- package/dist/attack/qualityMetrics.js +226 -0
- package/dist/attack/qualityMetrics.js.map +1 -0
- package/dist/attack/scanScheduler.d.ts +52 -0
- package/dist/attack/scanScheduler.js +265 -0
- package/dist/attack/scanScheduler.js.map +1 -0
- package/dist/attack/scanState.d.ts +58 -0
- package/dist/attack/scanState.js +102 -0
- package/dist/attack/scanState.js.map +1 -0
- package/dist/attack/searchIntent.d.ts +16 -0
- package/dist/attack/searchIntent.js +57 -0
- package/dist/attack/searchIntent.js.map +1 -0
- package/dist/attack/verifyLoop.d.ts +43 -0
- package/dist/attack/verifyLoop.js +329 -15
- package/dist/attack/verifyLoop.js.map +1 -1
- package/dist/attack/workItem.d.ts +57 -0
- package/dist/attack/workItem.js +225 -0
- package/dist/attack/workItem.js.map +1 -0
- package/dist/audit/findingReviewQueue.d.ts +109 -0
- package/dist/audit/findingReviewQueue.js +335 -0
- package/dist/audit/findingReviewQueue.js.map +1 -0
- package/dist/audit/scanAuditLog.d.ts +160 -0
- package/dist/audit/scanAuditLog.js +404 -0
- package/dist/audit/scanAuditLog.js.map +1 -0
- package/dist/dependency/dependencyChecker.js +35 -9
- package/dist/dependency/dependencyChecker.js.map +1 -1
- package/dist/dependency/exploitPriority.d.ts +33 -0
- package/dist/dependency/exploitPriority.js +78 -0
- package/dist/dependency/exploitPriority.js.map +1 -0
- package/dist/dependency/finding.d.ts +16 -0
- package/dist/dependency/osvClient.js +2 -0
- package/dist/dependency/osvClient.js.map +1 -1
- package/dist/dependency/types.d.ts +12 -1
- package/dist/mcp/server.js +13 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +1 -0
- package/dist/mcp/tools.js +127 -6
- package/dist/mcp/tools.js.map +1 -1
- package/dist/project-map/agentMemory.d.ts +83 -1
- package/dist/project-map/agentMemory.js +197 -7
- package/dist/project-map/agentMemory.js.map +1 -1
- package/dist/project-map/architectureContext.d.ts +202 -0
- package/dist/project-map/architectureContext.js +421 -0
- package/dist/project-map/architectureContext.js.map +1 -0
- package/dist/project-map/blastRadius.d.ts +54 -0
- package/dist/project-map/blastRadius.js +196 -0
- package/dist/project-map/blastRadius.js.map +1 -0
- package/dist/project-map/callGraphExtractor.d.ts +13 -0
- package/dist/project-map/callGraphExtractor.js +222 -0
- package/dist/project-map/callGraphExtractor.js.map +1 -0
- package/dist/project-map/capabilityRegistry.d.ts +46 -0
- package/dist/project-map/capabilityRegistry.js +91 -0
- package/dist/project-map/capabilityRegistry.js.map +1 -0
- package/dist/project-map/findTests.d.ts +29 -0
- package/dist/project-map/findTests.js +236 -0
- package/dist/project-map/findTests.js.map +1 -0
- package/dist/project-map/handlerInventory.d.ts +112 -0
- package/dist/project-map/handlerInventory.js +184 -0
- package/dist/project-map/handlerInventory.js.map +1 -0
- package/dist/project-map/implementationResolver.d.ts +43 -0
- package/dist/project-map/implementationResolver.js +217 -0
- package/dist/project-map/implementationResolver.js.map +1 -0
- package/dist/project-map/mapContext.d.ts +6 -1
- package/dist/project-map/mapContext.js +1 -0
- package/dist/project-map/mapContext.js.map +1 -1
- package/dist/project-map/scanCache.d.ts +57 -3
- package/dist/project-map/scanCache.js +61 -2
- package/dist/project-map/scanCache.js.map +1 -1
- package/dist/project-map/symbolIndex.d.ts +39 -0
- package/dist/project-map/symbolIndex.js +385 -0
- package/dist/project-map/symbolIndex.js.map +1 -0
- package/dist/tooling/agentEvalScoring.d.ts +77 -0
- package/dist/tooling/agentEvalScoring.js +140 -0
- package/dist/tooling/agentEvalScoring.js.map +1 -0
- package/dist/tooling/agentRegression.d.ts +53 -0
- package/dist/tooling/agentRegression.js +99 -0
- package/dist/tooling/agentRegression.js.map +1 -0
- package/dist/tools/agentScan.d.ts +69 -0
- package/dist/tools/agentScan.js +702 -43
- package/dist/tools/agentScan.js.map +1 -1
- package/dist/tools/findingReviewTools.d.ts +22 -0
- package/dist/tools/findingReviewTools.js +121 -0
- package/dist/tools/findingReviewTools.js.map +1 -0
- package/dist/tools/fix.js +1 -1
- package/dist/tools/fix.js.map +1 -1
- package/dist/tools/map.js +191 -1
- package/dist/tools/map.js.map +1 -1
- package/dist/tools/runTests.d.ts +2 -0
- package/dist/tools/runTests.js +29 -0
- package/dist/tools/runTests.js.map +1 -0
- package/dist/utils/effectMock.d.ts +1 -0
- package/dist/utils/effectMock.js +162 -0
- package/dist/utils/effectMock.js.map +1 -0
- package/dist/utils/gitContext.d.ts +26 -0
- package/dist/utils/gitContext.js +317 -0
- package/dist/utils/gitContext.js.map +1 -0
- package/dist/utils/localTestRunner.d.ts +57 -2
- package/dist/utils/localTestRunner.js +122 -101
- package/dist/utils/localTestRunner.js.map +1 -1
- package/dist/utils/runtimeDetect.d.ts +12 -2
- package/dist/utils/runtimeDetect.js +247 -10
- package/dist/utils/runtimeDetect.js.map +1 -1
- package/dist/utils/securityConfig.d.ts +17 -0
- package/dist/utils/securityConfig.js +192 -0
- package/dist/utils/securityConfig.js.map +1 -0
- package/dist/utils/testCommandPolicy.d.ts +36 -0
- package/dist/utils/testCommandPolicy.js +252 -0
- package/dist/utils/testCommandPolicy.js.map +1 -0
- package/dist/utils/testRunner.d.ts +56 -0
- package/dist/utils/testRunner.js +246 -0
- package/dist/utils/testRunner.js.map +1 -0
- package/dist/utils/testSafety.d.ts +40 -2
- package/dist/utils/testSafety.js +205 -26
- package/dist/utils/testSafety.js.map +1 -1
- package/dist/utils/verificationSandbox.d.ts +113 -0
- package/dist/utils/verificationSandbox.js +656 -0
- package/dist/utils/verificationSandbox.js.map +1 -0
- 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":";AAAA;;;;;;;;;;;;;GAaG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuGH,0DA0CC;AAqCD,4BA6FC;AAjRD,+CAAiC;AACjC,uCAAyB;AACzB,2CAA6B;AAC7B,+CAAoD;AACpD,uDAAuF;AACvF,2DAA6G;AAC7G,6CAA+C;AAE/C,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,CAAC;AAClC,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,CAAC;AACxC,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC;AAC7B,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;AAuClF,SAAS,YAAY,CAAC,CAAS;IAC3B,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,iBAAiB,CAAC,aAAqB,EAAE,OAAe;IAC7D,IAAI,CAAC;QACD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC3D,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,SAAS,oBAAoB,CAAC,aAAqB;IAC/C,MAAM,GAAG,GAAG,iBAAiB,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,iBAAiB,CAAC,aAAa,EAAE,mBAAmB,CAAC;WAC3D,iBAAiB,CAAC,aAAa,EAAE,gBAAgB,CAAC;WAClD,iBAAiB,CAAC,aAAa,EAAE,WAAW,CAAC;WAC7C,iBAAiB,CAAC,aAAa,EAAE,UAAU,CAAC;WAC5C,iBAAiB,CAAC,aAAa,EAAE,kBAAkB,CAAC;WACpD,iBAAiB,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;IAC1D,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO,GAAG,GAAG,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;AAChD,CAAC;AAED,SAAS,cAAc,CAAC,CAAS;IAC7B,IAAI,CAAC,CAAC,MAAM,IAAI,UAAU;QAAE,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,iBAAiB,CAAC;AACtD,CAAC;AAED,SAAS,UAAU,CAAC,OAAmC;IACnD,QAAQ,OAAO,EAAE,CAAC;QACd,KAAK,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC;QAC7B,KAAK,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC;QAC7B,KAAK,OAAO,CAAC,CAAC,OAAO,OAAO,CAAC;QAC7B,KAAK,SAAS,CAAC,CAAC,OAAO,SAAS,CAAC;QACjC,KAAK,SAAS,CAAC,CAAC,OAAO,SAAS,CAAC;QACjC,KAAK,qBAAqB,CAAC,CAAC,OAAO,qBAAqB,CAAC;QACzD,OAAO,CAAC,CAAC,OAAO,OAAO,CAAC;IAC5B,CAAC;AACL,CAAC;AAOD,SAAgB,uBAAuB,CAAC,GAAoB,EAAE,aAAqB;IAC/E,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,UAAU,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;QACrE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAC;IAC1E,CAAC;IAED,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAA,uCAAmB,EAAC;YAC/B,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,SAAS,EAAE,GAAG,CAAC,SAAS;SAC3B,EAAE,aAAa,CAAC,CAAC;QAClB,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAM,EAAE,CAAC;QAC3D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACjD,CAAC;IAED,iBAAiB;IACjB,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qDAAqD,EAAE,CAAC;IACvF,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QACtC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,eAAe,eAAe,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC;IAC7G,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,MAAM,IAAI,QAAQ,EAAE,EAAE,CAAC;IAC1H,CAAC;IACD,IAAI,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,qBAAqB,EAAE,CAAC;QACpE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,8BAA8B,qBAAqB,SAAS,EAAE,CAAC;IAC9F,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,4BAAe,EAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mCAAmC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;IACpF,CAAC;IACD,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QAClB,MAAM,WAAW,GAAG,IAAA,4BAAe,EAAC,GAAG,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QACpE,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACvB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9F,CAAC;IACL,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAoB,EAAE,OAA8B;IAC9E,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC;YAC1C,CAAC,CAAC,YAAY,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAChD,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,OAAO,2CAA2C,IAAA,0CAAsB,EAAC,OAAO,CAAC,cAAc,OAAO,CAAC,SAAS,KAAK,KAAK,GAAG,OAAO,EAAE,CAAC;IAC3I,CAAC;IACD,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,mBAAmB,GAAG,CAAC,WAAW,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3F,OAAO,iDAAiD,GAAG,CAAC,MAAM,aAAa,GAAG,CAAC,MAAO,CAAC,MAAM,gBAAgB,YAAY,CAAC,GAAG,CAAC,MAAO,CAAC,IAAI,SAAS,cAAc,GAAG,CAAC,SAAS,IAAI,kBAAkB,IAAI,CAAC;AACjN,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAoB,EAAE,OAAyC,EAAE,aAAqB;IAC/G,MAAM,MAAM,GAAG,oBAAoB,CAAC,aAAa,CAAC,CAAC;IACnD,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,EAAE,CAAC;QACrC,OAAO;YACH,GAAG,CAAC,IAAI;YACR,OAAO,CAAC,UAAU;YAClB,OAAO,CAAC,IAAI;YACZ,OAAO,CAAC,aAAa;YACrB,GAAG,CAAC,WAAW;YACf,OAAO,CAAC,SAAS;YACjB,MAAM;SACT,CAAC;IACN,CAAC;IACD,OAAO;QACH,GAAG,CAAC,IAAI;QACR,GAAG,CAAC,MAAM;QACV,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;QAC5C,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI;QACtD,GAAG,CAAC,SAAS,IAAI,kBAAkB;QACnC,MAAM;KACT,CAAC;AACN,CAAC;AAEM,KAAK,UAAU,QAAQ,CAC1B,GAAoB,EACpB,aAAqB,EACrB,OAKC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAG,uBAAuB,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAC/D,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO;YACH,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,CAAC,CAAC;YACZ,MAAM,EAAE,qBAAqB,UAAU,CAAC,KAAK,EAAE;YAC/C,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;SACrC,CAAC;IACN,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;IACnC,MAAM,OAAO,GAAG,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,cAAc,GAAG,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAE5E,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC;IACpC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,IAAI,uBAAc,EAAE,CAAC;IACvD,IAAI,UAAU;QAAE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IAErC,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,eAAe,CACzC,sBAAsB,EACtB,OAAO,EACP,cAAc,EACd,MAAM,EACN,iBAAiB,EACjB,aAAa,CAChB,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACrB,OAAO;gBACH,QAAQ,EAAE,KAAK;gBACf,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,QAAQ;gBAChB,QAAQ,EAAE,CAAC,CAAC;gBACZ,MAAM,EAAE,kBAAkB,QAAQ,CAAC,MAAM,GAAG;gBAC5C,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;aACrC,CAAC;QACN,CAAC;QAED,IAAI,UAA2B,CAAC;QAChC,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,EAAE,CAAC;YACrC,UAAU,GAAG,MAAM,IAAA,gCAAc,EAC7B,OAAO,CAAC,UAAU,EAClB,OAAO,CAAC,IAAI,EACZ,aAAa,EACb;gBACI,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,MAAM,EAAE,OAAO,EAAE,MAAM;gBACvB,cAAc,EAAE,OAAO,EAAE,cAAc;aAC1C,CACJ,CAAC;QACN,CAAC;aAAM,CAAC;YACJ,UAAU,GAAG,MAAM,IAAA,8BAAY,EAC3B,GAAG,CAAC,MAAO,EACX,GAAG,CAAC,MAAO,EACX,aAAa,EACb;gBACI,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,IAAI;gBACpC,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,kBAAkB;gBAC9C,MAAM,EAAE,OAAO,EAAE,MAAM;gBACvB,cAAc,EAAE,OAAO,EAAE,cAAc;aAC1C,CACJ,CAAC;QACN,CAAC;QAED,OAAO;YACH,QAAQ,EAAE,IAAI;YACd,SAAS,EAAE,QAAQ,CAAC,SAAS;YAC7B,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC;YACtC,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC;YACzC,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS;YACrF,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;SACrC,CAAC;IACN,CAAC;YAAS,CAAC;QACP,IAAI,UAAU;YAAE,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACxC,CAAC;AACL,CAAC"}
|
|
@@ -1,4 +1,42 @@
|
|
|
1
|
-
|
|
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;
|
package/dist/utils/testSafety.js
CHANGED
|
@@ -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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
10
|
-
const
|
|
11
|
-
child_process
|
|
12
|
-
net
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
18
|
-
|
|
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
|
|
134
|
+
return { allowed: false, reason };
|
|
21
135
|
}
|
|
22
136
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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":";;
|
|
1
|
+
{"version":3,"file":"testSafety.js","sourceRoot":"","sources":["../../src/utils/testSafety.ts"],"names":[],"mappings":"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"}
|