agentaudit 3.6.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/cli.mjs +64 -5
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -806,7 +806,9 @@ async function resolveSourceUrl(server) {
806
806
  return null;
807
807
  }
808
808
 
809
- async function discoverCommand() {
809
+ async function discoverCommand(options = {}) {
810
+ const autoScan = options.scan || false;
811
+
810
812
  console.log(` ${c.bold}Discovering local MCP servers...${c.reset}`);
811
813
  console.log();
812
814
 
@@ -830,6 +832,7 @@ async function discoverCommand() {
830
832
  let auditedServers = 0;
831
833
  let unauditedServers = 0;
832
834
  const unauditedWithUrls = [];
835
+ const allServersWithUrls = []; // For --scan: all servers we can scan
833
836
 
834
837
  for (const config of configs) {
835
838
  const servers = extractServersFromConfig(config.content);
@@ -874,20 +877,23 @@ async function discoverCommand() {
874
877
  else if (server.url) sourceLabel = `${c.dim}${server.url.length > 60 ? server.url.slice(0, 57) + '...' : server.url}${c.reset}`;
875
878
  else if (server.command) sourceLabel = `${c.dim}${[server.command, ...server.args.slice(0, 2)].join(' ')}${c.reset}`;
876
879
 
880
+ // Always resolve source URL (needed for --scan)
881
+ const resolvedUrl = await resolveSourceUrl(server);
882
+
877
883
  if (regData) {
878
884
  auditedServers++;
879
885
  const riskScore = regData.risk_score ?? regData.latest_risk_score ?? 0;
880
886
  const hasOfficial = regData.has_official_audit;
881
887
  console.log(`${branch} ${c.bold}${server.name}${c.reset} ${sourceLabel}`);
882
888
  console.log(`${pipe} ${riskBadge(riskScore)} Risk ${riskScore} ${hasOfficial ? `${c.green}✔ official${c.reset} ` : ''}${c.dim}${REGISTRY_URL}/skills/${slug}${c.reset}`);
889
+ if (resolvedUrl) allServersWithUrls.push({ name: server.name, sourceUrl: resolvedUrl, hasAudit: true, regData });
883
890
  } else {
884
891
  unauditedServers++;
885
- // Resolve source URL
886
- const resolvedUrl = await resolveSourceUrl(server);
887
892
  console.log(`${branch} ${c.bold}${server.name}${c.reset} ${sourceLabel}`);
888
893
  if (resolvedUrl) {
889
894
  console.log(`${pipe} ${c.yellow}⚠ not audited${c.reset} ${c.dim}Run: ${c.cyan}agentaudit audit ${resolvedUrl}${c.reset}`);
890
895
  unauditedWithUrls.push({ name: server.name, sourceUrl: resolvedUrl });
896
+ allServersWithUrls.push({ name: server.name, sourceUrl: resolvedUrl, hasAudit: false });
891
897
  } else {
892
898
  console.log(`${pipe} ${c.yellow}⚠ not audited${c.reset} ${c.dim}Source URL unknown — check the package's GitHub/npm page${c.reset}`);
893
899
  }
@@ -909,7 +915,55 @@ async function discoverCommand() {
909
915
  if (unauditedServers > 0) console.log(` ${icons.caution} ${c.yellow}${unauditedServers} not audited${c.reset}`);
910
916
  console.log();
911
917
 
912
- if (unauditedServers > 0) {
918
+ // --scan: automatically scan all servers with resolved source URLs
919
+ if (autoScan) {
920
+ const scanTargets = allServersWithUrls.filter(s => s.sourceUrl && s.sourceUrl.startsWith('http'));
921
+ if (scanTargets.length > 0) {
922
+ console.log(`${c.dim}${'─'.repeat(60)}${c.reset}`);
923
+ console.log(` ${c.bold}${icons.scan} Auto-scanning ${scanTargets.length} server${scanTargets.length !== 1 ? 's' : ''}...${c.reset}`);
924
+ console.log();
925
+
926
+ const scanResults = [];
927
+ for (const target of scanTargets) {
928
+ const result = await scanRepo(target.sourceUrl);
929
+ if (result) scanResults.push({ ...result, serverName: target.name });
930
+ }
931
+
932
+ if (scanResults.length > 1) {
933
+ // Print combined scan summary
934
+ console.log(`${c.dim}${'─'.repeat(60)}${c.reset}`);
935
+ console.log(` ${c.bold}Scan Summary${c.reset} ${scanResults.length} server${scanResults.length !== 1 ? 's' : ''} scanned`);
936
+ console.log();
937
+
938
+ let totalFindings = 0;
939
+ let serversWithFindings = 0;
940
+
941
+ for (const r of scanResults) {
942
+ const findingCount = r.findings ? r.findings.length : 0;
943
+ totalFindings += findingCount;
944
+ if (findingCount > 0) serversWithFindings++;
945
+
946
+ const status = findingCount === 0
947
+ ? `${icons.safe} ${c.green}clean${c.reset}`
948
+ : `${icons.caution} ${c.yellow}${findingCount} finding${findingCount !== 1 ? 's' : ''}${c.reset}`;
949
+ console.log(` ${status} ${c.bold}${r.serverName || r.slug}${c.reset} ${c.dim}(${r.duration})${c.reset}`);
950
+ }
951
+
952
+ console.log();
953
+ if (serversWithFindings > 0) {
954
+ console.log(` ${c.yellow}${serversWithFindings}/${scanResults.length} server${scanResults.length !== 1 ? 's' : ''} with findings (${totalFindings} total)${c.reset}`);
955
+ console.log(` ${c.dim}Run ${c.cyan}agentaudit audit <url>${c.dim} for deep LLM analysis on flagged servers${c.reset}`);
956
+ } else {
957
+ console.log(` ${c.green}All servers passed quick scan${c.reset}`);
958
+ console.log(` ${c.dim}Run ${c.cyan}agentaudit audit <url>${c.dim} for thorough LLM-powered analysis${c.reset}`);
959
+ }
960
+ console.log();
961
+ }
962
+ } else {
963
+ console.log(` ${c.dim}No scannable source URLs found.${c.reset}`);
964
+ console.log();
965
+ }
966
+ } else if (unauditedServers > 0) {
913
967
  if (unauditedWithUrls.length > 0) {
914
968
  console.log(` ${c.dim}To audit unaudited servers:${c.reset}`);
915
969
  for (const { name, sourceUrl } of unauditedWithUrls) {
@@ -920,6 +974,8 @@ async function discoverCommand() {
920
974
  console.log(` ${c.cyan}agentaudit audit <source-url>${c.reset}`);
921
975
  }
922
976
  console.log();
977
+ console.log(` ${c.dim}Or run ${c.cyan}agentaudit discover --scan${c.dim} to auto-scan all servers${c.reset}`);
978
+ console.log();
923
979
  }
924
980
  }
925
981
 
@@ -1210,6 +1266,7 @@ async function main() {
1210
1266
  console.log(` ${c.bold}Commands:${c.reset}`);
1211
1267
  console.log();
1212
1268
  console.log(` ${c.cyan}agentaudit discover${c.reset} Find local MCP servers + check registry`);
1269
+ console.log(` ${c.cyan}agentaudit discover --scan${c.reset} Discover + auto-scan all servers`);
1213
1270
  console.log(` ${c.cyan}agentaudit scan${c.reset} <url> [url...] Quick static scan (regex, local)`);
1214
1271
  console.log(` ${c.cyan}agentaudit audit${c.reset} <url> [url...] Deep LLM-powered security audit`);
1215
1272
  console.log(` ${c.cyan}agentaudit check${c.reset} <name> Look up package in registry`);
@@ -1221,6 +1278,7 @@ async function main() {
1221
1278
  console.log();
1222
1279
  console.log(` ${c.bold}Examples:${c.reset}`);
1223
1280
  console.log(` agentaudit discover`);
1281
+ console.log(` agentaudit discover --scan`);
1224
1282
  console.log(` agentaudit scan https://github.com/owner/repo`);
1225
1283
  console.log(` agentaudit audit https://github.com/owner/repo`);
1226
1284
  console.log(` agentaudit check fastmcp`);
@@ -1252,7 +1310,8 @@ async function main() {
1252
1310
  }
1253
1311
 
1254
1312
  if (command === 'discover') {
1255
- await discoverCommand();
1313
+ const scanFlag = targets.includes('--scan') || targets.includes('-s');
1314
+ await discoverCommand({ scan: scanFlag });
1256
1315
  return;
1257
1316
  }
1258
1317
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentaudit",
3
- "version": "3.6.0",
3
+ "version": "3.7.0",
4
4
  "description": "Security scanner for AI packages — MCP server + CLI",
5
5
  "type": "module",
6
6
  "bin": {