agentaudit 3.10.9 → 3.10.10
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/cli.mjs +59 -67
- package/index.mjs +8 -8
- package/package.json +3 -3
package/cli.mjs
CHANGED
|
@@ -435,26 +435,31 @@ function singleSelect(items, { title = 'Select', hint = '↑↓=move Enter=sele
|
|
|
435
435
|
});
|
|
436
436
|
}
|
|
437
437
|
|
|
438
|
-
async function
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
438
|
+
async function validateApiKey(apiKey) {
|
|
439
|
+
try {
|
|
440
|
+
const res = await fetch(`${REGISTRY_URL}/api/auth/validate`, {
|
|
441
|
+
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
442
|
+
signal: AbortSignal.timeout(10_000),
|
|
443
|
+
});
|
|
444
|
+
if (res.ok) {
|
|
445
|
+
const data = await res.json();
|
|
446
|
+
return { valid: true, agent_name: data.agent_name || null };
|
|
447
|
+
}
|
|
448
|
+
return { valid: false, agent_name: null };
|
|
449
|
+
} catch {
|
|
450
|
+
return { valid: false, agent_name: null };
|
|
451
|
+
}
|
|
447
452
|
}
|
|
448
453
|
|
|
449
454
|
async function setupCommand() {
|
|
450
|
-
console.log(` ${c.bold}AgentAudit
|
|
451
|
-
console.log(` ${c.dim}
|
|
455
|
+
console.log(` ${c.bold}AgentAudit Setup${c.reset}`);
|
|
456
|
+
console.log(` ${c.dim}Link your API key to upload audit reports to agentaudit.dev${c.reset}`);
|
|
452
457
|
console.log();
|
|
453
458
|
|
|
454
459
|
const existing = loadCredentials();
|
|
455
460
|
if (existing) {
|
|
456
|
-
console.log(` ${icons.safe} Already
|
|
457
|
-
console.log(` ${c.dim}Key: ${existing.api_key.slice(0,
|
|
461
|
+
console.log(` ${icons.safe} Already configured as ${c.bold}${existing.agent_name}${c.reset}`);
|
|
462
|
+
console.log(` ${c.dim}Key: ${existing.api_key.slice(0, 12)}...${c.reset}`);
|
|
458
463
|
console.log();
|
|
459
464
|
const answer = await askQuestion(` Reconfigure? ${c.dim}(y/N)${c.reset} `);
|
|
460
465
|
if (answer.toLowerCase() !== 'y') {
|
|
@@ -464,39 +469,28 @@ async function setupCommand() {
|
|
|
464
469
|
console.log();
|
|
465
470
|
}
|
|
466
471
|
|
|
467
|
-
console.log(` ${c.bold}1
|
|
468
|
-
console.log(` ${c.
|
|
469
|
-
console.log();
|
|
470
|
-
const choice = await askQuestion(` Choice ${c.dim}(1/2)${c.reset}: `);
|
|
472
|
+
console.log(` ${c.bold}Step 1:${c.reset} Create an API key at ${c.cyan}${REGISTRY_URL}/profile${c.reset}`);
|
|
473
|
+
console.log(` ${c.dim}Sign in with GitHub, then click "Create API Key".${c.reset}`);
|
|
471
474
|
console.log();
|
|
475
|
+
const key = await askQuestion(` ${c.bold}Step 2:${c.reset} Paste your API key here: `);
|
|
476
|
+
if (!key || !key.trim()) {
|
|
477
|
+
console.log(` ${c.red}No key entered.${c.reset}`);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
472
480
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const
|
|
477
|
-
saveCredentials({ api_key: key, agent_name:
|
|
481
|
+
process.stdout.write(` Validating...`);
|
|
482
|
+
const validation = await validateApiKey(key.trim());
|
|
483
|
+
if (validation.valid) {
|
|
484
|
+
const agentName = validation.agent_name || 'agent';
|
|
485
|
+
saveCredentials({ api_key: key.trim(), agent_name: agentName });
|
|
486
|
+
console.log(` ${c.green}valid!${c.reset}`);
|
|
478
487
|
console.log();
|
|
479
|
-
console.log(` ${icons.safe}
|
|
488
|
+
console.log(` ${icons.safe} Logged in as ${c.bold}${agentName}${c.reset}`);
|
|
489
|
+
console.log(` ${c.dim}Key saved to: ${USER_CRED_FILE}${c.reset}`);
|
|
480
490
|
} else {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
return;
|
|
485
|
-
}
|
|
486
|
-
process.stdout.write(` Registering ${c.bold}${name}${c.reset}...`);
|
|
487
|
-
try {
|
|
488
|
-
const data = await registerAgent(name);
|
|
489
|
-
saveCredentials({ api_key: data.api_key, agent_name: data.agent_name });
|
|
490
|
-
console.log(` ${c.green}done!${c.reset}`);
|
|
491
|
-
console.log();
|
|
492
|
-
console.log(` ${icons.safe} Registered as ${c.bold}${data.agent_name}${c.reset}`);
|
|
493
|
-
console.log(` ${c.dim}Key: ${data.api_key.slice(0, 12)}...${c.reset}`);
|
|
494
|
-
console.log(` ${c.dim}Saved to: ${USER_CRED_FILE}${c.reset}`);
|
|
495
|
-
} catch (err) {
|
|
496
|
-
console.log(` ${c.red}failed${c.reset}`);
|
|
497
|
-
console.log(` ${c.red}${err.message}${c.reset}`);
|
|
498
|
-
return;
|
|
499
|
-
}
|
|
491
|
+
console.log(` ${c.red}invalid${c.reset}`);
|
|
492
|
+
console.log(` ${c.red}Key not recognized. Make sure you copied the full key from ${REGISTRY_URL}/profile${c.reset}`);
|
|
493
|
+
return;
|
|
500
494
|
}
|
|
501
495
|
|
|
502
496
|
console.log();
|
|
@@ -1056,7 +1050,7 @@ function quickChecks(files) {
|
|
|
1056
1050
|
|
|
1057
1051
|
async function checkRegistry(slug) {
|
|
1058
1052
|
try {
|
|
1059
|
-
const res = await fetch(`${REGISTRY_URL}/api/
|
|
1053
|
+
const res = await fetch(`${REGISTRY_URL}/api/packages/${encodeURIComponent(slug)}`, {
|
|
1060
1054
|
signal: AbortSignal.timeout(5000),
|
|
1061
1055
|
});
|
|
1062
1056
|
if (res.ok) return await res.json();
|
|
@@ -1146,7 +1140,7 @@ function printScanResult(url, info, files, findings, registryData, duration) {
|
|
|
1146
1140
|
if (registryData) {
|
|
1147
1141
|
const rd = registryData;
|
|
1148
1142
|
const riskScore = rd.risk_score ?? rd.latest_risk_score ?? 0;
|
|
1149
|
-
console.log(`${icons.treeLast} ${c.dim}registry${c.reset} ${riskBadge(riskScore)} Risk ${riskScore} ${c.dim}${REGISTRY_URL}/
|
|
1143
|
+
console.log(`${icons.treeLast} ${c.dim}registry${c.reset} ${riskBadge(riskScore)} Risk ${riskScore} ${c.dim}${REGISTRY_URL}/packages/${slug}${c.reset}`);
|
|
1150
1144
|
} else {
|
|
1151
1145
|
console.log(`${icons.treeLast} ${c.dim}registry${c.reset} ${c.dim}not audited yet${c.reset}`);
|
|
1152
1146
|
}
|
|
@@ -1533,7 +1527,7 @@ async function discoverCommand(options = {}) {
|
|
|
1533
1527
|
const riskScore = regData.risk_score ?? regData.latest_risk_score ?? 0;
|
|
1534
1528
|
const hasOfficial = regData.has_official_audit;
|
|
1535
1529
|
console.log(`${branch} ${c.bold}${server.name}${c.reset} ${sourceLabel}`);
|
|
1536
|
-
console.log(`${pipe} ${riskBadge(riskScore)} Risk ${riskScore} ${hasOfficial ? `${c.green}✔ official${c.reset} ` : ''}${c.dim}${REGISTRY_URL}/
|
|
1530
|
+
console.log(`${pipe} ${riskBadge(riskScore)} Risk ${riskScore} ${hasOfficial ? `${c.green}✔ official${c.reset} ` : ''}${c.dim}${REGISTRY_URL}/packages/${slug}${c.reset}`);
|
|
1537
1531
|
if (resolvedUrl) allServersWithUrls.push({ name: server.name, sourceUrl: resolvedUrl, hasAudit: true, regData });
|
|
1538
1532
|
} else {
|
|
1539
1533
|
unauditedServers++;
|
|
@@ -2046,7 +2040,7 @@ async function auditRepo(url) {
|
|
|
2046
2040
|
if (res.ok) {
|
|
2047
2041
|
const data = await res.json();
|
|
2048
2042
|
console.log(` ${c.green}done${c.reset}`);
|
|
2049
|
-
console.log(` ${c.dim}Report: ${REGISTRY_URL}/
|
|
2043
|
+
console.log(` ${c.dim}Report: ${REGISTRY_URL}/packages/${slug}${c.reset}`);
|
|
2050
2044
|
} else {
|
|
2051
2045
|
let errBody = '';
|
|
2052
2046
|
try { errBody = await res.text(); } catch {}
|
|
@@ -2059,27 +2053,22 @@ async function auditRepo(url) {
|
|
|
2059
2053
|
console.log(` ${c.yellow}failed${c.reset}`);
|
|
2060
2054
|
}
|
|
2061
2055
|
} else if (process.stdin.isTTY) {
|
|
2062
|
-
// No credentials —
|
|
2063
|
-
console.log();
|
|
2064
|
-
console.log(` ${c.bold}Share this audit with the community?${c.reset}`);
|
|
2065
|
-
console.log(` ${c.dim}Uploading helps others assess package security. Account is free.${c.reset}`);
|
|
2056
|
+
// No credentials — prompt to paste key or set up
|
|
2066
2057
|
console.log();
|
|
2067
|
-
console.log(` ${c.bold}
|
|
2068
|
-
console.log(` ${c.
|
|
2058
|
+
console.log(` ${c.bold}Want to upload this report to agentaudit.dev?${c.reset}`);
|
|
2059
|
+
console.log(` ${c.dim}Create an API key at ${c.cyan}${REGISTRY_URL}/profile${c.dim} (sign in with GitHub)${c.reset}`);
|
|
2069
2060
|
console.log();
|
|
2070
|
-
const
|
|
2071
|
-
if (
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2061
|
+
const pastedKey = await askQuestion(` Paste API key ${c.dim}(or Enter to skip)${c.reset}: `);
|
|
2062
|
+
if (pastedKey && pastedKey.trim()) {
|
|
2063
|
+
process.stdout.write(` Validating...`);
|
|
2064
|
+
const validation = await validateApiKey(pastedKey.trim());
|
|
2065
|
+
if (validation.valid) {
|
|
2066
|
+
const agentName = validation.agent_name || 'agent';
|
|
2067
|
+
saveCredentials({ api_key: pastedKey.trim(), agent_name: agentName });
|
|
2068
|
+
creds = { api_key: pastedKey.trim(), agent_name: agentName };
|
|
2069
|
+
console.log(` ${c.green}valid!${c.reset}`);
|
|
2070
|
+
process.stdout.write(` Uploading report...`);
|
|
2076
2071
|
try {
|
|
2077
|
-
process.stdout.write(` Registering ${c.bold}${name}${c.reset}...`);
|
|
2078
|
-
const regData = await registerAgent(name);
|
|
2079
|
-
saveCredentials({ api_key: regData.api_key, agent_name: regData.agent_name });
|
|
2080
|
-
console.log(` ${c.green}done!${c.reset}`);
|
|
2081
|
-
creds = { api_key: regData.api_key, agent_name: regData.agent_name };
|
|
2082
|
-
process.stdout.write(` Uploading report...`);
|
|
2083
2072
|
const res = await fetch(`${REGISTRY_URL}/api/reports`, {
|
|
2084
2073
|
method: 'POST',
|
|
2085
2074
|
headers: {
|
|
@@ -2091,7 +2080,7 @@ async function auditRepo(url) {
|
|
|
2091
2080
|
});
|
|
2092
2081
|
if (res.ok) {
|
|
2093
2082
|
console.log(` ${c.green}done${c.reset}`);
|
|
2094
|
-
console.log(` ${c.dim}Report: ${REGISTRY_URL}/
|
|
2083
|
+
console.log(` ${c.dim}Report: ${REGISTRY_URL}/packages/${slug}${c.reset}`);
|
|
2095
2084
|
} else {
|
|
2096
2085
|
console.log(` ${c.yellow}failed (HTTP ${res.status})${c.reset}`);
|
|
2097
2086
|
}
|
|
@@ -2099,10 +2088,13 @@ async function auditRepo(url) {
|
|
|
2099
2088
|
console.log(` ${c.red}failed${c.reset}`);
|
|
2100
2089
|
console.log(` ${c.dim}${err.message}${c.reset}`);
|
|
2101
2090
|
}
|
|
2091
|
+
} else {
|
|
2092
|
+
console.log(` ${c.red}invalid key${c.reset}`);
|
|
2093
|
+
console.log(` ${c.dim}Run ${c.cyan}agentaudit setup${c.dim} to configure.${c.reset}`);
|
|
2102
2094
|
}
|
|
2103
2095
|
}
|
|
2104
2096
|
} else {
|
|
2105
|
-
console.log(` ${c.dim}Run ${c.cyan}agentaudit setup${c.dim} to
|
|
2097
|
+
console.log(` ${c.dim}Run ${c.cyan}agentaudit setup${c.dim} to configure your API key and upload reports${c.reset}`);
|
|
2106
2098
|
}
|
|
2107
2099
|
|
|
2108
2100
|
console.log();
|
|
@@ -2131,7 +2123,7 @@ async function checkPackage(name) {
|
|
|
2131
2123
|
console.log(` ${c.bold}${name}${c.reset} ${riskBadge(riskScore)}`);
|
|
2132
2124
|
console.log(` ${c.dim}Risk Score: ${riskScore}/100${c.reset}`);
|
|
2133
2125
|
if (data.source_url) console.log(` ${c.dim}Source: ${data.source_url}${c.reset}`);
|
|
2134
|
-
console.log(` ${c.dim}Registry: ${REGISTRY_URL}/
|
|
2126
|
+
console.log(` ${c.dim}Registry: ${REGISTRY_URL}/packages/${name}${c.reset}`);
|
|
2135
2127
|
if (data.has_official_audit) console.log(` ${c.green}✔ Officially audited${c.reset}`);
|
|
2136
2128
|
console.log();
|
|
2137
2129
|
}
|
package/index.mjs
CHANGED
|
@@ -292,7 +292,7 @@ async function resolveSourceUrl(server) {
|
|
|
292
292
|
|
|
293
293
|
async function checkRegistry(slug) {
|
|
294
294
|
try {
|
|
295
|
-
const res = await fetch(`${REGISTRY_URL}/api/
|
|
295
|
+
const res = await fetch(`${REGISTRY_URL}/api/packages/${encodeURIComponent(slug)}`, {
|
|
296
296
|
signal: AbortSignal.timeout(5000),
|
|
297
297
|
});
|
|
298
298
|
if (res.ok) return await res.json();
|
|
@@ -303,7 +303,7 @@ async function checkRegistry(slug) {
|
|
|
303
303
|
// ── MCP Server ───────────────────────────────────────────
|
|
304
304
|
|
|
305
305
|
const server = new Server(
|
|
306
|
-
{ name: 'agentaudit', version: '3.9
|
|
306
|
+
{ name: 'agentaudit', version: '3.10.9' },
|
|
307
307
|
{ capabilities: { tools: {} } }
|
|
308
308
|
);
|
|
309
309
|
|
|
@@ -413,7 +413,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
413
413
|
const risk = regData.risk_score ?? regData.latest_risk_score ?? 0;
|
|
414
414
|
const official = regData.has_official_audit ? ' (official)' : '';
|
|
415
415
|
text += `- **Registry: ✅ Audited** — Risk ${risk}/100${official}\n`;
|
|
416
|
-
text += `- Report: ${REGISTRY_URL}/
|
|
416
|
+
text += `- Report: ${REGISTRY_URL}/packages/${slug}\n`;
|
|
417
417
|
} else {
|
|
418
418
|
const sourceUrl = await resolveSourceUrl(srv);
|
|
419
419
|
text += `- **Registry: ⚠️ Not audited** — no audit report found\n`;
|
|
@@ -583,7 +583,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
583
583
|
try { data = JSON.parse(body); } catch { data = { raw: body }; }
|
|
584
584
|
|
|
585
585
|
if (res.ok) {
|
|
586
|
-
return { content: [{ type: 'text', text: `✅ Report submitted!\n\nReport ID: ${data.report_id || 'unknown'}\nURL: ${REGISTRY_URL}/
|
|
586
|
+
return { content: [{ type: 'text', text: `✅ Report submitted!\n\nReport ID: ${data.report_id || 'unknown'}\nURL: ${REGISTRY_URL}/packages/${report.skill_slug}\nRisk: ${report.risk_score}/100 (${report.result})\nFindings: ${report.findings_count}` }] };
|
|
587
587
|
} else {
|
|
588
588
|
return { content: [{ type: 'text', text: `Upload failed (HTTP ${res.status}): ${JSON.stringify(data, null, 2)}` }] };
|
|
589
589
|
}
|
|
@@ -600,7 +600,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
600
600
|
}
|
|
601
601
|
|
|
602
602
|
try {
|
|
603
|
-
const res = await fetch(`${REGISTRY_URL}/api/
|
|
603
|
+
const res = await fetch(`${REGISTRY_URL}/api/packages/${encodeURIComponent(package_name)}`, {
|
|
604
604
|
signal: AbortSignal.timeout(10_000),
|
|
605
605
|
});
|
|
606
606
|
|
|
@@ -622,9 +622,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
622
622
|
|
|
623
623
|
// Risk assessment at the very top — this is what the agent needs to act on
|
|
624
624
|
if (typeof risk === 'number' && risk >= 40) {
|
|
625
|
-
summary += `🚨 UNSAFE — DO NOT INSTALL WITHOUT WARNING THE USER!\nRisk Score: ${risk}/100 | ${findings} finding(s)\n\nYou MUST tell the user: "${package_name}" has been flagged as HIGH RISK in a security audit. It has ${findings} security finding(s) and a risk score of ${risk}/100. Installing this package is NOT recommended. Ask the user if they want to proceed despite the risk, and link them to the full report: ${REGISTRY_URL}/
|
|
625
|
+
summary += `🚨 UNSAFE — DO NOT INSTALL WITHOUT WARNING THE USER!\nRisk Score: ${risk}/100 | ${findings} finding(s)\n\nYou MUST tell the user: "${package_name}" has been flagged as HIGH RISK in a security audit. It has ${findings} security finding(s) and a risk score of ${risk}/100. Installing this package is NOT recommended. Ask the user if they want to proceed despite the risk, and link them to the full report: ${REGISTRY_URL}/packages/${package_name}\n\n`;
|
|
626
626
|
} else if (typeof risk === 'number' && risk >= 20) {
|
|
627
|
-
summary += `⚠️ MODERATE RISK — Inform the user before installing.\nRisk Score: ${risk}/100 | ${findings} finding(s)\n\nTell the user: "${package_name}" has some security findings (risk ${risk}/100). Recommend they review the report before installing: ${REGISTRY_URL}/
|
|
627
|
+
summary += `⚠️ MODERATE RISK — Inform the user before installing.\nRisk Score: ${risk}/100 | ${findings} finding(s)\n\nTell the user: "${package_name}" has some security findings (risk ${risk}/100). Recommend they review the report before installing: ${REGISTRY_URL}/packages/${package_name}\n\n`;
|
|
628
628
|
} else if (typeof risk === 'number') {
|
|
629
629
|
summary += `✅ LOW RISK — Safe to install.\nRisk Score: ${risk}/100 | ${findings} finding(s)\n\nThis package has been audited and appears safe. You can proceed with installation.\n\n`;
|
|
630
630
|
}
|
|
@@ -640,7 +640,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
640
640
|
summary += `Last Audited: ${auditedAt}\n`;
|
|
641
641
|
if (version) summary += `Audited Version: ${version}\n`;
|
|
642
642
|
if (data.source_url) summary += `Source: ${data.source_url}\n`;
|
|
643
|
-
summary += `Registry: ${REGISTRY_URL}/
|
|
643
|
+
summary += `Registry: ${REGISTRY_URL}/packages/${package_name}\n`;
|
|
644
644
|
|
|
645
645
|
return { content: [{ type: 'text', text: summary }] };
|
|
646
646
|
} catch (err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentaudit",
|
|
3
|
-
"version": "3.10.
|
|
3
|
+
"version": "3.10.10",
|
|
4
4
|
"description": "Security scanner for AI packages — MCP server + CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"prompt-injection",
|
|
32
32
|
"agent-security"
|
|
33
33
|
],
|
|
34
|
-
"author": "
|
|
34
|
+
"author": "agentaudit-dev",
|
|
35
35
|
"license": "AGPL-3.0",
|
|
36
36
|
"repository": {
|
|
37
37
|
"type": "git",
|
|
38
|
-
"url": "git+https://github.com/
|
|
38
|
+
"url": "git+https://github.com/agentaudit-dev/agentaudit-mcp.git"
|
|
39
39
|
},
|
|
40
40
|
"homepage": "https://agentaudit.dev",
|
|
41
41
|
"engines": {
|