fullcourtdefense-cli 1.7.11 → 1.7.13
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/commands/local-scan.js +154 -31
- package/dist/version.json +1 -1
- package/package.json +1 -1
|
@@ -1096,7 +1096,7 @@ function compactScanHtml(args) {
|
|
|
1096
1096
|
h1 { margin: 6px 0 8px; font-size: 26px; line-height: 1.15; }
|
|
1097
1097
|
p { color: #475569; line-height: 1.55; }
|
|
1098
1098
|
.grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
|
|
1099
|
-
.menuShell { display: grid; grid-template-columns: minmax(
|
|
1099
|
+
.menuShell { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1.15fr) minmax(180px, .7fr); gap: 14px; margin-top: 18px; align-items: stretch; }
|
|
1100
1100
|
.menuGroup { border: 1px solid #dbeafe; background: rgba(255,255,255,.7); border-radius: 20px; padding: 12px; }
|
|
1101
1101
|
.menuGroup.run { border-color: #bbf7d0; background: #f0fdf4; }
|
|
1102
1102
|
.menuLabel { color: #475569; font-size: 11px; font-weight: 900; letter-spacing: .08em; text-transform: uppercase; margin: 0 0 9px; }
|
|
@@ -1108,6 +1108,11 @@ function compactScanHtml(args) {
|
|
|
1108
1108
|
.sectionTitle h2 { margin: 0; font-size: 18px; }
|
|
1109
1109
|
.muted { color: #64748b; font-size: 13px; }
|
|
1110
1110
|
.card { cursor: pointer; border: 2px solid #e2e8f0; background: white; border-radius: 18px; padding: 16px; text-align: left; transition: .15s ease; }
|
|
1111
|
+
.workflowCard { min-height: 118px; }
|
|
1112
|
+
.workflowCard b { font-size: 18px; }
|
|
1113
|
+
.workflowCard span { font-size: 13px; }
|
|
1114
|
+
.scanTypeGrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 12px 0; }
|
|
1115
|
+
.advancedScanGrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 8px 0 12px; }
|
|
1111
1116
|
.card:hover, .card.active { border-color: #2563eb; background: #eff6ff; transform: translateY(-1px); }
|
|
1112
1117
|
.card b { display: block; font-size: 14px; margin-bottom: 4px; }
|
|
1113
1118
|
.card span { color: #64748b; font-size: 12px; line-height: 1.35; }
|
|
@@ -1157,8 +1162,8 @@ function compactScanHtml(args) {
|
|
|
1157
1162
|
<main class="wrap">
|
|
1158
1163
|
<section class="hero">
|
|
1159
1164
|
<div class="eyebrow">Local Web Console</div>
|
|
1160
|
-
<h1>
|
|
1161
|
-
<p>
|
|
1165
|
+
<h1>Choose a local workflow</h1>
|
|
1166
|
+
<p>Pick one clear path. Run MCP Tool is a one-off tool call. Security Scan is a red-team scan against an internal endpoint, RAG target, or MCP server.</p>
|
|
1162
1167
|
<div class="auth">
|
|
1163
1168
|
<div class="eyebrow">${isConfigured ? 'Authenticated' : 'Authentication Required'}</div>
|
|
1164
1169
|
<p id="authStatus">${isConfigured
|
|
@@ -1181,7 +1186,7 @@ function compactScanHtml(args) {
|
|
|
1181
1186
|
</div>
|
|
1182
1187
|
<div class="note" id="backendStatus">Backend status: not checked yet.</div>
|
|
1183
1188
|
</div>
|
|
1184
|
-
<div class="steps">
|
|
1189
|
+
<div class="steps" id="scanSteps">
|
|
1185
1190
|
<div class="step active" id="step-dot-1">1. Connect target</div>
|
|
1186
1191
|
<div class="step" id="step-dot-2">2. Select scan type</div>
|
|
1187
1192
|
<div class="step" id="step-dot-3">3. Run red-team scan</div>
|
|
@@ -1189,19 +1194,15 @@ function compactScanHtml(args) {
|
|
|
1189
1194
|
<div class="menuShell" id="cards">
|
|
1190
1195
|
<div class="menuGroup run">
|
|
1191
1196
|
<div class="menuLabel">Run, not a scan</div>
|
|
1192
|
-
<button class="card active" data-
|
|
1197
|
+
<button class="card workflowCard active" data-workflow="runner"><b>Run one MCP tool</b><span>Call exactly one local MCP tool through a direct server or protected gateway. Best for demos and policy checks.</span></button>
|
|
1193
1198
|
</div>
|
|
1194
1199
|
<div class="menuGroup">
|
|
1195
1200
|
<div class="menuLabel">Security scans</div>
|
|
1196
|
-
<
|
|
1197
|
-
<button class="card" data-target="endpoint"><b>Endpoint Scan</b><span>Red-team an internal agent/chat API.</span></button>
|
|
1198
|
-
<button class="card" data-target="rag"><b>RAG Scan</b><span>Test retrieval URL or local corpus path.</span></button>
|
|
1199
|
-
<button class="card" data-target="mcp"><b>MCP Scan</b><span>Scan tool responses and tool-abuse paths.</span></button>
|
|
1200
|
-
</div>
|
|
1201
|
+
<button class="card workflowCard" data-workflow="scan"><b>Start security scan</b><span>Run quick or full red-team tests against Endpoint, RAG, or MCP targets. Reports save to Full Court Defense.</span></button>
|
|
1201
1202
|
</div>
|
|
1202
1203
|
<div class="menuGroup">
|
|
1203
1204
|
<div class="menuLabel">Help</div>
|
|
1204
|
-
<button class="card" data-
|
|
1205
|
+
<button class="card workflowCard" data-workflow="help"><b>Options</b><span>Modes, formats, and when to use each local workflow.</span></button>
|
|
1205
1206
|
</div>
|
|
1206
1207
|
</div>
|
|
1207
1208
|
</section>
|
|
@@ -1210,8 +1211,8 @@ function compactScanHtml(args) {
|
|
|
1210
1211
|
<div id="step-1" class="stepSection">
|
|
1211
1212
|
<div class="sectionTitle">
|
|
1212
1213
|
<div>
|
|
1213
|
-
<h2>
|
|
1214
|
-
<div class="muted">
|
|
1214
|
+
<h2 id="connectTitle">Run MCP Tool</h2>
|
|
1215
|
+
<div class="muted" id="connectSubtitle">Call one MCP tool from this machine. This is not a scan.</div>
|
|
1215
1216
|
</div>
|
|
1216
1217
|
</div>
|
|
1217
1218
|
<div id="runner-fields">
|
|
@@ -1223,11 +1224,11 @@ function compactScanHtml(args) {
|
|
|
1223
1224
|
<div class="two">
|
|
1224
1225
|
<div>
|
|
1225
1226
|
<label>Protected MCP HTTP/SSE URL</label>
|
|
1226
|
-
<input id="runnerMcpUrl" placeholder="http://127.0.0.1:5066/mcp" />
|
|
1227
|
+
<input id="runnerMcpUrl" placeholder="Optional: http://127.0.0.1:5066/mcp" />
|
|
1227
1228
|
</div>
|
|
1228
1229
|
<div>
|
|
1229
1230
|
<label>Tool name</label>
|
|
1230
|
-
<input id="runnerTool" placeholder="
|
|
1231
|
+
<input id="runnerTool" placeholder="Example: lookup_customer_profile" />
|
|
1231
1232
|
</div>
|
|
1232
1233
|
</div>
|
|
1233
1234
|
<div class="two">
|
|
@@ -1241,12 +1242,12 @@ function compactScanHtml(args) {
|
|
|
1241
1242
|
</div>
|
|
1242
1243
|
</div>
|
|
1243
1244
|
<div class="two">
|
|
1244
|
-
<div><label>Or stdio command</label><input id="runnerMcpCommand" placeholder="
|
|
1245
|
-
<div><label>Command args</label><input id="runnerMcpArgs" placeholder=
|
|
1245
|
+
<div><label>Or stdio command</label><input id="runnerMcpCommand" placeholder="node" /></div>
|
|
1246
|
+
<div><label>Command args</label><input id="runnerMcpArgs" placeholder="C:\\path\\to\\mcp-server.js" /></div>
|
|
1246
1247
|
</div>
|
|
1247
1248
|
<label>Tool arguments JSON</label>
|
|
1248
1249
|
<textarea id="runnerToolArgs" spellcheck="false">{
|
|
1249
|
-
"customerId": "
|
|
1250
|
+
"customerId": "RO-PB-10492"
|
|
1250
1251
|
}</textarea>
|
|
1251
1252
|
<div class="actions">
|
|
1252
1253
|
<button class="primary" id="runMcpTool">Run MCP tool</button>
|
|
@@ -1265,6 +1266,19 @@ function compactScanHtml(args) {
|
|
|
1265
1266
|
</div>
|
|
1266
1267
|
</div>
|
|
1267
1268
|
|
|
1269
|
+
<div id="scan-picker" class="hidden">
|
|
1270
|
+
<div class="note">Security scans run red-team templates locally from this machine. First choose what you want to test.</div>
|
|
1271
|
+
<div class="scanTypeGrid">
|
|
1272
|
+
<button class="card scanTypeCard active" data-target="endpoint"><b>Bot Scan</b><span>Red-team an internal bot, agent, or chat API with prompt-injection templates.</span></button>
|
|
1273
|
+
<button class="card scanTypeCard" data-target="posture"><b>Security Posture Scan</b><span>Run the web-style checkup for HTTPS, headers, auth exposure, and endpoint posture.</span></button>
|
|
1274
|
+
</div>
|
|
1275
|
+
<div class="menuLabel">Advanced local targets</div>
|
|
1276
|
+
<div class="advancedScanGrid">
|
|
1277
|
+
<button class="card scanTypeCard" data-target="rag"><b>RAG Scan</b><span>Test retrieval URL or local corpus path.</span></button>
|
|
1278
|
+
<button class="card scanTypeCard" data-target="mcp"><b>MCP Scan</b><span>Scan tool responses and tool-abuse paths.</span></button>
|
|
1279
|
+
</div>
|
|
1280
|
+
</div>
|
|
1281
|
+
|
|
1268
1282
|
<div id="endpoint-fields" class="hidden">
|
|
1269
1283
|
<label>Internal endpoint URL</label>
|
|
1270
1284
|
<input id="endpoint" placeholder="http://127.0.0.1:3000/chat" />
|
|
@@ -1274,6 +1288,30 @@ function compactScanHtml(args) {
|
|
|
1274
1288
|
</div>
|
|
1275
1289
|
</div>
|
|
1276
1290
|
|
|
1291
|
+
<div id="posture-fields" class="hidden">
|
|
1292
|
+
<div class="note">Security Posture Scan checks endpoint configuration, auth exposure, headers, transport, and operational security signals. This matches the web Security Checkup flow.</div>
|
|
1293
|
+
<div class="two">
|
|
1294
|
+
<div>
|
|
1295
|
+
<label>AI endpoint URL</label>
|
|
1296
|
+
<input id="postureUrl" placeholder="https://your-ai-endpoint.com/api/chat" />
|
|
1297
|
+
</div>
|
|
1298
|
+
<div>
|
|
1299
|
+
<label>HTTP method</label>
|
|
1300
|
+
<select id="postureMethod"><option value="POST" selected>POST</option><option value="GET">GET</option></select>
|
|
1301
|
+
</div>
|
|
1302
|
+
</div>
|
|
1303
|
+
<div class="two">
|
|
1304
|
+
<div>
|
|
1305
|
+
<label>Auth type</label>
|
|
1306
|
+
<select id="postureAuthType"><option value="none" selected>No Auth</option><option value="bearer">Bearer Token</option><option value="api-key">API Key</option></select>
|
|
1307
|
+
</div>
|
|
1308
|
+
<div>
|
|
1309
|
+
<label>Token / API key value</label>
|
|
1310
|
+
<input id="postureToken" type="password" placeholder="Optional" />
|
|
1311
|
+
</div>
|
|
1312
|
+
</div>
|
|
1313
|
+
</div>
|
|
1314
|
+
|
|
1277
1315
|
<div id="rag-fields" class="hidden">
|
|
1278
1316
|
<label>RAG retrieval URL</label>
|
|
1279
1317
|
<input id="ragUrl" placeholder="http://127.0.0.1:8787/rag/retrieve" />
|
|
@@ -1361,25 +1399,42 @@ function compactScanHtml(args) {
|
|
|
1361
1399
|
<b>Red-team console</b>
|
|
1362
1400
|
<span class="pill" id="consoleStatus">Ready</span>
|
|
1363
1401
|
</div>
|
|
1364
|
-
<pre id="out">Full Court Defense Local
|
|
1402
|
+
<pre id="out">Full Court Defense Local Web Console ready.
|
|
1365
1403
|
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1404
|
+
Choose Run MCP Tool for one live tool call.
|
|
1405
|
+
Choose Endpoint/RAG/MCP Scan for a local red-team scan.
|
|
1406
|
+
Local targets stay on this machine; saved scan reports go to Full Court Defense.</pre>
|
|
1369
1407
|
</div>
|
|
1370
1408
|
</div>
|
|
1371
1409
|
</section>
|
|
1372
1410
|
</main>
|
|
1373
1411
|
<script>
|
|
1412
|
+
const scanTargets = ['endpoint','posture','rag','mcp'];
|
|
1374
1413
|
let target = 'runner';
|
|
1375
1414
|
let step = 1;
|
|
1376
1415
|
const qs = new URLSearchParams(location.search);
|
|
1377
|
-
if (['runner','endpoint','rag','mcp'].includes(qs.get('target'))) target = qs.get('target');
|
|
1416
|
+
if (['runner','endpoint','posture','rag','mcp','help'].includes(qs.get('target'))) target = qs.get('target');
|
|
1378
1417
|
const byId = id => document.getElementById(id);
|
|
1418
|
+
const workflow = () => scanTargets.includes(target) ? 'scan' : target;
|
|
1379
1419
|
const sync = () => {
|
|
1380
|
-
document.querySelectorAll('.
|
|
1381
|
-
|
|
1382
|
-
byId('
|
|
1420
|
+
document.querySelectorAll('.workflowCard').forEach(c => c.classList.toggle('active', c.dataset.workflow === workflow()));
|
|
1421
|
+
document.querySelectorAll('.scanTypeCard').forEach(c => c.classList.toggle('active', c.dataset.target === target));
|
|
1422
|
+
['runner','endpoint','posture','rag','mcp','help'].forEach(id => byId(id + '-fields').classList.toggle('hidden', id !== target));
|
|
1423
|
+
const scanTarget = scanTargets.includes(target);
|
|
1424
|
+
byId('scan-picker').classList.toggle('hidden', !scanTarget);
|
|
1425
|
+
byId('scanSteps').classList.toggle('hidden', !scanTarget);
|
|
1426
|
+
byId('scanActions').classList.toggle('hidden', !scanTarget);
|
|
1427
|
+
byId('connectTitle').textContent = target === 'runner'
|
|
1428
|
+
? 'Run MCP Tool'
|
|
1429
|
+
: target === 'help'
|
|
1430
|
+
? 'Local workflow options'
|
|
1431
|
+
: 'Choose scan target';
|
|
1432
|
+
byId('connectSubtitle').textContent = target === 'runner'
|
|
1433
|
+
? 'Call one MCP tool from this machine. This is not a scan.'
|
|
1434
|
+
: target === 'help'
|
|
1435
|
+
? 'Choose one-off tool run or local red-team scan.'
|
|
1436
|
+
: 'Select Endpoint, RAG, or MCP, then connect the internal target.';
|
|
1437
|
+
if (!scanTarget) setStep(1);
|
|
1383
1438
|
};
|
|
1384
1439
|
const setStep = next => {
|
|
1385
1440
|
step = next;
|
|
@@ -1389,7 +1444,14 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
|
|
|
1389
1444
|
byId('step-dot-' + n).classList.toggle('done', n < step);
|
|
1390
1445
|
});
|
|
1391
1446
|
};
|
|
1392
|
-
document.querySelectorAll('.
|
|
1447
|
+
document.querySelectorAll('.workflowCard').forEach(c => c.onclick = () => {
|
|
1448
|
+
target = c.dataset.workflow === 'scan' ? 'endpoint' : c.dataset.workflow;
|
|
1449
|
+
sync();
|
|
1450
|
+
});
|
|
1451
|
+
document.querySelectorAll('.scanTypeCard').forEach(c => c.onclick = () => {
|
|
1452
|
+
target = c.dataset.target;
|
|
1453
|
+
sync();
|
|
1454
|
+
});
|
|
1393
1455
|
sync();
|
|
1394
1456
|
byId('ragUrl').value = qs.get('ragUrl') || '';
|
|
1395
1457
|
byId('ragPath').value = qs.get('ragPath') || '';
|
|
@@ -1398,13 +1460,14 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
|
|
|
1398
1460
|
byId('mcpCommand').value = qs.get('mcpCommand') || '';
|
|
1399
1461
|
byId('mcpArgs').value = qs.get('mcpArgs') || '';
|
|
1400
1462
|
byId('runnerMcpUrl').value = qs.get('mcpUrl') || '';
|
|
1401
|
-
byId('runnerMcpCommand').value = qs.get('mcpCommand') || '
|
|
1463
|
+
byId('runnerMcpCommand').value = qs.get('mcpCommand') || '';
|
|
1402
1464
|
byId('runnerMcpArgs').value = qs.get('mcpArgs') || '';
|
|
1403
1465
|
byId('runnerTool').value = qs.get('mcpTool') || '';
|
|
1404
1466
|
byId('runnerOperation').value = qs.get('operation') || '';
|
|
1405
1467
|
const payload = () => ({
|
|
1406
1468
|
target, mode: byId('mode').value, format: byId('format').value,
|
|
1407
1469
|
endpoint: byId('endpoint').value, inputField: byId('inputField').value, outputField: byId('outputField').value,
|
|
1470
|
+
postureUrl: byId('postureUrl').value, postureMethod: byId('postureMethod').value, postureAuthType: byId('postureAuthType').value, postureToken: byId('postureToken').value,
|
|
1408
1471
|
ragUrl: byId('ragUrl').value, ragPath: byId('ragPath').value, ragInputField: byId('ragInputField').value, ragOutputField: byId('ragOutputField').value,
|
|
1409
1472
|
mcpUrl: byId('mcpUrl').value, mcpCommand: byId('mcpCommand').value, mcpArgs: byId('mcpArgs').value, mcpTool: byId('mcpTool').value
|
|
1410
1473
|
});
|
|
@@ -1440,6 +1503,7 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
|
|
|
1440
1503
|
const renderCommand = p => {
|
|
1441
1504
|
const parts = ['fullcourtdefense scan --local --type', p.target, '--mode', p.mode, '--format', p.format, '--no-open'];
|
|
1442
1505
|
if (p.target === 'endpoint') parts.push('--endpoint', JSON.stringify(p.endpoint), '--method POST --request-format custom --input-field', p.inputField || 'message', '--output-field', p.outputField || 'response');
|
|
1506
|
+
if (p.target === 'posture') return 'Security Posture Scan runs through this local web UI and calls the Full Court Defense posture checkup API for ' + (p.postureUrl || '<endpoint-url>');
|
|
1443
1507
|
if (p.target === 'rag') { if (p.ragUrl) parts.push('--rag-url', JSON.stringify(p.ragUrl), '--method POST --request-format custom --input-field', p.ragInputField || 'query', '--output-field', p.ragOutputField || 'chunks'); else parts.push('--rag-path', JSON.stringify(p.ragPath || '.\\\\docs')); }
|
|
1444
1508
|
if (p.target === 'mcp') { if (p.mcpUrl) parts.push('--mcp-url', JSON.stringify(p.mcpUrl)); else parts.push('--mcp-command', p.mcpCommand || 'node', '--mcp-args', JSON.stringify(p.mcpArgs || '.\\\\server.js')); parts.push('--mcp-tool', p.mcpTool || 'all'); }
|
|
1445
1509
|
return parts.join(' ');
|
|
@@ -1495,6 +1559,10 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
|
|
|
1495
1559
|
sync();
|
|
1496
1560
|
setStep(1);
|
|
1497
1561
|
byId('endpoint').value = '';
|
|
1562
|
+
byId('postureUrl').value = '';
|
|
1563
|
+
byId('postureMethod').value = 'POST';
|
|
1564
|
+
byId('postureAuthType').value = 'none';
|
|
1565
|
+
byId('postureToken').value = '';
|
|
1498
1566
|
byId('inputField').value = 'message';
|
|
1499
1567
|
byId('outputField').value = 'response';
|
|
1500
1568
|
byId('ragUrl').value = '';
|
|
@@ -1506,18 +1574,18 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
|
|
|
1506
1574
|
byId('mcpArgs').value = '';
|
|
1507
1575
|
byId('mcpTool').value = 'all';
|
|
1508
1576
|
byId('runnerMcpUrl').value = '';
|
|
1509
|
-
byId('runnerMcpCommand').value = '
|
|
1577
|
+
byId('runnerMcpCommand').value = '';
|
|
1510
1578
|
byId('runnerMcpArgs').value = '';
|
|
1511
1579
|
byId('runnerTool').value = '';
|
|
1512
1580
|
byId('runnerOperation').value = '';
|
|
1513
|
-
byId('runnerToolArgs').value = '{\\n "customerId": "
|
|
1581
|
+
byId('runnerToolArgs').value = '{\\n "customerId": "RO-PB-10492"\\n}';
|
|
1514
1582
|
byId('mcpResultCard').classList.add('hidden');
|
|
1515
1583
|
byId('mcpResultJson').value = '';
|
|
1516
1584
|
byId('mcpResultTable').innerHTML = '';
|
|
1517
1585
|
byId('mode').value = 'quick';
|
|
1518
1586
|
byId('format').value = 'report';
|
|
1519
1587
|
clearScanSummary();
|
|
1520
|
-
setConsole('Full Court Defense Local
|
|
1588
|
+
setConsole('Full Court Defense Local Web Console ready.\\n\\nChoose Run MCP Tool for one live tool call.\\nChoose Endpoint/RAG/MCP Scan for a local red-team scan.', 'Ready');
|
|
1521
1589
|
};
|
|
1522
1590
|
byId('command').onclick = () => { setConsole(renderCommand(payload()), 'Command'); };
|
|
1523
1591
|
byId('connectNext').onclick = () => setStep(2);
|
|
@@ -1699,6 +1767,20 @@ Full uses the full web attack corpus bundled with the CLI.</pre>
|
|
|
1699
1767
|
byId('run').textContent = 'Run local scan';
|
|
1700
1768
|
return;
|
|
1701
1769
|
}
|
|
1770
|
+
if (target === 'posture') {
|
|
1771
|
+
try {
|
|
1772
|
+
setConsole('Starting Security Posture Scan...\\n', 'Running posture');
|
|
1773
|
+
const postureRes = await fetch('/posture/run', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload()) });
|
|
1774
|
+
const postureData = await postureRes.json();
|
|
1775
|
+
setConsole(JSON.stringify(postureData, null, 2), postureData.ok ? 'Posture complete' : 'Posture failed');
|
|
1776
|
+
} catch (error) {
|
|
1777
|
+
setConsole('Security Posture Scan failed: ' + (error && error.message ? error.message : String(error)), 'Posture failed');
|
|
1778
|
+
} finally {
|
|
1779
|
+
byId('run').disabled = false;
|
|
1780
|
+
byId('run').textContent = 'Run local scan';
|
|
1781
|
+
}
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1702
1784
|
setConsole('Starting local red-team scan...\\n', 'Running');
|
|
1703
1785
|
const res = await fetch('/run', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload()) });
|
|
1704
1786
|
if (!res.body) {
|
|
@@ -1811,6 +1893,40 @@ async function runCliFromBrowser(body, onChunk) {
|
|
|
1811
1893
|
});
|
|
1812
1894
|
});
|
|
1813
1895
|
}
|
|
1896
|
+
async function runPostureScanFromBrowser(args, body) {
|
|
1897
|
+
const auth = currentShieldConfig(args);
|
|
1898
|
+
const apiUrl = (auth.apiUrl || DEFAULT_API_URL).replace(/\/$/, '');
|
|
1899
|
+
const endpoint = typeof body.postureUrl === 'string' ? body.postureUrl.trim() : '';
|
|
1900
|
+
const method = body.postureMethod === 'GET' ? 'GET' : 'POST';
|
|
1901
|
+
const authType = typeof body.postureAuthType === 'string' ? body.postureAuthType : 'none';
|
|
1902
|
+
const token = typeof body.postureToken === 'string' ? body.postureToken.trim() : '';
|
|
1903
|
+
if (!endpoint)
|
|
1904
|
+
throw new Error('AI endpoint URL is required for Security Posture Scan.');
|
|
1905
|
+
const headers = {};
|
|
1906
|
+
if (authType === 'bearer' && token)
|
|
1907
|
+
headers.Authorization = `Bearer ${token}`;
|
|
1908
|
+
if (authType === 'api-key' && token)
|
|
1909
|
+
headers['X-API-Key'] = token;
|
|
1910
|
+
const response = await fetch(`${apiUrl}/api/posture/scan/public`, {
|
|
1911
|
+
method: 'POST',
|
|
1912
|
+
headers: { 'content-type': 'application/json' },
|
|
1913
|
+
body: JSON.stringify({
|
|
1914
|
+
endpoint,
|
|
1915
|
+
method,
|
|
1916
|
+
scanMode: 'passive',
|
|
1917
|
+
...(Object.keys(headers).length ? { headers } : {}),
|
|
1918
|
+
}),
|
|
1919
|
+
signal: AbortSignal.timeout(60000),
|
|
1920
|
+
});
|
|
1921
|
+
const text = await response.text();
|
|
1922
|
+
return {
|
|
1923
|
+
ok: response.ok,
|
|
1924
|
+
status: response.status,
|
|
1925
|
+
endpoint,
|
|
1926
|
+
scanType: 'security_posture',
|
|
1927
|
+
result: text,
|
|
1928
|
+
};
|
|
1929
|
+
}
|
|
1814
1930
|
function createMcpClient(options) {
|
|
1815
1931
|
if (options.transport === 'sse')
|
|
1816
1932
|
return new SseMcpClient(options);
|
|
@@ -1977,6 +2093,13 @@ function startCompactWebServer(args) {
|
|
|
1977
2093
|
res.end(JSON.stringify(result));
|
|
1978
2094
|
return;
|
|
1979
2095
|
}
|
|
2096
|
+
if (req.method === 'POST' && url.pathname === '/posture/run') {
|
|
2097
|
+
const body = await readRequestBody(req);
|
|
2098
|
+
const result = await runPostureScanFromBrowser(args, body);
|
|
2099
|
+
res.writeHead(result.ok ? 200 : 400, { 'content-type': 'application/json; charset=utf-8' });
|
|
2100
|
+
res.end(JSON.stringify(result));
|
|
2101
|
+
return;
|
|
2102
|
+
}
|
|
1980
2103
|
if (req.method === 'POST' && url.pathname === '/run') {
|
|
1981
2104
|
const body = await readRequestBody(req);
|
|
1982
2105
|
res.writeHead(200, {
|
package/dist/version.json
CHANGED