agentaudit 3.9.32 → 3.9.34

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 (3) hide show
  1. package/cli.mjs +63 -2
  2. package/index.mjs +36 -2
  3. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -1704,6 +1704,17 @@ async function auditRepo(url) {
1704
1704
 
1705
1705
  // Upload to registry
1706
1706
  const creds = loadCredentials();
1707
+ const finalModel = providerMeta.reported_model || actualModel;
1708
+ const finalProvider = resolvedProvider.id;
1709
+ if (!finalModel || finalModel === 'unknown') {
1710
+ console.log(` ${c.yellow}⚠ Model not detected — report will not include model attestation.${c.reset}`);
1711
+ console.log(` ${c.dim} This usually means the LLM API did not return model info.${c.reset}`);
1712
+ console.log(` ${c.dim} Try: agentaudit config set model <model-name>${c.reset}`);
1713
+ if (process.argv.includes('--debug')) {
1714
+ console.log(` ${c.dim} providerMeta: ${JSON.stringify(providerMeta)}${c.reset}`);
1715
+ console.log(` ${c.dim} actualModel: ${actualModel}, resolvedProvider: ${resolvedProvider.id}${c.reset}`);
1716
+ }
1717
+ }
1707
1718
  if (creds) {
1708
1719
  process.stdout.write(` Uploading report to registry...`);
1709
1720
  try {
@@ -1717,8 +1728,8 @@ async function auditRepo(url) {
1717
1728
  ...report,
1718
1729
  commit_sha: report.commit_sha || repoCommitSha || undefined,
1719
1730
  package_version: report.package_version || repoPackageVersion || undefined,
1720
- audit_model: providerMeta.reported_model || actualModel,
1721
- audit_provider: resolvedProvider.id,
1731
+ audit_model: finalModel !== 'unknown' ? finalModel : undefined,
1732
+ audit_provider: finalProvider,
1722
1733
  provider_msg_id: providerMeta.provider_msg_id || undefined,
1723
1734
  provider_fingerprint: providerMeta.provider_fingerprint || undefined,
1724
1735
  input_tokens: providerMeta.input_tokens || undefined,
@@ -1732,13 +1743,63 @@ async function auditRepo(url) {
1732
1743
  const reportSlug = data?.skill_slug || data?.slug || slug;
1733
1744
  console.log(` ${c.green}done${c.reset}`);
1734
1745
  console.log(` ${c.dim}Report: ${REGISTRY_URL}/skills/${reportSlug}${c.reset}`);
1746
+ // Show API warnings
1747
+ if (data?.warnings?.length) {
1748
+ for (const w of data.warnings) {
1749
+ console.log(` ${c.yellow}⚠ ${w}${c.reset}`);
1750
+ }
1751
+ }
1735
1752
  // Refresh stats cache in background
1736
1753
  if (creds.agent_name) refreshStatsCache(creds.agent_name).catch(() => {});
1754
+ // Fetch registry consensus after upload
1755
+ try {
1756
+ const regData = await checkRegistry(reportSlug);
1757
+ if (regData) {
1758
+ const regRisk = regData.latest_risk_score ?? regData.risk_score ?? 0;
1759
+ const regTrust = regData.trust_score ?? (100 - regRisk);
1760
+ const totalReports = regData.total_reports ?? 1;
1761
+ const uniqueAgents = regData.unique_agents ?? 1;
1762
+ const confidence = regData.confidence ?? 'unverified';
1763
+ const totalFindings = regData.total_findings ?? 0;
1764
+ const hasOfficial = regData.has_official_audit;
1765
+
1766
+ // Show registry consensus if different from own report or multiple reports exist
1767
+ if (totalReports > 1 || regRisk !== report.risk_score) {
1768
+ console.log();
1769
+ console.log(` ${c.bold}Registry Consensus${c.reset}`);
1770
+ const trustColor = regTrust >= 70 ? c.green : regTrust >= 40 ? c.yellow : c.red;
1771
+ const trustLabel = regTrust >= 70 ? 'SAFE' : regTrust >= 40 ? 'CAUTION' : 'UNSAFE';
1772
+ console.log(` ${trustColor}${c.bold}${trustLabel}${c.reset} Trust Score: ${trustColor}${regTrust}/100${c.reset} ${c.dim}(across ${totalReports} reports from ${uniqueAgents} auditor${uniqueAgents !== 1 ? 's' : ''})${c.reset}`);
1773
+ if (totalFindings > 0) {
1774
+ console.log(` ${c.dim}Total findings across all reports: ${totalFindings}${c.reset}`);
1775
+ }
1776
+ const confDisplay = {
1777
+ consensus: { icon: '🟢', label: 'Consensus Certified', color: c.green },
1778
+ verified: { icon: '🟢', label: 'Verified', color: c.green },
1779
+ low: { icon: '🟡', label: 'Low Confidence', color: c.yellow },
1780
+ unverified: { icon: '🔴', label: 'Unverified', color: c.yellow },
1781
+ }[confidence] || { icon: '⚪', label: confidence, color: c.dim };
1782
+ console.log(` ${confDisplay.icon} ${confDisplay.color}${confDisplay.label}${c.reset}`);
1783
+ if (hasOfficial) console.log(` ${c.green}✔ Officially audited${c.reset}`);
1784
+
1785
+ // Warn if own report disagrees with consensus
1786
+ const ownRisk = report.risk_score || 0;
1787
+ if (Math.abs(ownRisk - regRisk) > 10) {
1788
+ console.log();
1789
+ console.log(` ${c.yellow}⚠ Your audit (risk ${ownRisk}) differs from registry consensus (risk ${regRisk}).${c.reset}`);
1790
+ console.log(` ${c.dim} This may indicate model-specific blind spots or a changing codebase.${c.reset}`);
1791
+ }
1792
+ }
1793
+ }
1794
+ } catch {}
1737
1795
  } else {
1796
+ const errBody = await res.text().catch(() => '');
1738
1797
  console.log(` ${c.yellow}failed (HTTP ${res.status})${c.reset}`);
1798
+ if (process.argv.includes('--debug')) console.log(` ${c.dim}Response: ${errBody.slice(0, 500)}${c.reset}`);
1739
1799
  }
1740
1800
  } catch (err) {
1741
1801
  console.log(` ${c.yellow}failed${c.reset}`);
1802
+ if (process.argv.includes('--debug')) console.log(` ${c.dim}Error: ${err.message}${c.reset}`);
1742
1803
  }
1743
1804
  } else {
1744
1805
  console.log(` ${c.dim}Run ${c.cyan}agentaudit setup${c.dim} to upload reports to the registry${c.reset}`);
package/index.mjs CHANGED
@@ -534,7 +534,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
534
534
  try { data = JSON.parse(body); } catch { data = { raw: body }; }
535
535
 
536
536
  if (res.ok) {
537
- return { content: [{ type: 'text', text: `✅ Report submitted!\n\nReport ID: ${data.report_id || 'unknown'}\nURL: ${REGISTRY_URL}/skills/${report.skill_slug}\nRisk: ${report.risk_score}/100 (${report.result})\nFindings: ${report.findings_count}` }] };
537
+ const reportSlug = data?.skill_slug || report.skill_slug;
538
+ // Fetch registry consensus to give the agent full decision context
539
+ let consensusInfo = '';
540
+ try {
541
+ const regRes = await fetch(`${REGISTRY_URL}/api/skills/${encodeURIComponent(reportSlug)}`, { signal: AbortSignal.timeout(5000) });
542
+ if (regRes.ok) {
543
+ const reg = await regRes.json();
544
+ const regRisk = reg.latest_risk_score ?? 0;
545
+ const regTrust = reg.trust_score ?? (100 - regRisk);
546
+ const totalReports = reg.total_reports ?? 1;
547
+ const uniqueAgents = reg.unique_agents ?? 1;
548
+ const confidence = reg.confidence ?? 'unverified';
549
+ const totalFindings = reg.total_findings ?? 0;
550
+ const trustLabel = regTrust >= 70 ? 'SAFE' : regTrust >= 40 ? 'CAUTION' : 'UNSAFE';
551
+ consensusInfo = `\n\n📊 **Registry Consensus** (across ${totalReports} reports from ${uniqueAgents} auditor${uniqueAgents !== 1 ? 's' : ''}):\n- Trust Score: ${regTrust}/100 (${trustLabel})\n- Total Findings: ${totalFindings}\n- Confidence: ${confidence}${reg.has_official_audit ? '\n- ✔ Officially audited' : ''}`;
552
+ if (totalReports > 1) {
553
+ consensusInfo += `\n\n⚠️ IMPORTANT: Your audit is ONE data point. The registry consensus reflects ALL audits. If your result differs significantly, this may indicate model-specific blind spots. Agents should use the REGISTRY CONSENSUS (not just this single audit) when making install/trust decisions.`;
554
+ }
555
+ }
556
+ } catch {}
557
+ return { content: [{ type: 'text', text: `✅ Report submitted!\n\nReport ID: ${data.report_id || 'unknown'}\nURL: ${REGISTRY_URL}/skills/${reportSlug}\nYour Audit: Risk ${report.risk_score}/100 (${report.result}), ${report.findings_count} findings${consensusInfo}` }] };
538
558
  } else {
539
559
  return { content: [{ type: 'text', text: `Upload failed (HTTP ${res.status}): ${JSON.stringify(data, null, 2)}` }] };
540
560
  }
@@ -584,8 +604,22 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
584
604
  summary += `⚠️ OUTDATED: The package has changed since the last audit. Consider running a fresh audit first.\n\n`;
585
605
  }
586
606
 
607
+ // Consensus section — critical for agent decision-making
608
+ const totalReports = data.total_reports ?? 1;
609
+ const uniqueAgents = data.unique_agents ?? 1;
610
+ const confidence = data.confidence ?? 'unverified';
611
+ const trustScore = data.trust_score ?? (100 - (risk || 0));
612
+ const trustLabel = trustScore >= 70 ? 'SAFE' : trustScore >= 40 ? 'CAUTION' : 'UNSAFE';
613
+
614
+ summary += `--- Registry Consensus ---\n`;
615
+ summary += `Trust Score: ${trustScore}/100 (${trustLabel})\n`;
616
+ summary += `Reports: ${totalReports} from ${uniqueAgents} independent auditor${uniqueAgents !== 1 ? 's' : ''}\n`;
617
+ summary += `Confidence: ${confidence}\n`;
618
+ if (confidence === 'unverified') summary += `⚠️ Only 1 audit exists — consider running your own for independent verification.\n`;
619
+ if (confidence === 'low') summary += `⚠️ Limited independent verification — more auditors needed for consensus.\n`;
620
+
587
621
  // Details section
588
- summary += `--- Details ---\n`;
622
+ summary += `\n--- Details ---\n`;
589
623
  summary += `Package: ${package_name}\n`;
590
624
  summary += `Status: ${official}\n`;
591
625
  summary += `Last Audited: ${auditedAt}\n`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentaudit",
3
- "version": "3.9.32",
3
+ "version": "3.9.34",
4
4
  "description": "Security scanner for AI packages — MCP server + CLI",
5
5
  "type": "module",
6
6
  "bin": {